--- /dev/null
+module nbi-notifications {
+ yang-version 1;
+ namespace "nbi-notifications";
+ prefix nbinotifications;
+
+ import org-openroadm-service {
+ prefix oor-service;
+ revision-date 2019-05-31;
+ }
+ import org-openroadm-common-service-types {
+ prefix org-openroadm-common-service-types;
+ revision-date 2019-05-31;
+ }
+ import org-openroadm-common-state-types {
+ prefix org-openroadm-common-state-types;
+ revision-date 2018-11-30;
+ }
+
+ organization
+ "transportPCE";
+ contact
+ "transportPCE committers - ODL";
+ description
+ "YANG definitions for using REST API in NBI notifications module. Copyright
+ (c) 2020 ORANGE and others. All rights reserved.";
+
+ revision 2020-11-30 {
+ description
+ "Initial revision of NBI notifications";
+ }
+
+ grouping notification-service {
+ leaf message {
+ type string;
+ mandatory true;
+ description
+ "Message for the specified service";
+ }
+ leaf service-name {
+ type string;
+ mandatory true;
+ description
+ "Identifier for the service to be created in the ROADM network, e.g., CLFI, CLCI, etc.
+ This is reported against the service, but may not get reflected in the service in the network.";
+ }
+ leaf common-id {
+ type string;
+ description
+ "To be used by the ROADM controller to identify the routing constraints
+ received from planning application (PED).";
+ }
+ leaf connection-type {
+ type org-openroadm-common-service-types:connection-type;
+ mandatory true;
+ }
+ container service-a-end {
+ uses org-openroadm-common-service-types:service-endpoint;
+ }
+ container service-z-end {
+ uses org-openroadm-common-service-types:service-endpoint;
+ }
+ leaf response-failed {
+ type string;
+ description
+ "Response of the error if the service request encountered an anomaly";
+ }
+ leaf operational-state {
+ type org-openroadm-common-state-types:state;
+ config false;
+ description
+ "Operational State: Actual state of service";
+ }
+ }
+
+ container notification-service {
+ description
+ "Model used to send a notification from a service request";
+ uses notification-service;
+ }
+
+ rpc get-notifications-service {
+ description "Get the notifications service send by ServiceHandler by filtering through connection type";
+ input {
+ leaf connection-type {
+ type org-openroadm-common-service-types:connection-type;
+ mandatory true;
+ description
+ "Type connection of the service ";
+ }
+ leaf id-consumer {
+ type string;
+ mandatory true;
+ description
+ "Unique ID for the consumer";
+ }
+ leaf group-id {
+ type string;
+ mandatory true;
+ description
+ "ID Group for the consumer";
+ }
+ }
+ output {
+ list notification-service {
+ uses notification-service;
+ }
+ }
+ }
+
+ notification publish-notification-service {
+ description "Publish the notifications service for topic";
+ leaf topic {
+ type string;
+ mandatory true;
+ description
+ "Topic where to send the notification service";
+ }
+ uses notification-service;
+ }
+}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright © 2021 Orange and others. All rights reserved. This program and the accompanying materials
+ are made available under the terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ and is available at http://www.eclipse.org/legal/epl-v10.html -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.opendaylight.mdsal</groupId>
+ <artifactId>binding-parent</artifactId>
+ <version>7.0.5</version>
+ <relativePath />
+ </parent>
+ <groupId>org.opendaylight.transportpce</groupId>
+ <artifactId>transportpce-dmaap-client</artifactId>
+ <version>3.0.0-SNAPSHOT</version>
+ <packaging>bundle</packaging>
+ <description>client to send message to Dmaap message router</description>
+
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ </properties>
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>transportpce-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.mdsal</groupId>
+ <artifactId>mdsal-binding-api</artifactId>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.jersey.core</groupId>
+ <artifactId>jersey-client</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.jersey.ext</groupId>
+ <artifactId>jersey-proxy-client</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.jersey.inject</groupId>
+ <artifactId>jersey-hk2</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.jersey.media</groupId>
+ <artifactId>jersey-media-json-jackson</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.fasterxml.jackson.datatype</groupId>
+ <artifactId>jackson-datatype-jsr310</artifactId>
+ </dependency>
+ <!-- Testing dependencies -->
+ <dependency>
+ <groupId>org.glassfish.jersey.test-framework</groupId>
+ <artifactId>jersey-test-framework-core</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.jersey.test-framework.providers</groupId>
+ <artifactId>jersey-test-framework-provider-grizzly2</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-core</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-classic</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+</project>
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright © 2021 Orange, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.dmaap.client.impl;
+
+import org.opendaylight.mdsal.binding.api.NotificationService;
+import org.opendaylight.transportpce.dmaap.client.listener.NbiNotificationsListenerImpl;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.NbiNotificationsListener;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DmaapClientProvider {
+ private static final Logger LOG = LoggerFactory.getLogger(DmaapClientProvider.class);
+ private ListenerRegistration<NbiNotificationsListener> listenerRegistration;
+ private NotificationService notificationService;
+ private final String baseUrl;
+ private final String username;
+ private final String password;
+
+ public DmaapClientProvider(NotificationService notificationService, String baseUrl,
+ String username, String password) {
+ this.notificationService = notificationService;
+ this.baseUrl = baseUrl;
+ this.username = username;
+ this.password = password;
+ }
+
+ /**
+ * Method called when the blueprint container is created.
+ */
+ public void init() {
+ LOG.info("DmaapClientProvider Session Initiated");
+ listenerRegistration = notificationService.registerNotificationListener(
+ new NbiNotificationsListenerImpl(baseUrl, username, password));
+ }
+
+ /**
+ * Method called when the blueprint container is destroyed.
+ */
+ public void close() {
+ listenerRegistration.close();
+ LOG.info("DmaapClientProvider Closed");
+ }
+
+}
--- /dev/null
+/*
+ * Copyright © 2021 Orange, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.dmaap.client.listener;
+
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.ClientBuilder;
+import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature;
+import org.glassfish.jersey.client.proxy.WebResourceFactory;
+import org.glassfish.jersey.jackson.JacksonFeature;
+import org.glassfish.jersey.logging.LoggingFeature;
+import org.opendaylight.transportpce.dmaap.client.resource.EventsApi;
+import org.opendaylight.transportpce.dmaap.client.resource.config.JsonConfigurator;
+import org.opendaylight.transportpce.dmaap.client.resource.model.CreatedEvent;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.NbiNotificationsListener;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.PublishNotificationService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NbiNotificationsListenerImpl implements NbiNotificationsListener {
+ private static final Logger LOG = LoggerFactory.getLogger(NbiNotificationsListenerImpl.class);
+ private String topic = "unauthenticated.TPCE";
+ private EventsApi api;
+
+ public NbiNotificationsListenerImpl(String baseUrl, String username, String password) {
+ LOG.info("Dmaap server {} for user {}", baseUrl, username);
+ Client client = ClientBuilder.newClient();
+ if (username != null && username.isBlank() && password != null && !password.isBlank()) {
+ HttpAuthenticationFeature authFeature = HttpAuthenticationFeature.basic(username, password);
+ client.register(authFeature);
+ topic = "authenticated.TPCE";
+ }
+ client.register(new LoggingFeature(java.util.logging.Logger.getLogger(this.getClass().getName())))
+ .register(JacksonFeature.class).register(JsonConfigurator.class);
+ api = WebResourceFactory.newResource(EventsApi.class, client.target(baseUrl));
+
+ }
+
+ @Override
+ public void onPublishNotificationService(PublishNotificationService notification) {
+ try {
+ CreatedEvent response = api.sendEvent(topic, notification);
+ LOG.info("Response received {}", response);
+ } catch (WebApplicationException e) {
+ LOG.warn("Cannot send event {}", notification, e);
+ }
+
+ }
+
+}
--- /dev/null
+/*
+ * Copyright © 2021 Orange, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.dmaap.client.resource;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import org.opendaylight.transportpce.dmaap.client.resource.model.CreatedEvent;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.PublishNotificationService;
+
+@Path("/events")
+public interface EventsApi {
+
+ @POST
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @Path("/{topic}")
+ CreatedEvent sendEvent(@PathParam("topic") String topic, PublishNotificationService event);
+
+}
--- /dev/null
+/*
+ * Copyright © 2021 Orange, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.dmaap.client.resource.config;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
+import javax.ws.rs.ext.ContextResolver;
+
+public class JsonConfigurator implements ContextResolver<ObjectMapper> {
+
+ private final ObjectMapper mapper;
+
+ public JsonConfigurator() {
+ mapper = new ObjectMapper();
+ mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
+ mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
+ mapper.enable(SerializationFeature.INDENT_OUTPUT);
+ mapper.registerModule(new JavaTimeModule());
+ mapper.registerModule(new PublishNotificationServiceModule());
+ }
+
+ @Override
+ public ObjectMapper getContext(Class<?> type) {
+ return mapper;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright © 2021 Orange, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.dmaap.client.resource.config;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+import java.io.IOException;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev190531.service.lgx.Lgx;
+
+// This class is a temporary workaround while waiting jackson
+// support in yang tools https://git.opendaylight.org/gerrit/c/yangtools/+/94852
+public class LgxSerializer extends StdSerializer<Lgx> {
+ private static final long serialVersionUID = 1L;
+
+ public LgxSerializer() {
+ super(Lgx.class);
+ }
+
+ @Override
+ public void serialize(Lgx value, JsonGenerator gen, SerializerProvider provider) throws IOException {
+ if (value != null) {
+ gen.writeStartObject();
+ gen.writeStringField("lgx-port-rack", value.getLgxPortRack());
+ gen.writeStringField("lgx-port-shelf", value.getLgxPortShelf());
+ gen.writeStringField("lgx-device-name", value.getLgxDeviceName());
+ gen.writeStringField("lgx-port-name", value.getLgxPortName());
+ gen.writeEndObject();
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2021 Orange, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.dmaap.client.resource.config;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+import java.io.IOException;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev190531.service.port.Port;
+
+// This class is a temporary workaround while waiting jackson
+// support in yang tools https://git.opendaylight.org/gerrit/c/yangtools/+/94852
+public class PortSerializer extends StdSerializer<Port> {
+ private static final long serialVersionUID = 1L;
+
+ public PortSerializer() {
+ super(Port.class);
+ }
+
+ @Override
+ public void serialize(Port value, JsonGenerator gen, SerializerProvider provider) throws IOException {
+ if (value != null) {
+ gen.writeStartObject();
+ gen.writeStringField("port-rack", value.getPortRack());
+ gen.writeStringField("port-shelf", value.getPortShelf());
+ gen.writeStringField("port-device-name", value.getPortDeviceName());
+ gen.writeStringField("port-name", value.getPortName());
+ gen.writeStringField("port-type", value.getPortType());
+ gen.writeEndObject();
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2021 Orange, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.dmaap.client.resource.config;
+
+import com.fasterxml.jackson.databind.module.SimpleModule;
+import com.fasterxml.jackson.datatype.jsr310.PackageVersion;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev190531.service.endpoint.RxDirection;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev190531.service.endpoint.TxDirection;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev190531.service.lgx.Lgx;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev190531.service.port.Port;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.PublishNotificationService;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.notification.service.ServiceAEnd;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.notification.service.ServiceZEnd;
+
+//This class is a temporary workaround while waiting jackson
+//support in yang tools https://git.opendaylight.org/gerrit/c/yangtools/+/94852
+public class PublishNotificationServiceModule extends SimpleModule {
+
+ private static final long serialVersionUID = 1L;
+
+ public PublishNotificationServiceModule() {
+ super(PackageVersion.VERSION);
+ addSerializer(PublishNotificationService.class, new PublishNotificationServiceSerializer());
+ addSerializer(Lgx.class, new LgxSerializer());
+ addSerializer(Port.class, new PortSerializer());
+ addSerializer(RxDirection.class, new RxDirectionSerializer());
+ addSerializer(TxDirection.class, new TxDirectionSerializer());
+ addSerializer(ServiceAEnd.class, new ServiceAEndSerializer());
+ addSerializer(ServiceZEnd.class, new ServiceZEndSerializer());
+ }
+
+}
--- /dev/null
+/*
+ * Copyright © 2021 Orange, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.dmaap.client.resource.config;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+import java.io.IOException;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.PublishNotificationService;
+
+// This class is a temporary workaround while waiting jackson
+// support in yang tools https://git.opendaylight.org/gerrit/c/yangtools/+/94852
+public class PublishNotificationServiceSerializer extends StdSerializer<PublishNotificationService> {
+ private static final long serialVersionUID = 1L;
+
+ public PublishNotificationServiceSerializer() {
+ super(PublishNotificationService.class);
+ }
+
+ @Override
+ public void serialize(PublishNotificationService value, JsonGenerator gen, SerializerProvider provider)
+ throws IOException {
+ if (value != null) {
+ gen.writeStartObject();
+ gen.writeStringField("common-id", value.getCommonId());
+ gen.writeStringField("message", value.getMessage());
+ gen.writeStringField("response-failed", value.getResponseFailed());
+ gen.writeStringField("service-name", value.getServiceName());
+ gen.writeStringField("topic", value.getTopic());
+ if (value.getOperationalState() != null) {
+ gen.writeStringField("operational-state", value.getOperationalState().getName());
+ }
+ gen.writeObjectField("service-a-end", value.getServiceAEnd());
+ gen.writeObjectField("service-z-end", value.getServiceZEnd());
+ gen.writeEndObject();
+ }
+ }
+
+}
--- /dev/null
+/*
+ * Copyright © 2021 Orange, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.dmaap.client.resource.config;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+import java.io.IOException;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev190531.service.endpoint.RxDirection;
+
+// This class is a temporary workaround while waiting jackson
+// support in yang tools https://git.opendaylight.org/gerrit/c/yangtools/+/94852
+public class RxDirectionSerializer extends StdSerializer<RxDirection> {
+ private static final long serialVersionUID = 1L;
+
+ public RxDirectionSerializer() {
+ super(RxDirection.class);
+ }
+
+ @Override
+ public void serialize(RxDirection value, JsonGenerator gen, SerializerProvider provider) throws IOException {
+ if (value != null) {
+ gen.writeStartObject();
+ if (value.getPort() != null) {
+ gen.writeObjectField("port", value.getPort());
+ }
+ if (value.getLgx() != null) {
+ gen.writeObjectField("lgx", value.getLgx());
+ }
+ gen.writeEndObject();
+ }
+ }
+
+}
--- /dev/null
+/*
+ * Copyright © 2021 Orange, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.dmaap.client.resource.config;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+import java.io.IOException;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.notification.service.ServiceAEnd;
+
+// This class is a temporary workaround while waiting jackson
+// support in yang tools https://git.opendaylight.org/gerrit/c/yangtools/+/94852
+public class ServiceAEndSerializer extends StdSerializer<ServiceAEnd> {
+ private static final long serialVersionUID = 1L;
+
+ public ServiceAEndSerializer() {
+ super(ServiceAEnd.class);
+ }
+
+ @Override
+ public void serialize(ServiceAEnd value, JsonGenerator gen, SerializerProvider provider) throws IOException {
+ if (value != null) {
+ gen.writeStartObject();
+ gen.writeStringField("clli", value.getClli());
+ if (value.getServiceFormat() != null) {
+ gen.writeStringField("service-format", value.getServiceFormat().getName());
+ }
+ if (value.getNodeId() != null) {
+ gen.writeStringField("node-id", value.getNodeId().getValue());
+ }
+ if (value.getServiceRate() != null) {
+ gen.writeNumberField("service-rate", value.getServiceRate().intValue());
+ }
+ if (value.getOpticType() != null) {
+ gen.writeStringField("optic-type", value.getOpticType().getName());
+ }
+ if (value.getTxDirection() != null) {
+ gen.writeObjectField("tx-direction", value.getTxDirection());
+ }
+ if (value.getRxDirection() != null) {
+ gen.writeObjectField("rx-direction", value.getRxDirection());
+ }
+ gen.writeEndObject();
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2021 Orange, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.dmaap.client.resource.config;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+import java.io.IOException;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.notification.service.ServiceZEnd;
+
+// This class is a temporary workaround while waiting jackson
+// support in yang tools https://git.opendaylight.org/gerrit/c/yangtools/+/94852
+public class ServiceZEndSerializer extends StdSerializer<ServiceZEnd> {
+ private static final long serialVersionUID = 1L;
+
+ public ServiceZEndSerializer() {
+ super(ServiceZEnd.class);
+ }
+
+ @Override
+ public void serialize(ServiceZEnd value, JsonGenerator gen, SerializerProvider provider) throws IOException {
+ if (value != null) {
+ gen.writeStartObject();
+ gen.writeStringField("clli", value.getClli());
+ if (value.getServiceFormat() != null) {
+ gen.writeStringField("service-format", value.getServiceFormat().getName());
+ }
+ if (value.getNodeId() != null) {
+ gen.writeStringField("node-id", value.getNodeId().getValue());
+ }
+ if (value.getServiceRate() != null) {
+ gen.writeNumberField("service-rate", value.getServiceRate().intValue());
+ }
+ if (value.getOpticType() != null) {
+ gen.writeStringField("optic-type", value.getOpticType().getName());
+ }
+ if (value.getTxDirection() != null) {
+ gen.writeObjectField("tx-direction", value.getTxDirection());
+ }
+ if (value.getRxDirection() != null) {
+ gen.writeObjectField("rx-direction", value.getRxDirection());
+ }
+ gen.writeEndObject();
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2021 Orange, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.dmaap.client.resource.config;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+import java.io.IOException;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev190531.service.endpoint.TxDirection;
+
+// This class is a temporary workaround while waiting jackson
+// support in yang tools https://git.opendaylight.org/gerrit/c/yangtools/+/94852
+public class TxDirectionSerializer extends StdSerializer<TxDirection> {
+ private static final long serialVersionUID = 1L;
+
+ public TxDirectionSerializer() {
+ super(TxDirection.class);
+ }
+
+ @Override
+ public void serialize(TxDirection value, JsonGenerator gen, SerializerProvider provider) throws IOException {
+ if (value != null) {
+ gen.writeStartObject();
+ if (value.getPort() != null) {
+ gen.writeObjectField("port", value.getPort());
+ }
+ if (value.getLgx() != null) {
+ gen.writeObjectField("lgx", value.getLgx());
+ }
+ gen.writeEndObject();
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2021 Orange, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.dmaap.client.resource.model;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+public class CreatedEvent {
+
+ @JsonProperty("serverTimeMs")
+ private Integer serverTimeMs;
+
+ @JsonProperty("count")
+ private Integer count;
+
+ public Integer getServerTimeMs() {
+ return serverTimeMs;
+ }
+
+ public void setServerTimeMs(Integer serverTimeMs) {
+ this.serverTimeMs = serverTimeMs;
+ }
+
+ public Integer getCount() {
+ return count;
+ }
+
+ public void setCount(Integer count) {
+ this.count = count;
+ }
+
+ @Override
+ public String toString() {
+ return new StringBuilder()
+ .append("CreatedEvent [serverTimeMs=")
+ .append(serverTimeMs).append(", count=")
+ .append(count).append("]")
+ .toString();
+ }
+}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!-- Copyright © 2021 Orange and others. All rights reserved. This program and the accompanying materials
+ are made available under the terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ and is available at http://www.eclipse.org/legal/epl-v10.html -->
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" xmlns:odl="http://opendaylight.org/xmlns/blueprint/v1.0.0"
+ xmlns:cm="http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.1.0"
+ odl:use-default-for-reference-types="true">
+ <cm:property-placeholder persistent-id="org.opendaylight.transportpce.dmaap" update-strategy="reload">
+ <cm:default-properties>
+ <cm:property name="dmaap.baseUrl" value="http://localhost:8080" />
+ <cm:property name="dmaap.username" value="" />
+ <cm:property name="dmaap.password" value="" />
+ </cm:default-properties>
+ </cm:property-placeholder>
+ <reference id="notificationService" interface="org.opendaylight.mdsal.binding.api.NotificationService"/>
+
+ <bean id="provider"
+ class="org.opendaylight.transportpce.dmaap.client.impl.DmaapClientProvider"
+ init-method="init" destroy-method="close">
+ <argument ref="notificationService" />
+ <argument value="${dmaap.baseUrl}"></argument>
+ <argument value="${dmaap.username}"></argument>
+ <argument value="${dmaap.password}"></argument>
+ </bean>
+</blueprint>
--- /dev/null
+/*
+ * Copyright © 2021 Orange, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.dmaap.client.impl;
+
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.mdsal.binding.api.NotificationService;
+import org.opendaylight.transportpce.dmaap.client.listener.NbiNotificationsListenerImpl;
+
+
+public class DmaapClientProviderTest {
+
+ @Mock
+ private NotificationService notificationService;
+
+ @Before
+ public void init() {
+ MockitoAnnotations.openMocks(this);
+
+ }
+
+ @Test
+ public void testInitRegisterNbiNotificationsToRpcRegistry() {
+ DmaapClientProvider provider = new DmaapClientProvider(notificationService, "http://localhost", "username", "password");
+ provider.init();
+ (verify(notificationService, times(1)))
+ .registerNotificationListener(Mockito.any(NbiNotificationsListenerImpl.class));
+ }
+
+}
--- /dev/null
+/*
+ * Copyright © 2021 Orange, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.dmaap.client.listener;
+
+import static org.junit.Assert.assertEquals;
+
+import ch.qos.logback.classic.Logger;
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.core.read.ListAppender;
+import java.util.List;
+import javax.ws.rs.core.Application;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.test.JerseyTest;
+import org.glassfish.jersey.test.TestProperties;
+import org.junit.Test;
+import org.opendaylight.transportpce.dmaap.client.resource.EventsApiStub;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev190531.ConnectionType;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev190531.service.endpoint.RxDirectionBuilder;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev190531.service.endpoint.TxDirectionBuilder;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.common.state.types.rev181130.State;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.service.format.rev190531.ServiceFormat;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.NbiNotificationsListener;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.PublishNotificationService;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.PublishNotificationServiceBuilder;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.notification.service.ServiceAEndBuilder;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.notification.service.ServiceZEndBuilder;
+import org.opendaylight.yangtools.yang.common.Uint32;
+import org.slf4j.LoggerFactory;
+
+public class NbiNotificationsListenerImplTest extends JerseyTest {
+ @Override
+ protected Application configure() {
+ enable(TestProperties.LOG_TRAFFIC);
+ enable(TestProperties.DUMP_ENTITY);
+ return new ResourceConfig(EventsApiStub.class);
+ }
+
+ @Test
+ public void onPublishNotificationServiceTest() {
+ Logger logger = (Logger) LoggerFactory.getLogger(NbiNotificationsListenerImpl.class);
+ ListAppender<ILoggingEvent> listAppender = new ListAppender<>();
+ listAppender.start();
+ logger.addAppender(listAppender);
+ NbiNotificationsListener listener = new NbiNotificationsListenerImpl("http://localhost:9998", null, null);
+ PublishNotificationService notification = new PublishNotificationServiceBuilder().setCommonId("CommonId")
+ .setMessage("Service implemented")
+ .setOperationalState(State.InService)
+ .setTopic("topic")
+ .setConnectionType(ConnectionType.Service)
+ .setServiceAEnd(new ServiceAEndBuilder()
+ .setClli("clli")
+ .setNodeId(new org.opendaylight.yang.gen.v1.http
+ .org.openroadm.common.node.types.rev181130.NodeIdType("nodeidtype"))
+ .setServiceFormat(ServiceFormat.Ethernet)
+ .setServiceRate(Uint32.valueOf(100))
+ .setRxDirection(new RxDirectionBuilder().build())
+ .setTxDirection(new TxDirectionBuilder().build())
+ .build())
+ .setServiceZEnd(new ServiceZEndBuilder()
+ .setClli("clli")
+ .setNodeId(new org.opendaylight.yang.gen.v1.http
+ .org.openroadm.common.node.types.rev181130.NodeIdType("nodeidtype"))
+ .setServiceFormat(ServiceFormat.Ethernet)
+ .setServiceRate(Uint32.valueOf(100))
+ .setRxDirection(new RxDirectionBuilder().build())
+ .setTxDirection(new TxDirectionBuilder().build())
+ .build())
+ .build();
+ listener.onPublishNotificationService(notification);
+ // as onPublishNotificationService is a void method, we check log message to be sur everything went well
+ List<ILoggingEvent> logsList = listAppender.list;
+ assertEquals("Response received CreatedEvent [serverTimeMs=1, count=1]", logsList.get(1).getFormattedMessage());
+
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2021 Orange, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.dmaap.client.resource;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import org.opendaylight.transportpce.dmaap.client.resource.model.CreatedEvent;
+
+@Path("/events")
+public class EventsApiStub {
+
+ @POST
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @Path("/{topic}")
+ public CreatedEvent sendEvent(@PathParam("topic") String topic, String event) {
+ CreatedEvent response = new CreatedEvent();
+ response.setCount(1);
+ response.setServerTimeMs(1);
+ return response;
+ }
+
+}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright © 2021 Orange and others. All rights reserved. This program
+ and the accompanying materials are made available under the terms of the
+ Eclipse Public License v1.0 which accompanies this distribution, and is available
+ at http://www.eclipse.org/legal/epl-v10.html INTERNAL -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.opendaylight.odlparent</groupId>
+ <artifactId>single-feature-parent</artifactId>
+ <version>8.1.0</version>
+ <relativePath />
+ </parent>
+ <groupId>org.opendaylight.transportpce</groupId>
+ <artifactId>odl-transportpce-dmaap-client</artifactId>
+ <version>3.0.0-SNAPSHOT</version>
+ <packaging>feature</packaging>
+
+ <name>OpenDaylight :: transportpce :: dmaap-client</name>
+ <properties>
+ <!-- skipped because we are using config file as artifact and it is not installed before running test -->
+ <skip.karaf.featureTest>true</skip.karaf.featureTest>
+ </properties>
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.transportpce</groupId>
+ <artifactId>odl-transportpce</artifactId>
+ <version>${project.version}</version>
+ <classifier>features</classifier>
+ <type>xml</type>
+ <exclusions>
+ <exclusion>
+ <groupId>org.glassfish.jersey.inject</groupId>
+ <artifactId>jersey-hk2</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.transportpce</groupId>
+ <artifactId>transportpce-dmaap-client</artifactId>
+ <version>${project.version}</version>
+ <exclusions>
+ <exclusion>
+ <groupId>org.glassfish.jersey.inject</groupId>
+ <artifactId>jersey-hk2</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>build-helper-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>attach-dmaap-artifact</id>
+ <phase>test</phase>
+ <goals>
+ <goal>attach-artifact</goal>
+ </goals>
+ <configuration>
+ <artifacts>
+ <artifact>
+ <file>${basedir}/src/main/resources/org.opendaylight.transportpce.dmaap.cfg</file>
+ <type>cfg</type>
+ <classifier>config</classifier>
+ </artifact>
+ </artifacts>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!-- Copyright © 2021 Orange and others. All rights reserved. This program
+ and the accompanying materials are made available under the terms of the
+ Eclipse Public License v1.0 which accompanies this distribution, and is available
+ at http://www.eclipse.org/legal/epl-v10.html INTERNAL -->
+<features xmlns="http://karaf.apache.org/xmlns/features/v1.4.0" name="odl-transportpce-dmaap-client">
+ <feature name="odl-transportpce-dmaap-client">
+ <configfile finalname="etc/org.opendaylight.transportpce.dmaap.cfg" override="false">
+ mvn:${project.groupId}/${project.artifactId}/${project.version}/cfg/config
+ </configfile>
+ </feature>
+</features>
\ No newline at end of file
--- /dev/null
+dmaap.baseUrl=${env:DMAAP_BASE_URL:-http://localhost:8080}
+dmaap.username=${env:DMAAP_USERNAME:+username}
+dmaap.password=${env:DMAAP_PASSWORD:+password}
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright © 2021 Orange and others. All rights reserved. This program
+ and the accompanying materials are made available under the terms of the
+ Eclipse Public License v1.0 which accompanies this distribution, and is available
+ at http://www.eclipse.org/legal/epl-v10.html INTERNAL -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.opendaylight.odlparent</groupId>
+ <artifactId>single-feature-parent</artifactId>
+ <version>8.1.0</version>
+ <relativePath />
+ </parent>
+
+ <groupId>org.opendaylight.transportpce</groupId>
+ <artifactId>odl-transportpce-nbinotifications</artifactId>
+ <version>3.0.0-SNAPSHOT</version>
+ <packaging>feature</packaging>
+
+ <name>OpenDaylight :: transportpce :: nbinotifications</name>
+ <properties>
+ <!-- skipped because we are using config file as artifact and it is not installed before running test -->
+ <skip.karaf.featureTest>true</skip.karaf.featureTest>
+ </properties>
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.transportpce</groupId>
+ <artifactId>odl-transportpce</artifactId>
+ <version>${project.version}</version>
+ <classifier>features</classifier>
+ <type>xml</type>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>transportpce-nbinotifications</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>build-helper-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>attach-dmaap-artifact</id>
+ <phase>package</phase>
+ <goals>
+ <goal>attach-artifact</goal>
+ </goals>
+ <configuration>
+ <artifacts>
+ <artifact>
+ <file>${basedir}/src/main/resources/org.opendaylight.transportpce.nbinotifications.cfg</file>
+ <type>cfg</type>
+ <classifier>config</classifier>
+ </artifact>
+ </artifacts>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!-- Copyright © 2021 Orange and others. All rights reserved. This program
+ and the accompanying materials are made available under the terms of the
+ Eclipse Public License v1.0 which accompanies this distribution, and is available
+ at http://www.eclipse.org/legal/epl-v10.html INTERNAL -->
+<features xmlns="http://karaf.apache.org/xmlns/features/v1.4.0" name="odl-transportpce-nbinotifications">
+ <feature name="odl-transportpce-nbinotifications">
+ <configfile finalname="etc/org.opendaylight.transportpce.nbinotififications.cfg" override="false">
+ mvn:${project.groupId}/${project.artifactId}/${project.version}/cfg/config
+ </configfile>
+ </feature>
+</features>
\ No newline at end of file
--- /dev/null
+suscriber.server=${env:KAFKA_SERVER:-localhost:9092}
+publisher.server=${env:KAFKA_SERVER:-localhost:9092}
<module>odl-transportpce</module>
<module>odl-transportpce-tapi</module>
<module>odl-transportpce-inventory</module>
+ <module>odl-transportpce-nbinotifications</module>
+ <module>odl-transportpce-dmaap-client</module>
</modules>
</project>
<type>xml</type>
<scope>runtime</scope>
</dependency>
-
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>odl-transportpce-nbinotifications</artifactId>
+ <version>${project.version}</version>
+ <classifier>features</classifier>
+ <type>xml</type>
+ <scope>runtime</scope>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>odl-transportpce-dmaap-client</artifactId>
+ <version>${project.version}</version>
+ <classifier>features</classifier>
+ <type>xml</type>
+ <scope>runtime</scope>
+ </dependency>
</dependencies>
<build>
</properties>
<dependencies>
+ <!-- for parsing command line arguments -->
+ <dependency>
+ <groupId>commons-cli</groupId>
+ <artifactId>commons-cli</artifactId>
+ <version>1.4</version>
+ </dependency>
<!-- TPCE Models - BEGIN -->
<dependency>
<artifactId>transportpce-tapi</artifactId>
<version>${transportpce.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.transportpce</groupId>
+ <artifactId>transportpce-nbinotifications</artifactId>
+ <version>${transportpce.version}</version>
+ </dependency>
<!-- TPCE bundles - END -->
<dependency>
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.concurrent.ExecutionException;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.DefaultParser;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Main {
+ private static final String RESTCONF_OPTION_NAME = "restconf";
+
+ private static final String NBINOTIFICATION_OPTION_NAME = "nbinotification";
+
private static final Logger LOG = LoggerFactory.getLogger(Main.class);
private ShutdownHook shutdownHook;
public void start() {
- start(new String[] {}, false);
+ start(null, false, false);
}
@SuppressWarnings("checkstyle:Illegalcatch")
- public void start(String[] args, boolean registerShutdownHook) {
+ public void start(String restConfConfigurationFile, boolean activateNbiNotification, boolean registerShutdownHook) {
long startTime = System.nanoTime();
TpceBanner.print();
RestConfConfiguration restConfConfig = null;
ControllerConfiguration singleNodeConfiguration = ControllerConfigUtils
.getDefaultSingleNodeConfiguration(TPCEUtils.getYangModels());
// 2. get RESTCONF NBP configuration
- if (args.length == 1) {
- Path configPath = Paths.get(args[0]);
+ if (restConfConfigurationFile != null) {
+ Path configPath = Paths.get(restConfConfigurationFile);
LOG.info("Using restconf configuration from file {} ...", configPath);
restConfConfig = RestConfConfigUtils.getRestConfConfiguration(Files.newInputStream(configPath));
restConfConfig.setJsonRestconfServiceType(JsonRestConfServiceType.DRAFT_02);
// 3. NETCONF SBP configuration
NetconfConfiguration netconfSBPConfig = NetconfConfigUtils.createDefaultNetconfConfiguration();
- startLighty(singleNodeConfiguration, restConfConfig, netconfSBPConfig, registerShutdownHook);
+ startLighty(singleNodeConfiguration, restConfConfig, netconfSBPConfig, registerShutdownHook, activateNbiNotification);
float duration = (System.nanoTime() - startTime) / 1_000_000f;
LOG.info("lighty.io and RESTCONF-NETCONF started in {}ms", duration);
} catch (ConfigurationException | ExecutionException | IOException e) {
}
}
+ /**
+ * Build options for command line arguments
+ * @return
+ */
+ private static Options buildOptions() {
+ Option restconfFileOption = Option.builder(RESTCONF_OPTION_NAME)
+ .desc("Restconf configuration file")
+ .argName(RESTCONF_OPTION_NAME)
+ .hasArg(true)
+ .required(false)
+ .build();
+ Option useNbiNotificationsOption = Option.builder(NBINOTIFICATION_OPTION_NAME)
+ .desc("Activate NBI notifications feature")
+ .argName(NBINOTIFICATION_OPTION_NAME)
+ .hasArg(false)
+ .required(false)
+ .build();
+ Options options = new Options();
+ options.addOption(restconfFileOption);
+ options.addOption(useNbiNotificationsOption);
+ return options;
+ }
+
private void startLighty(ControllerConfiguration controllerConfiguration,
RestConfConfiguration restConfConfiguration, NetconfConfiguration netconfSBPConfiguration,
- boolean registerShutdownHook) throws ConfigurationException, ExecutionException, InterruptedException {
+ boolean registerShutdownHook, boolean activateNbiNotification)
+ throws ConfigurationException, ExecutionException, InterruptedException {
// 1. initialize and start Lighty controller (MD-SAL, Controller, YangTools,
// Akka)
netconfSouthboundPlugin.start().get();
// 4. start TransportPCE beans
- TransportPCE transportPCE = new TransportPCEImpl(lightyController.getServices());
+ TransportPCE transportPCE = new TransportPCEImpl(lightyController.getServices(), activateNbiNotification);
transportPCE.start().get();
// 5. Register shutdown hook for graceful shutdown.
}
public static void main(String[] args) {
- Main app = new Main();
- app.start(args, true);
+ Options options = buildOptions();
+ try {
+ CommandLine commandLine = new DefaultParser().parse(options, args);
+ String restConfConfigurationFile = commandLine.getOptionValue(RESTCONF_OPTION_NAME, null);
+ boolean useNbiNotifications = commandLine.hasOption(NBINOTIFICATION_OPTION_NAME);
+ Main app = new Main();
+ app.start(restConfConfigurationFile, useNbiNotifications, true);
+ } catch (ParseException e) {
+ HelpFormatter formatter = new HelpFormatter();
+ formatter.printHelp(
+ "java -ms<size> -mx<size> -XX:MaxMetaspaceSize=<size> -jar tpce.jar "
+ + "[-restconf <restconfConfigurationFile>] [-nbinotification]"
+ +" e.g. java -ms128m -mx512m -XX:MaxMetaspaceSize=128m -jar tpce.jar"
+ + "-restconf ../src/test/resources/config.json -nbinotification",
+ options);
+ System.exit(1);
+ }
}
private static class ShutdownHook extends Thread {
import io.lighty.core.controller.api.AbstractLightyModule;
import io.lighty.core.controller.api.LightyServices;
+
+import java.util.Arrays;
+import java.util.List;
+
import org.opendaylight.transportpce.common.crossconnect.CrossConnect;
import org.opendaylight.transportpce.common.crossconnect.CrossConnectImpl;
import org.opendaylight.transportpce.common.crossconnect.CrossConnectImpl121;
import org.opendaylight.transportpce.common.openroadminterfaces.OpenRoadmInterfacesImpl121;
import org.opendaylight.transportpce.common.openroadminterfaces.OpenRoadmInterfacesImpl221;
import org.opendaylight.transportpce.common.openroadminterfaces.OpenRoadmInterfacesImpl710;
+import org.opendaylight.transportpce.nbinotifications.impl.NbiNotificationsProvider;
import org.opendaylight.transportpce.networkmodel.NetConfTopologyListener;
import org.opendaylight.transportpce.networkmodel.NetworkModelProvider;
import org.opendaylight.transportpce.networkmodel.NetworkUtilsImpl;
private final TapiProvider tapiProvider;
// service-handler beans
private final ServicehandlerProvider servicehandlerProvider;
+ // nbi-notifications beans
+ private NbiNotificationsProvider nbiNotificationsProvider;
+ /**
+ * List of publisher topics.
+ */
+ private final List<String> publisherTopicList =
+ Arrays.asList("PceListener", "ServiceHandlerOperations", "ServiceHandler", "RendererListener");
- public TransportPCEImpl(LightyServices lightyServices) {
+ public TransportPCEImpl(LightyServices lightyServices, boolean activateNbiNotification) {
LOG.info("Initializing transaction providers ...");
deviceTransactionManager = new DeviceTransactionManagerImpl(lightyServices.getBindingMountPointService(),
MAX_DURATION_TO_SUBMIT_TRANSACTION);
serviceDataStoreOperations, pceListenerImpl, rendererListenerImpl, networkModelListenerImpl,
servicehandler);
tapiProvider = initTapi(lightyServices, servicehandler);
+ if(activateNbiNotification) {
+ LOG.info("Creating nbi-notifications beans ...");
+ nbiNotificationsProvider = new NbiNotificationsProvider(
+ publisherTopicList, null, null, lightyServices.getRpcProviderService(),
+ lightyServices.getNotificationService(), lightyServices.getAdapterContext().currentSerializer());
+ }
}
@Override
servicehandlerProvider.init();
LOG.info("Initializing tapi provider ...");
tapiProvider.init();
+ LOG.info("Initializing nbi-notifications provider ...");
+ nbiNotificationsProvider.init();
LOG.info("Init done.");
return true;
}
@Override
protected boolean stopProcedure() {
+ nbiNotificationsProvider.close();
+ LOG.info("Shutting down nbi-notifications provider ...");
tapiProvider.close();
LOG.info("Shutting down service-handler provider ...");
servicehandlerProvider.close();
org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.restconf.rev131019.$YangModuleInfoImpl
.getInstance(),
org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.tapi.rev180928.$YangModuleInfoImpl
+ .getInstance(),
+ org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.$YangModuleInfoImpl
.getInstance());
private static final Set<YangModuleInfo> TPCE_YANG_MODEL = Stream.concat(
@Test
public void startNoConfigFileTest() throws Exception {
- main.start(new String[0], true);
+ main.start(null, false, true);
ContentResponse response = client.GET("http://localhost:8181/restconf/config/ietf-network:networks/network/openroadm-topology");
assertEquals("Response code should be 200", 200, response.getStatus());
}
@Test
public void startConfigFileTest() throws Exception {
File configFile = new File("src/test/resources/config.json");
- String[] args = {configFile.getAbsolutePath()};
- main.start(args, true);
+ main.start(configFile.getAbsolutePath(), false, true);
ContentResponse response = client.GET("http://localhost:8888/restconfCustom/config/ietf-network:networks/network/openroadm-topology");
assertEquals("Response code should be 200", 200, response.getStatus());
}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright © 2020 Orange and others. All rights reserved. This program
+ and the accompanying materials are made available under the terms of the
+ Eclipse Public License v1.0 which accompanies this distribution, and is available
+ at http://www.eclipse.org/legal/epl-v10.html INTERNAL -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.opendaylight.mdsal</groupId>
+ <artifactId>binding-parent</artifactId>
+ <version>7.0.5</version>
+ <relativePath />
+ </parent>
+
+ <groupId>org.opendaylight.transportpce</groupId>
+ <artifactId>transportpce-nbinotifications</artifactId>
+ <version>3.0.0-SNAPSHOT</version>
+ <packaging>bundle</packaging>
+
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <kafka.version>2.6.0</kafka.version>
+ </properties>
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>transportpce-common</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>transportpce-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}.ordmodels</groupId>
+ <artifactId>transportpce-ordmodels-service</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.kafka</groupId>
+ <artifactId>kafka-clients</artifactId>
+ <version>${kafka.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.mdsal</groupId>
+ <artifactId>mdsal-binding-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.mdsal</groupId>
+ <artifactId>mdsal-binding-dom-adapter</artifactId>
+ </dependency>
+ <!-- Testing Dependencies -->
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>test-common</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-databind</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+</project>
--- /dev/null
+/*
+ * Copyright © 2020 Orange, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.nbinotifications.consumer;
+
+import com.google.common.annotations.VisibleForTesting;
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Properties;
+import org.apache.kafka.clients.consumer.Consumer;
+import org.apache.kafka.clients.consumer.ConsumerConfig;
+import org.apache.kafka.clients.consumer.ConsumerRecord;
+import org.apache.kafka.clients.consumer.ConsumerRecords;
+import org.apache.kafka.clients.consumer.KafkaConsumer;
+import org.apache.kafka.common.serialization.StringDeserializer;
+import org.opendaylight.transportpce.common.converter.JsonStringConverter;
+import org.opendaylight.transportpce.nbinotifications.serialization.ConfigConstants;
+import org.opendaylight.transportpce.nbinotifications.serialization.NotificationServiceDeserializer;
+import org.opendaylight.transportpce.nbinotifications.utils.NbiNotificationsUtils;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.get.notifications.service.output.NotificationService;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class Subscriber {
+ private static final Logger LOG = LoggerFactory.getLogger(Subscriber.class);
+
+ private final Consumer<String, NotificationService> consumer;
+
+ public Subscriber(String id, String groupId, String suscriberServer,
+ JsonStringConverter<org.opendaylight.yang.gen.v1
+ .nbi.notifications.rev201130.NotificationService> deserializer) {
+ Properties propsConsumer = NbiNotificationsUtils.loadProperties("subscriber.properties");
+ propsConsumer.put(ConsumerConfig.GROUP_ID_CONFIG, groupId);
+ propsConsumer.put(ConsumerConfig.CLIENT_ID_CONFIG, id);
+ propsConsumer.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
+ propsConsumer.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG , NotificationServiceDeserializer.class);
+ propsConsumer.put(ConfigConstants.CONVERTER , deserializer);
+ if (suscriberServer != null && !suscriberServer.isBlank()) {
+ propsConsumer.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, suscriberServer);
+ }
+ LOG.info("Suscribing for group id {}, client config id {} with properties {}", groupId, id, propsConsumer);
+ consumer = new KafkaConsumer<>(propsConsumer);
+ }
+
+ public List<NotificationService> subscribeService(String topicName) {
+ LOG.info("Subscribe request to topic '{}' ", topicName);
+ consumer.subscribe(Collections.singleton(topicName));
+ final ConsumerRecords<String, NotificationService> consumerRecords = consumer.poll(Duration.ofMillis(1000));
+ List<NotificationService> notificationServiceList = new ArrayList<>();
+ YangInstanceIdentifier.of(NotificationService.QNAME);
+ for (ConsumerRecord<String, NotificationService> record : consumerRecords) {
+ if (record.value() != null) {
+ notificationServiceList.add(record.value());
+ }
+ }
+ LOG.info("Getting records '{}' ", notificationServiceList);
+ consumer.unsubscribe();
+ consumer.close();
+ return notificationServiceList;
+ }
+
+ @VisibleForTesting public Subscriber(Consumer<String, NotificationService> consumer) {
+ this.consumer = consumer;
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2020 Orange, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.nbinotifications.impl;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import java.util.List;
+import org.opendaylight.transportpce.common.converter.JsonStringConverter;
+import org.opendaylight.transportpce.nbinotifications.consumer.Subscriber;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.GetNotificationsServiceInput;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.GetNotificationsServiceOutput;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.GetNotificationsServiceOutputBuilder;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.NbiNotificationsService;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.get.notifications.service.output.NotificationService;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NbiNotificationsImpl implements NbiNotificationsService {
+ private static final Logger LOG = LoggerFactory.getLogger(NbiNotificationsImpl.class);
+ private final JsonStringConverter<org.opendaylight.yang.gen.v1
+ .nbi.notifications.rev201130.NotificationService> converter;
+ private final String server;
+
+ public NbiNotificationsImpl(JsonStringConverter<org.opendaylight.yang.gen.v1
+ .nbi.notifications.rev201130.NotificationService> converter, String server) {
+ this.converter = converter;
+ this.server = server;
+ }
+
+ @Override
+ public ListenableFuture<RpcResult<GetNotificationsServiceOutput>> getNotificationsService(
+ GetNotificationsServiceInput input) {
+ LOG.info("RPC getNotificationsService received");
+ if (input == null || input.getIdConsumer() == null || input.getGroupId() == null) {
+ LOG.warn("Missing mandatory params for input {}", input);
+ return RpcResultBuilder.success(new GetNotificationsServiceOutputBuilder().build()).buildFuture();
+ }
+ Subscriber subscriber = new Subscriber(input.getIdConsumer(), input.getGroupId(), server, converter);
+ List<NotificationService> notificationServiceList = subscriber
+ .subscribeService(input.getConnectionType().getName());
+ GetNotificationsServiceOutputBuilder output = new GetNotificationsServiceOutputBuilder()
+ .setNotificationService(notificationServiceList);
+ return RpcResultBuilder.success(output.build()).buildFuture();
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2020 Orange, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.nbinotifications.impl;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.opendaylight.mdsal.binding.api.NotificationService;
+import org.opendaylight.mdsal.binding.api.RpcProviderService;
+import org.opendaylight.mdsal.binding.dom.codec.spi.BindingDOMCodecServices;
+import org.opendaylight.transportpce.common.converter.JsonStringConverter;
+import org.opendaylight.transportpce.nbinotifications.listener.NbiNotificationsListenerImpl;
+import org.opendaylight.transportpce.nbinotifications.producer.Publisher;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.NbiNotificationsListener;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.NbiNotificationsService;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.concepts.ObjectRegistration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NbiNotificationsProvider {
+
+ private static final Logger LOG = LoggerFactory.getLogger(NbiNotificationsProvider.class);
+ private static Map<String, Publisher> publishersMap = new HashMap<>();
+
+ private final RpcProviderService rpcService;
+ private ObjectRegistration<NbiNotificationsService> rpcRegistration;
+ private ListenerRegistration<NbiNotificationsListener> listenerRegistration;
+ private NotificationService notificationService;
+ private final JsonStringConverter<org.opendaylight.yang.gen.v1
+ .nbi.notifications.rev201130.NotificationService> converter;
+ private final String suscriberServer;
+
+
+ public NbiNotificationsProvider(List<String> topics,
+ String suscriberServer, String publisherServer,
+ RpcProviderService rpcProviderService, NotificationService notificationService,
+ BindingDOMCodecServices bindingDOMCodecServices) {
+ this.rpcService = rpcProviderService;
+ this.notificationService = notificationService;
+ converter = new JsonStringConverter<>(bindingDOMCodecServices);
+ for (String topic: topics) {
+ LOG.info("Creating publisher for topic {}", topic);
+ publishersMap.put(topic, new Publisher(topic, publisherServer, converter));
+ }
+ this.suscriberServer = suscriberServer;
+ }
+
+ /**
+ * Method called when the blueprint container is created.
+ */
+ public void init() {
+ LOG.info("NbiNotificationsProvider Session Initiated");
+ rpcRegistration = rpcService.registerRpcImplementation(NbiNotificationsService.class,
+ new NbiNotificationsImpl(converter, suscriberServer));
+ listenerRegistration = notificationService.registerNotificationListener(
+ new NbiNotificationsListenerImpl(publishersMap));
+ }
+
+ /**
+ * Method called when the blueprint container is destroyed.
+ */
+ public void close() {
+ for (Publisher publisher : publishersMap.values()) {
+ publisher.close();
+ }
+ rpcRegistration.close();
+ listenerRegistration.close();
+ LOG.info("NbiNotificationsProvider Closed");
+ }
+
+}
--- /dev/null
+/*
+ * Copyright © 2020 Orange, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.nbinotifications.listener;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.opendaylight.transportpce.nbinotifications.producer.Publisher;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.NbiNotificationsListener;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.NotificationServiceBuilder;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.PublishNotificationService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NbiNotificationsListenerImpl implements NbiNotificationsListener {
+ private static final Logger LOG = LoggerFactory.getLogger(NbiNotificationsListenerImpl.class);
+ private Map<String, Publisher> publishersMap = new HashMap<>();
+
+ public NbiNotificationsListenerImpl(Map<String, Publisher> publishersMap) {
+ this.publishersMap = publishersMap;
+ }
+
+ @Override
+ public void onPublishNotificationService(PublishNotificationService notification) {
+ LOG.info("Receiving request for publishing notification service");
+ String topic = notification.getTopic();
+ if (!publishersMap.containsKey(topic)) {
+ LOG.error("Unknown topic {}", topic);
+ return;
+ }
+ Publisher publisher = publishersMap.get(topic);
+ publisher.sendEvent(new NotificationServiceBuilder().setCommonId(notification.getCommonId())
+ .setConnectionType(notification.getConnectionType()).setMessage(notification.getMessage())
+ .setOperationalState(notification.getOperationalState())
+ .setResponseFailed(notification.getResponseFailed())
+ .setServiceAEnd(notification.getServiceAEnd()).setServiceName(notification.getServiceName())
+ .setServiceZEnd(notification.getServiceZEnd()).build());
+
+ }
+
+}
--- /dev/null
+/*
+ * Copyright © 2020 Orange, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.nbinotifications.producer;
+
+import com.google.common.annotations.VisibleForTesting;
+import java.util.Properties;
+import org.apache.kafka.clients.producer.KafkaProducer;
+import org.apache.kafka.clients.producer.Producer;
+import org.apache.kafka.clients.producer.ProducerConfig;
+import org.apache.kafka.clients.producer.ProducerRecord;
+import org.apache.kafka.common.serialization.StringSerializer;
+import org.opendaylight.transportpce.common.converter.JsonStringConverter;
+import org.opendaylight.transportpce.nbinotifications.serialization.ConfigConstants;
+import org.opendaylight.transportpce.nbinotifications.serialization.NotificationServiceSerializer;
+import org.opendaylight.transportpce.nbinotifications.utils.NbiNotificationsUtils;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.NotificationService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class Publisher {
+ private static final Logger LOG = LoggerFactory.getLogger(Publisher.class);
+
+ private final String id;
+ private final Producer<String, NotificationService> producer;
+
+ public Publisher(String id, String publisherServer, JsonStringConverter<NotificationService> serializer) {
+ Properties properties = NbiNotificationsUtils.loadProperties("publisher.properties");
+ properties.put(ProducerConfig.CLIENT_ID_CONFIG, id);
+ if (publisherServer != null && !publisherServer.isBlank()) {
+ properties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, publisherServer);
+ }
+ properties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
+ properties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG , NotificationServiceSerializer.class);
+ properties.put(ConfigConstants.CONVERTER , serializer);
+ LOG.info("Creationg publisher for id {} with properties {}", id, properties);
+ producer = new KafkaProducer<>(properties);
+ this.id = id;
+ }
+
+ @VisibleForTesting Publisher(String id, Producer<String, NotificationService> producer) {
+ this.producer = producer;
+ this.id = id;
+ }
+
+ public void close() {
+ producer.close();
+ }
+
+ public void sendEvent(NotificationService notificationService) {
+ LOG.info("SendEvent request to topic '{}' ", notificationService.getConnectionType().getName());
+ producer.send(new ProducerRecord<>(notificationService.getConnectionType().getName(), id, notificationService));
+ producer.flush();
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2021 Orange, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.nbinotifications.serialization;
+
+public final class ConfigConstants {
+ private ConfigConstants() {
+ }
+
+ public static final String CONVERTER = "converter";
+
+}
--- /dev/null
+/*
+ * Copyright © 2021 Orange, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.nbinotifications.serialization;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Map;
+import org.apache.kafka.common.serialization.Deserializer;
+import org.opendaylight.transportpce.common.converter.JsonStringConverter;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.get.notifications.service.output.NotificationService;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.get.notifications.service.output.NotificationServiceBuilder;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.codec.gson.JSONCodecFactorySupplier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NotificationServiceDeserializer implements Deserializer<NotificationService> {
+ private static final Logger LOG = LoggerFactory.getLogger(NotificationServiceDeserializer.class);
+ private JsonStringConverter<org.opendaylight.yang.gen.v1
+ .nbi.notifications.rev201130.NotificationService> converter;
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public void configure(Map<String, ?> configs, boolean isKey) {
+ LOG.info("Deserializer configuration {}", configs);
+ if (configs.containsKey(ConfigConstants.CONVERTER)
+ && configs.get(ConfigConstants.CONVERTER) instanceof JsonStringConverter<?>) {
+ converter = (JsonStringConverter<org.opendaylight.yang.gen.v1
+ .nbi.notifications.rev201130.NotificationService>) configs
+ .get(ConfigConstants.CONVERTER);
+ }
+ }
+
+ @Override
+ public NotificationService deserialize(String topic, byte[] data) {
+ if (converter == null) {
+ throw new IllegalArgumentException(
+ "Converter should be configured through configure method of deserializer");
+ }
+ String value = new String(data, StandardCharsets.UTF_8);
+ // The message published is
+ // org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.NotificationService
+ // we have to map it to
+ // org.opendaylight.yang.gen
+ // .v1.nbi.notifications.rev201130.get.notifications.service.output.NotificationService
+ org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.NotificationService mappedString = converter
+ .createDataObjectFromJsonString(YangInstanceIdentifier.of(
+ org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.NotificationService.QNAME),
+ value,
+ JSONCodecFactorySupplier.RFC7951);
+ if (mappedString != null) {
+ LOG.info("Reading event {}", mappedString);
+ return new NotificationServiceBuilder().setCommonId(mappedString.getCommonId())
+ .setConnectionType(mappedString.getConnectionType()).setMessage(mappedString.getMessage())
+ .setOperationalState(mappedString.getOperationalState())
+ .setResponseFailed(mappedString.getResponseFailed()).setServiceName(mappedString.getServiceName())
+ .setServiceAEnd(mappedString.getServiceAEnd()).setServiceZEnd(mappedString.getServiceZEnd())
+ .build();
+ }
+ return null;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright © 2021 Orange, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.nbinotifications.serialization;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.Map;
+import org.apache.kafka.common.serialization.Serializer;
+import org.opendaylight.transportpce.common.converter.JsonStringConverter;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.NotificationService;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.codec.gson.JSONCodecFactorySupplier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NotificationServiceSerializer implements Serializer<NotificationService> {
+ private static final Logger LOG = LoggerFactory.getLogger(NotificationServiceSerializer.class);
+ private JsonStringConverter<NotificationService> converter;
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public void configure(Map<String, ?> configs, boolean isKey) {
+ LOG.info("Deserializer configuration {}", configs);
+ if (configs.containsKey(ConfigConstants.CONVERTER)
+ && configs.get(ConfigConstants.CONVERTER) instanceof JsonStringConverter<?>) {
+ converter = (JsonStringConverter<NotificationService>) configs.get(ConfigConstants.CONVERTER);
+ }
+ }
+
+ @Override
+ public byte[] serialize(String topic, NotificationService data) {
+ if (converter == null) {
+ throw new IllegalArgumentException(
+ "Converter should be" + "configured through configure method of serializer");
+ }
+ if (data == null) {
+ return new byte[0];
+ }
+ try {
+ InstanceIdentifier<NotificationService> iid = InstanceIdentifier.builder(NotificationService.class).build();
+ String serialized = converter.createJsonStringFromDataObject(iid, data, JSONCodecFactorySupplier.RFC7951);
+ LOG.info("Serialized event {}", serialized);
+ return serialized.getBytes(StandardCharsets.UTF_8);
+ } catch (IOException e) {
+ return new byte[0];
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2020 Orange, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.nbinotifications.utils;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public final class NbiNotificationsUtils {
+
+ private static final Logger LOG = LoggerFactory.getLogger(NbiNotificationsUtils.class);
+
+ private NbiNotificationsUtils() {
+ }
+
+ public static Properties loadProperties(String propertyFileName) {
+ Properties props = new Properties();
+ InputStream inputStream = NbiNotificationsUtils.class.getClassLoader()
+ .getResourceAsStream(propertyFileName);
+ try {
+ if (inputStream != null) {
+ props.load(inputStream);
+ } else {
+ LOG.warn("Kafka property file '{}' is empty", propertyFileName);
+ }
+ } catch (IOException e) {
+ LOG.warn("Kafka property file '{}' was not found in the classpath", propertyFileName);
+ }
+ return props;
+ }
+}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!-- Copyright © 2020 Orange and others. All rights reserved. This program and the accompanying materials
+ are made available under the terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ and is available at http://www.eclipse.org/legal/epl-v10.html -->
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" xmlns:odl="http://opendaylight.org/xmlns/blueprint/v1.0.0"
+xmlns:cm="http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.1.0"
+ odl:use-default-for-reference-types="true">
+ <cm:property-placeholder persistent-id="org.opendaylight.transportpce.nbinotifications" update-strategy="reload">
+ <cm:default-properties>
+ <cm:property name="suscriber.server" value="" />
+ <cm:property name="publisher.server" value="" />
+ </cm:default-properties>
+ </cm:property-placeholder>
+ <reference id="rpcService" interface="org.opendaylight.mdsal.binding.api.RpcProviderService"/>
+ <reference id="notificationService" interface="org.opendaylight.mdsal.binding.api.NotificationService"/>
+ <reference id="bindingDOMCodecServices" interface="org.opendaylight.mdsal.binding.dom.codec.spi.BindingDOMCodecServices" />
+ <bean id="provider"
+ class="org.opendaylight.transportpce.nbinotifications.impl.NbiNotificationsProvider"
+ init-method="init" destroy-method="close">
+ <argument>
+ <list value-type="java.lang.String">
+ <value>PceListener</value>
+ <value>ServiceHandlerOperations</value>
+ <value>ServiceHandler</value>
+ <value>RendererListener</value>
+ </list>
+ </argument>
+ <argument value="${suscriber.server}"/>
+ <argument value="${publisher.server}"/>
+ <argument ref="rpcService" />
+ <argument ref="notificationService" />
+ <argument ref="bindingDOMCodecServices" />
+ </bean>
+</blueprint>
--- /dev/null
+#Kafka Producer/AdminClient properties
+bootstrap.servers=localhost:9092
+acks=all
+retries=3
+max.in.flight.requests.per.connection=1
+batch.size=16384
+linger.ms=1
+buffer.memory=33554432
--- /dev/null
+#Kafka Consumer properties
+bootstrap.servers=localhost:9092
+enable.auto.commit=true
+auto.commit.interval.ms=1000
+auto.offset.reset=earliest
--- /dev/null
+/*
+ * Copyright © 2020 Orange, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.nbinotifications.consumer;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.apache.kafka.clients.consumer.ConsumerRecord;
+import org.apache.kafka.clients.consumer.MockConsumer;
+import org.apache.kafka.clients.consumer.OffsetResetStrategy;
+import org.apache.kafka.common.TopicPartition;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.transportpce.nbinotifications.utils.NotificationServiceDataUtils;
+import org.opendaylight.transportpce.test.AbstractTest;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.get.notifications.service.output.NotificationService;
+
+public class SubscriberTest extends AbstractTest {
+ private static final String TOPIC = "topic";
+ private static final int PARTITION = 0;
+ private MockConsumer<String, NotificationService> mockConsumer;
+ private Subscriber subscriber;
+
+ @Before
+ public void setUp() {
+ mockConsumer = new MockConsumer<>(OffsetResetStrategy.EARLIEST);
+ subscriber = new Subscriber(mockConsumer);
+ }
+
+ @Test
+ public void subscribeServiceShouldBeSuccessful() {
+ // from https://www.baeldung.com/kafka-mockconsumer
+ ConsumerRecord<String, NotificationService> record = new ConsumerRecord<String, NotificationService>(
+ TOPIC, PARTITION, 0L, "key", NotificationServiceDataUtils.buildReceivedEvent());
+ mockConsumer.schedulePollTask(() -> {
+ mockConsumer.rebalance(Collections.singletonList(new TopicPartition(TOPIC, PARTITION)));
+ mockConsumer.addRecord(record);
+ });
+
+ Map<TopicPartition, Long> startOffsets = new HashMap<>();
+ TopicPartition tp = new TopicPartition(TOPIC, PARTITION);
+ startOffsets.put(tp, 0L);
+ mockConsumer.updateBeginningOffsets(startOffsets);
+ List<NotificationService> result = subscriber.subscribeService(TOPIC);
+ assertEquals("There should be 1 record", 1, result.size());
+ assertTrue("Consumer should be closed", mockConsumer.closed());
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2020 Orange, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.nbinotifications.impl;
+
+import static org.junit.Assert.assertNull;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import java.util.concurrent.ExecutionException;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.transportpce.common.converter.JsonStringConverter;
+import org.opendaylight.transportpce.test.AbstractTest;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev190531.ConnectionType;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.GetNotificationsServiceInputBuilder;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.GetNotificationsServiceOutput;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+
+public class NbiNotificationsImplTest extends AbstractTest {
+ private NbiNotificationsImpl nbiNotificationsImpl;
+
+ @Before
+ public void setUp() {
+ JsonStringConverter<org.opendaylight.yang.gen.v1
+ .nbi.notifications.rev201130.NotificationService> converter = new JsonStringConverter<>(
+ getDataStoreContextUtil().getBindingDOMCodecServices());
+ nbiNotificationsImpl = new NbiNotificationsImpl(converter, "localhost:8080");
+ }
+
+ public void getNotificationsServiceEmptyDataTest() throws InterruptedException, ExecutionException {
+ ListenableFuture<RpcResult<GetNotificationsServiceOutput>> result =
+ nbiNotificationsImpl.getNotificationsService(new GetNotificationsServiceInputBuilder().build());
+ assertNull("Should be null", result.get().getResult().getNotificationService());
+ }
+
+ @Test
+ public void getNotificationsServiceTest() throws InterruptedException, ExecutionException {
+ GetNotificationsServiceInputBuilder builder = new GetNotificationsServiceInputBuilder();
+ builder.setGroupId("groupId");
+ builder.setIdConsumer("consumerId");
+ builder.setConnectionType(ConnectionType.Service);
+ ListenableFuture<RpcResult<GetNotificationsServiceOutput>> result =
+ nbiNotificationsImpl.getNotificationsService(builder.build());
+ assertNull("Should be null", result.get().getResult().getNotificationService());
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2020 Orange, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.nbinotifications.impl;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import java.util.Arrays;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.mdsal.binding.api.NotificationService;
+import org.opendaylight.mdsal.binding.api.RpcProviderService;
+import org.opendaylight.transportpce.nbinotifications.listener.NbiNotificationsListenerImpl;
+import org.opendaylight.transportpce.test.AbstractTest;
+
+public class NbiNotificationsProviderTest extends AbstractTest {
+
+ @Mock
+ RpcProviderService rpcProviderRegistry;
+
+ @Mock
+ private NotificationService notificationService;
+
+ @Before
+ public void init() {
+ MockitoAnnotations.openMocks(this);
+
+ }
+
+ @Test
+ public void initTest() {
+ NbiNotificationsProvider provider = new NbiNotificationsProvider(
+ Arrays.asList("topic1", "topic2"), "localhost:8080", "localhost:8080",
+ rpcProviderRegistry, notificationService,
+ getDataStoreContextUtil().getBindingDOMCodecServices());
+ provider.init();
+ verify(rpcProviderRegistry, times(1))
+ .registerRpcImplementation(any(), any(NbiNotificationsImpl.class));
+ verify(notificationService, times(1))
+ .registerNotificationListener(any(NbiNotificationsListenerImpl.class));
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2021 Orange, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.nbinotifications.listener;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import java.util.Map;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.transportpce.nbinotifications.producer.Publisher;
+import org.opendaylight.transportpce.test.AbstractTest;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev190531.ConnectionType;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.common.state.types.rev181130.State;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.PublishNotificationService;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.PublishNotificationServiceBuilder;
+
+public class NbiNotificationsListenerImplTest extends AbstractTest {
+ @Mock
+ private Publisher publisher;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.openMocks(this);
+ }
+
+ @Test
+ public void onPublishNotificationServiceTest() {
+ NbiNotificationsListenerImpl listener = new NbiNotificationsListenerImpl(Map.of("test", publisher));
+ PublishNotificationService notification = new PublishNotificationServiceBuilder().setTopic("test")
+ .setCommonId("commonId").setConnectionType(ConnectionType.Service).setMessage("Service deleted")
+ .setOperationalState(State.OutOfService).setServiceName("service name").build();
+ listener.onPublishNotificationService(notification);
+ verify(publisher, times(1)).sendEvent(any());
+ }
+
+ @Test
+ public void onPublishNotificationServiceWrongTopicTest() {
+ NbiNotificationsListenerImpl listener = new NbiNotificationsListenerImpl(Map.of("test", publisher));
+ PublishNotificationService notification = new PublishNotificationServiceBuilder().setTopic("wrongtopic")
+ .setCommonId("commonId").setConnectionType(ConnectionType.Service).setMessage("Service deleted")
+ .setOperationalState(State.OutOfService).setServiceName("service name").build();
+ listener.onPublishNotificationService(notification);
+ verify(publisher, times(0)).sendEvent(any());
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2020 Orange, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.nbinotifications.producer;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.Map;
+import org.apache.kafka.clients.producer.MockProducer;
+import org.apache.kafka.common.serialization.StringSerializer;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.transportpce.common.converter.JsonStringConverter;
+import org.opendaylight.transportpce.nbinotifications.serialization.ConfigConstants;
+import org.opendaylight.transportpce.nbinotifications.serialization.NotificationServiceSerializer;
+import org.opendaylight.transportpce.test.AbstractTest;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.NotificationService;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.codec.gson.JSONCodecFactorySupplier;
+
+public class PublisherTest extends AbstractTest {
+ private JsonStringConverter<NotificationService> converter;
+ private Publisher publisher;
+ private MockProducer<String, NotificationService> mockProducer;
+
+ @Before
+ public void setUp() {
+ NotificationServiceSerializer serializer = new NotificationServiceSerializer();
+ Map<String, Object> properties = Map.of(ConfigConstants.CONVERTER , serializer);
+ serializer.configure(properties, false);
+ mockProducer = new MockProducer<>(true, new StringSerializer(), serializer);
+ converter = new JsonStringConverter<NotificationService>(
+ getDataStoreContextUtil().getBindingDOMCodecServices());
+ publisher = new Publisher("test",mockProducer);
+ }
+
+ @Test
+ public void sendEventShouldBeSuccessful() throws IOException {
+ String json = Files.readString(Paths.get("src/test/resources/event.json"));
+ NotificationService notificationService = converter
+ .createDataObjectFromJsonString(YangInstanceIdentifier.of(NotificationService.QNAME),
+ json, JSONCodecFactorySupplier.RFC7951);
+ publisher.sendEvent(notificationService);
+ assertEquals("We should have one message", 1, mockProducer.history().size());
+ assertEquals("Key should be test", "test",mockProducer.history().get(0).key());
+ }
+
+}
--- /dev/null
+/*
+ * Copyright © 2021 Orange, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.nbinotifications.serialization;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.Map;
+import org.junit.Test;
+import org.opendaylight.transportpce.common.converter.JsonStringConverter;
+import org.opendaylight.transportpce.test.AbstractTest;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.get.notifications.service.output.NotificationService;
+
+public class NotificationServiceDeserializerTest extends AbstractTest {
+
+ @Test
+ public void deserializeTest() throws IOException {
+ JsonStringConverter<org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.NotificationService> converter =
+ new JsonStringConverter<>(getDataStoreContextUtil().getBindingDOMCodecServices());
+ NotificationServiceDeserializer deserializer = new NotificationServiceDeserializer();
+ Map<String, Object> configs = Map.of(ConfigConstants.CONVERTER, converter);
+ deserializer.configure(configs, false);
+ NotificationService readEvent = deserializer.deserialize("Test",
+ Files.readAllBytes(Paths.get("src/test/resources/event.json")));
+ deserializer.close();
+ assertEquals("Service name should be service1", "service1", readEvent.getServiceName());
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2021 Orange, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.nbinotifications.serialization;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.Map;
+import org.junit.Test;
+import org.opendaylight.transportpce.common.converter.JsonStringConverter;
+import org.opendaylight.transportpce.test.AbstractTest;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.NotificationService;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.codec.gson.JSONCodecFactorySupplier;
+
+public class NotificationServiceSerializerTest extends AbstractTest {
+
+ @Test
+ public void serializeTest() throws IOException {
+ JsonStringConverter<NotificationService> converter =
+ new JsonStringConverter<>(getDataStoreContextUtil().getBindingDOMCodecServices());
+ String json = Files.readString(Paths.get("src/test/resources/event.json"));
+ NotificationService notificationService = converter
+ .createDataObjectFromJsonString(YangInstanceIdentifier.of(NotificationService.QNAME),
+ json, JSONCodecFactorySupplier.RFC7951);
+ NotificationServiceSerializer serializer = new NotificationServiceSerializer();
+ Map<String, Object> configs = Map.of(ConfigConstants.CONVERTER, converter);
+ serializer.configure(configs, false);
+ byte[] data = serializer.serialize("test", notificationService);
+ serializer.close();
+ assertNotNull("Serialized data should not be null", data);
+ String expectedJson = Files.readString(Paths.get("src/test/resources/expected_event.json"));
+ assertEquals("The event should be equals", expectedJson, new String(data, StandardCharsets.UTF_8));
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2020 Orange, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.nbinotifications.utils;
+
+import org.opendaylight.yang.gen.v1.http.org.openroadm.common.node.types.rev181130.NodeIdType;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev190531.ConnectionType;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev190531.service.endpoint.RxDirection;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev190531.service.endpoint.TxDirection;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev190531.service.lgx.LgxBuilder;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev190531.service.port.PortBuilder;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.common.state.types.rev181130.State;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.service.format.rev190531.ServiceFormat;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.NotificationService;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.NotificationServiceBuilder;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.notification.service.ServiceAEndBuilder;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.notification.service.ServiceZEndBuilder;
+import org.opendaylight.yangtools.yang.common.Uint32;
+
+public final class NotificationServiceDataUtils {
+
+ private NotificationServiceDataUtils() {
+ }
+
+ public static NotificationService buildSendEventInput() {
+ NotificationServiceBuilder notificationServiceBuilder = new NotificationServiceBuilder()
+ .setMessage("message")
+ .setServiceName("service1")
+ .setOperationalState(State.InService)
+ .setResponseFailed("")
+ .setCommonId("commond-id")
+ .setConnectionType(ConnectionType.Service)
+ .setServiceZEnd(getServiceZEndBuild().build())
+ .setServiceAEnd(getServiceAEndBuild().build());
+
+ return notificationServiceBuilder.build();
+ }
+
+ public static org.opendaylight.yang.gen.v1
+ .nbi.notifications.rev201130.get.notifications.service.output.NotificationService buildReceivedEvent() {
+ org.opendaylight.yang.gen.v1
+ .nbi.notifications.rev201130.get.notifications.service.output.NotificationServiceBuilder
+ notificationServiceBuilder = new org.opendaylight.yang.gen.v1
+ .nbi.notifications.rev201130.get.notifications.service.output.NotificationServiceBuilder()
+ .setMessage("message")
+ .setServiceName("service1")
+ .setOperationalState(State.InService)
+ .setResponseFailed("")
+ .setCommonId("commond-id")
+ .setConnectionType(ConnectionType.Service)
+ .setServiceZEnd(getServiceZEndBuild().build())
+ .setServiceAEnd(getServiceAEndBuild().build());
+
+ return notificationServiceBuilder.build();
+ }
+
+ public static ServiceAEndBuilder getServiceAEndBuild() {
+ return new ServiceAEndBuilder()
+ .setClli("clli").setServiceFormat(ServiceFormat.OC).setServiceRate(Uint32.valueOf(1))
+ .setNodeId(new NodeIdType("XPONDER-1-2"))
+ .setTxDirection(getTxDirection())
+ .setRxDirection(getRxDirection());
+ }
+
+ public static ServiceZEndBuilder getServiceZEndBuild() {
+ return new ServiceZEndBuilder()
+ .setClli("clli").setServiceFormat(ServiceFormat.OC).setServiceRate(Uint32.valueOf(1))
+ .setNodeId(new NodeIdType("XPONDER-1-2"))
+ .setTxDirection(getTxDirection())
+ .setRxDirection(getRxDirection());
+ }
+
+ private static TxDirection getTxDirection() {
+ return new org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev190531.service
+ .endpoint.TxDirectionBuilder().setPort(new PortBuilder().setPortDeviceName("device name")
+ .setPortName("port name").setPortRack("port rack").setPortShelf("port shelf")
+ .setPortSlot("port slot").setPortSubSlot("port subslot").setPortType("port type").build())
+ .setLgx(new LgxBuilder().setLgxDeviceName("lgx device name").setLgxPortName("lgx port name")
+ .setLgxPortRack("lgx port rack").setLgxPortShelf("lgx port shelf").build())
+ .build();
+ }
+
+ private static RxDirection getRxDirection() {
+ return new org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev190531.service
+ .endpoint.RxDirectionBuilder()
+ .setPort(new PortBuilder().setPortDeviceName("device name").setPortName("port name")
+ .setPortRack("port rack").setPortShelf("port shelf").setPortSlot("port slot")
+ .setPortSubSlot("port subslot").setPortType("port type").build())
+ .setLgx(new LgxBuilder().setLgxDeviceName("lgx device name")
+ .setLgxPortName("lgx port name").setLgxPortRack("lgx port rack")
+ .setLgxPortShelf("lgx port shelf").build())
+ .build();
+ }
+}
--- /dev/null
+{
+ "notification-service": {
+ "service-name": "service1",
+ "service-a-end": {
+ "service-format": "OC",
+ "node-id": "XPONDER-1-2",
+ "service-rate": 1,
+ "clli": "clli",
+ "tx-direction": {
+ "port": {
+ "port-slot": "port slot",
+ "port-device-name": "device name",
+ "port-rack": "port rack",
+ "port-shelf": "port shelf",
+ "port-type": "port type",
+ "port-sub-slot": "port subslot",
+ "port-name": "port name"
+ },
+ "lgx": {
+ "lgx-port-name": "lgx port name",
+ "lgx-port-shelf": "lgx port shelf",
+ "lgx-port-rack": "lgx port rack",
+ "lgx-device-name": "lgx device name"
+ }
+ },
+ "rx-direction": {
+ "port": {
+ "port-slot": "port slot",
+ "port-device-name": "device name",
+ "port-rack": "port rack",
+ "port-shelf": "port shelf",
+ "port-type": "port type",
+ "port-sub-slot": "port subslot",
+ "port-name": "port name"
+ },
+ "lgx": {
+ "lgx-port-name": "lgx port name",
+ "lgx-port-shelf": "lgx port shelf",
+ "lgx-port-rack": "lgx port rack",
+ "lgx-device-name": "lgx device name"
+ }
+ }
+ },
+ "common-id": "commond-id",
+ "operational-state": "inService",
+ "connection-type": "service",
+ "service-z-end": {
+ "service-format": "OC",
+ "node-id": "XPONDER-1-2",
+ "service-rate": 1,
+ "clli": "clli",
+ "tx-direction": {
+ "port": {
+ "port-slot": "port slot",
+ "port-device-name": "device name",
+ "port-rack": "port rack",
+ "port-shelf": "port shelf",
+ "port-type": "port type",
+ "port-sub-slot": "port subslot",
+ "port-name": "port name"
+ },
+ "lgx": {
+ "lgx-port-name": "lgx port name",
+ "lgx-port-shelf": "lgx port shelf",
+ "lgx-port-rack": "lgx port rack",
+ "lgx-device-name": "lgx device name"
+ }
+ },
+ "rx-direction": {
+ "port": {
+ "port-slot": "port slot",
+ "port-device-name": "device name",
+ "port-rack": "port rack",
+ "port-shelf": "port shelf",
+ "port-type": "port type",
+ "port-sub-slot": "port subslot",
+ "port-name": "port name"
+ },
+ "lgx": {
+ "lgx-port-name": "lgx port name",
+ "lgx-port-shelf": "lgx port shelf",
+ "lgx-port-rack": "lgx port rack",
+ "lgx-device-name": "lgx device name"
+ }
+ }
+ },
+ "message": "message",
+ "response-failed": ""
+ }
+}
--- /dev/null
+{"notification-service":{"service-name":"service1","service-a-end":{"service-format":"OC","node-id":"XPONDER-1-2","service-rate":1,"clli":"clli","tx-direction":{"port":{"port-slot":"port slot","port-device-name":"device name","port-rack":"port rack","port-shelf":"port shelf","port-type":"port type","port-sub-slot":"port subslot","port-name":"port name"},"lgx":{"lgx-port-name":"lgx port name","lgx-port-shelf":"lgx port shelf","lgx-port-rack":"lgx port rack","lgx-device-name":"lgx device name"}},"rx-direction":{"port":{"port-slot":"port slot","port-device-name":"device name","port-rack":"port rack","port-shelf":"port shelf","port-type":"port type","port-sub-slot":"port subslot","port-name":"port name"},"lgx":{"lgx-port-name":"lgx port name","lgx-port-shelf":"lgx port shelf","lgx-port-rack":"lgx port rack","lgx-device-name":"lgx device name"}}},"common-id":"commond-id","operational-state":"inService","connection-type":"service","service-z-end":{"service-format":"OC","node-id":"XPONDER-1-2","service-rate":1,"clli":"clli","tx-direction":{"port":{"port-slot":"port slot","port-device-name":"device name","port-rack":"port rack","port-shelf":"port shelf","port-type":"port type","port-sub-slot":"port subslot","port-name":"port name"},"lgx":{"lgx-port-name":"lgx port name","lgx-port-shelf":"lgx port shelf","lgx-port-rack":"lgx port rack","lgx-device-name":"lgx device name"}},"rx-direction":{"port":{"port-slot":"port slot","port-device-name":"device name","port-rack":"port rack","port-shelf":"port shelf","port-type":"port type","port-sub-slot":"port subslot","port-name":"port name"},"lgx":{"lgx-port-name":"lgx port name","lgx-port-shelf":"lgx port shelf","lgx-port-rack":"lgx port rack","lgx-device-name":"lgx device name"}}},"message":"message","response-failed":""}}
\ No newline at end of file
--- /dev/null
+#Kafka Producer/AdminClient properties
+bootstrap.servers=localhost:9092
+acks=all
+retries=3
+max.in.flight.requests.per.connection=1
+batch.size=16384
+linger.ms=1
+buffer.memory=33554432
--- /dev/null
+#Kafka Consumer properties
+bootstrap.servers=localhost:9092
+enable.auto.commit=true
+auto.commit.interval.ms=1000
+auto.offset.reset=earliest
<module>pce</module>
<module>servicehandler</module>
<module>tapi</module>
+ <module>nbinotifications</module>
+ <module>dmaap-client</module>
<module>features</module>
<module>karaf</module>
</modules>
import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev190531.service.delete.input.ServiceDeleteReqInfo.TailRetention;
import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev190531.service.delete.input.ServiceDeleteReqInfoBuilder;
import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev190531.service.list.Services;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.PublishNotificationService;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.PublishNotificationServiceBuilder;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.notification.service.ServiceAEndBuilder;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.notification.service.ServiceZEndBuilder;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.DateAndTime;
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.slf4j.Logger;
private PceListenerImpl pceListenerImpl;
private RendererListenerImpl rendererListenerImpl;
private NetworkModelListenerImpl networkModelListenerImpl;
+ private NotificationPublishService notificationPublishService;
+ private final String topic;
//TODO: remove private request fields as they are in global scope
public ServicehandlerImpl(DataBroker databroker, PathComputationService pathComputationService,
RendererServiceOperations rendererServiceOperations, NotificationPublishService notificationPublishService,
PceListenerImpl pceListenerImpl, RendererListenerImpl rendererListenerImpl,
- NetworkModelListenerImpl networkModelListenerImpl, ServiceDataStoreOperations serviceDataStoreOperations) {
+ NetworkModelListenerImpl networkModelListenerImpl, ServiceDataStoreOperations serviceDataStoreOperations,
+ String topic) {
this.db = databroker;
this.serviceDataStoreOperations = serviceDataStoreOperations;
this.pceServiceWrapper = new PCEServiceWrapper(pathComputationService, notificationPublishService);
this.pceListenerImpl = pceListenerImpl;
this.rendererListenerImpl = rendererListenerImpl;
this.networkModelListenerImpl = networkModelListenerImpl;
+ this.notificationPublishService = notificationPublishService;
+ this.topic = topic;
}
input, ResponseCodes.FINAL_ACK_YES,
validationResult.getResultMessage(), ResponseCodes.RESPONSE_FAILED);
}
+ PublishNotificationService nbiNotification = new PublishNotificationServiceBuilder()
+ .setServiceName(input.getServiceName())
+ .setServiceAEnd(new ServiceAEndBuilder(input.getServiceAEnd()).build())
+ .setServiceZEnd(new ServiceZEndBuilder(input.getServiceZEnd()).build())
+ .setCommonId(input.getCommonId()).setConnectionType(input.getConnectionType())
+ .setResponseFailed("")
+ .setMessage("ServiceCreate request received ...")
+ .setOperationalState(State.OutOfService)
+ .setTopic(topic)
+ .build();
+ sendNbiNotification(nbiNotification);
this.pceListenerImpl.setInput(new ServiceInput(input));
this.pceListenerImpl.setServiceReconfigure(false);
this.pceListenerImpl.setserviceDataStoreOperations(this.serviceDataStoreOperations);
PathComputationRequestOutput output = this.pceServiceWrapper.performPCE(input, true);
if (output == null) {
LOG.warn(SERVICE_CREATE_MSG, LogMessages.ABORT_PCE_FAILED);
+ nbiNotification = new PublishNotificationServiceBuilder(nbiNotification)
+ .setResponseFailed(LogMessages.ABORT_PCE_FAILED)
+ .setMessage("ServiceCreate request failed ...")
+ .setOperationalState(State.Degraded)
+ .build();
+ sendNbiNotification(nbiNotification);
return ModelMappingUtils.createCreateServiceReply(input, ResponseCodes.FINAL_ACK_YES,
LogMessages.PCE_FAILED, ResponseCodes.RESPONSE_FAILED);
}
LogMessages.serviceNotInDS(serviceName), ResponseCodes.RESPONSE_FAILED);
}
service = serviceOpt.get();
+ PublishNotificationService nbiNotification = new PublishNotificationServiceBuilder()
+ .setServiceName(service.getServiceName())
+ .setServiceAEnd(new ServiceAEndBuilder(service.getServiceAEnd()).build())
+ .setServiceZEnd(new ServiceZEndBuilder(service.getServiceZEnd()).build())
+ .setCommonId(service.getCommonId()).setConnectionType(service.getConnectionType())
+ .setMessage("ServiceDelete request received ...")
+ .setOperationalState(State.OutOfService)
+ .setResponseFailed("")
+ .setTopic(topic)
+ .build();
+ sendNbiNotification(nbiNotification);
LOG.debug("serviceDelete: Service '{}' found in datastore", serviceName);
this.pceListenerImpl.setInput(new ServiceInput(input));
this.pceListenerImpl.setServiceReconfigure(false);
if (output == null) {
LOG.error(SERVICE_DELETE_MSG, LogMessages.RENDERER_DELETE_FAILED);
+ nbiNotification = new PublishNotificationServiceBuilder(nbiNotification)
+ .setMessage("ServiceCreate request failed ...")
+ .setOperationalState(State.OutOfService)
+ .setResponseFailed(LogMessages.ABORT_PCE_FAILED)
+ .build();
+ sendNbiNotification(nbiNotification);
return ModelMappingUtils.createDeleteServiceReply(
input, ResponseCodes.FINAL_ACK_YES,
LogMessages.RENDERER_DELETE_FAILED, ResponseCodes.RESPONSE_FAILED);
return null;
}
+ /**
+ * Send notification to NBI notification in order to publish message.
+ * @param service PublishNotificationService
+ */
+ private void sendNbiNotification(PublishNotificationService service) {
+ try {
+ notificationPublishService.putNotification(service);
+ } catch (InterruptedException e) {
+ LOG.warn("Cannot send notification to nbi", e);
+ Thread.currentThread().interrupt();
+ }
+ }
}
private NetworkModelListenerImpl networkModelListenerImpl;
private ServicehandlerImpl servicehandler;
-
public ServicehandlerProvider(final DataBroker dataBroker, RpcProviderService rpcProviderService,
NotificationService notificationService, ServiceDataStoreOperations serviceDataStoreOperations,
PceListenerImpl pceListenerImpl, RendererListenerImpl rendererListenerImpl,
import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev200128.service.path.rpc.result.PathDescription;
import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev200128.service.path.rpc.result.PathDescriptionBuilder;
import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev201125.ServiceImplementationRequestInput;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.common.state.types.rev181130.State;
import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev200128.RpcStatusEx;
import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev200128.response.parameters.sp.ResponseParameters;
import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev200128.response.parameters.sp.ResponseParametersBuilder;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.PublishNotificationService;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.PublishNotificationServiceBuilder;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.notification.service.ServiceAEndBuilder;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.notification.service.ServiceZEndBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class PceListenerImpl implements TransportpcePceListener {
private static final Logger LOG = LoggerFactory.getLogger(PceListenerImpl.class);
+ private static final String TOPIC = "PceListener";
private ServicePathRpcResult servicePathRpcResult;
private RendererServiceOperations rendererServiceOperations;
private Boolean serviceReconfigure;
private Boolean tempService;
private Boolean serviceFeasiblity;
+ private NotificationPublishService notificationPublishService;
public PceListenerImpl(RendererServiceOperations rendererServiceOperations,
PathComputationService pathComputationService, NotificationPublishService notificationPublishService,
setInput(null);
setTempService(false);
setServiceFeasiblity(false);
+ this.notificationPublishService = notificationPublishService;
}
@Override
* @param notification the result notification.
*/
private void onPathComputationResult(ServicePathRpcResult notification) {
- LOG.info("PCE '{}' Notification received : {}",servicePathRpcResult.getNotificationType().getName(),
+ LOG.info("PCE '{}' Notification received : {}", servicePathRpcResult.getNotificationType().getName(),
notification);
- if (servicePathRpcResult.getStatus() == RpcStatusEx.Failed) {
- LOG.error("PCE path computation failed !");
- return;
- } else if (servicePathRpcResult.getStatus() == RpcStatusEx.Pending) {
- LOG.warn("PCE path computation returned a Penging RpcStatusEx code!");
- return;
- } else if (servicePathRpcResult.getStatus() != RpcStatusEx.Successful) {
- LOG.error("PCE path computation returned an unknown RpcStatusEx code!");
+ if (!checkStatus(notification)) {
return;
}
-
- LOG.info("PCE calculation done OK !");
if (servicePathRpcResult.getPathDescription() == null) {
LOG.error("'PathDescription' parameter is null ");
return;
}
}
ResponseParameters responseParameters = new ResponseParametersBuilder()
- .setPathDescription(new org.opendaylight.yang.gen.v1.http.org
- .transportpce.b.c._interface.service.types.rev200128
- .response.parameters.sp.response.parameters
- .PathDescriptionBuilder(pathDescription).build())
+ .setPathDescription(new org.opendaylight.yang.gen.v1.http
+ .org.transportpce.b.c._interface.service.types.rev200128
+ .response.parameters.sp.response.parameters.PathDescriptionBuilder(pathDescription).build())
.build();
PathComputationRequestOutput pceResponse = new PathComputationRequestOutputBuilder()
.setResponseParameters(responseParameters).build();
this.rendererServiceOperations.serviceImplementation(serviceImplementationRequest);
}
+ /**
+ * Check status of notification and send nbi notification.
+ * @param notification ServicePathRpcResult the notification to check.
+ * @return true is status is Successful, false otherwise.
+ */
+ private boolean checkStatus(ServicePathRpcResult notification) {
+ PublishNotificationService nbiNotification = getPublishNotificationService(notification);
+ PublishNotificationServiceBuilder publishNotificationServiceBuilder = new PublishNotificationServiceBuilder(
+ nbiNotification);
+ switch (servicePathRpcResult.getStatus()) {
+ case Failed:
+ LOG.error("PCE path computation failed !");
+ nbiNotification = publishNotificationServiceBuilder.setMessage("ServiceCreate request failed ...")
+ .setResponseFailed("PCE path computation failed !")
+ .setOperationalState(State.Degraded).build();
+ sendNbiNotification(nbiNotification);
+ return false;
+ case Pending:
+ LOG.warn("PCE path computation returned a Penging RpcStatusEx code!");
+ return false;
+ case Successful:
+ LOG.info("PCE calculation done OK !");
+ nbiNotification = publishNotificationServiceBuilder.setMessage("PCE calculation done OK !")
+ .setResponseFailed("").setOperationalState(State.OutOfService).build();
+ sendNbiNotification(nbiNotification);
+ return true;
+ default:
+ LOG.error("PCE path computation returned an unknown RpcStatusEx code {}",
+ servicePathRpcResult.getStatus());
+ nbiNotification = publishNotificationServiceBuilder.setMessage("ServiceCreate request failed ...")
+ .setResponseFailed("PCE path computation returned an unknown RpcStatusEx code!")
+ .setOperationalState(State.Degraded).build();
+ sendNbiNotification(nbiNotification);
+ return false;
+ }
+ }
+
+ private PublishNotificationService getPublishNotificationService(ServicePathRpcResult notification) {
+ PublishNotificationServiceBuilder nbiNotificationBuilder = new PublishNotificationServiceBuilder();
+ if (input != null) {
+ nbiNotificationBuilder.setServiceName(input.getServiceName())
+ .setServiceAEnd(new ServiceAEndBuilder(input.getServiceAEnd()).build())
+ .setServiceZEnd(new ServiceZEndBuilder(input.getServiceZEnd()).build())
+ .setCommonId(input.getCommonId()).setConnectionType(input.getConnectionType());
+ } else {
+ nbiNotificationBuilder.setServiceName(notification.getServiceName());
+ }
+ nbiNotificationBuilder.setTopic(TOPIC);
+ return nbiNotificationBuilder.build();
+ }
+
/**
* Process cancel resource result.
*/
this.serviceFeasiblity = serviceFeasiblity;
}
+ /**
+ * Send notification to NBI notification in order to publish message.
+ * @param service PublishNotificationService
+ */
+ private void sendNbiNotification(PublishNotificationService service) {
+ try {
+ notificationPublishService.putNotification(service);
+ } catch (InterruptedException e) {
+ LOG.warn("Cannot send notification to nbi", e);
+ Thread.currentThread().interrupt();
+ }
+ }
}
import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev190531.ServiceNotificationTypes;
import org.opendaylight.yang.gen.v1.http.org.openroadm.common.state.types.rev181130.State;
import org.opendaylight.yang.gen.v1.http.org.openroadm.equipment.states.types.rev181130.AdminStates;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev190531.service.list.Services;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.PublishNotificationService;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.PublishNotificationServiceBuilder;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.notification.service.ServiceAEndBuilder;
+import org.opendaylight.yang.gen.v1.nbi.notifications.rev201130.notification.service.ServiceZEndBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
*/
public class RendererListenerImpl implements TransportpceRendererListener {
+ private static final String TOPIC = "RendererListener";
private static final Logger LOG = LoggerFactory.getLogger(RendererListenerImpl.class);
private RendererRpcResultSp serviceRpcResultSp;
private ServiceDataStoreOperations serviceDataStoreOperations;
LOG.error("Renderer service delete returned an unknown RpcStatusEx code!");
return;
}
+ Services service = serviceDataStoreOperations.getService(notification.getServiceName()).get();
+ PublishNotificationService nbiNotification = new PublishNotificationServiceBuilder()
+ .setServiceName(service.getServiceName())
+ .setServiceAEnd(new ServiceAEndBuilder(service.getServiceAEnd()).build())
+ .setServiceZEnd(new ServiceZEndBuilder(service.getServiceZEnd()).build())
+ .setCommonId(service.getCommonId())
+ .setConnectionType(service.getConnectionType())
+ .setResponseFailed("")
+ .setMessage("Service deleted !")
+ .setOperationalState(org.opendaylight.yang.gen.v1.http
+ .org.openroadm.common.state.types.rev181130.State.Degraded)
+ .setTopic(TOPIC)
+ .build();
+ sendNbiNotification(nbiNotification);
+ LOG.info("Service '{}' deleted !", notification.getServiceName());
if (this.input == null) {
LOG.error("ServiceInput parameter is null !");
return;
*/
private void onSuccededServiceImplementation(RendererRpcResultSp notification) {
LOG.info("Service implemented !");
+ PublishNotificationService nbiNotification = new PublishNotificationServiceBuilder()
+ .setServiceName(input.getServiceName())
+ .setServiceAEnd(new ServiceAEndBuilder(input.getServiceAEnd()).build())
+ .setServiceZEnd(new ServiceZEndBuilder(input.getServiceZEnd()).build())
+ .setCommonId(input.getCommonId()).setConnectionType(input.getConnectionType())
+ .setResponseFailed("")
+ .setMessage("Service implemented !")
+ .setOperationalState(org.opendaylight.yang.gen.v1.http
+ .org.openroadm.common.state.types.rev181130.State.InService)
+ .setTopic(TOPIC)
+ .build();
+ sendNbiNotification(nbiNotification);
if (serviceDataStoreOperations == null) {
LOG.debug("serviceDataStoreOperations is null");
return;
}
} else {
operationResult = this.serviceDataStoreOperations.modifyService(
- serviceRpcResultSp.getServiceName(),
- State.InService,
- AdminStates.InService);
+ serviceRpcResultSp.getServiceName(), State.InService, AdminStates.InService);
if (!operationResult.isSuccess()) {
LOG.warn("Service status not updated in datastore !");
} else {
public void setTempService(Boolean tempService) {
this.tempService = tempService;
}
+
+ /**
+ * Send notification to NBI notification in order to publish message.
+ * @param service PublishNotificationService
+ */
+ private void sendNbiNotification(PublishNotificationService service) {
+ try {
+ notificationPublishService.putNotification(service);
+ } catch (InterruptedException e) {
+ LOG.warn("Cannot send notification to nbi", e);
+ Thread.currentThread().interrupt();
+ }
+ }
}
<argument ref="rendererListener" />
<argument ref="networkModelListener" />
<argument ref="serviceDatastoreOperation" />
+ <argument value="ServiceHandler" />
</bean>
<bean id="provider"
ServicehandlerImpl servicehandlerImpl =
new ServicehandlerImpl(getNewDataBroker(), pathComputationService, rendererServiceOperations,
notificationPublishService, pceListenerImpl, rendererListenerImpl, networkModelListenerImpl,
- serviceDataStoreOperations);
+ serviceDataStoreOperations, "ServiceHandler");
ListenableFuture<RpcResult<ServiceCreateOutput>> result =
servicehandlerImpl.serviceCreate(new ServiceCreateInputBuilder().build());
result.addListener(new Runnable() {
ServicehandlerImpl servicehandlerImpl =
new ServicehandlerImpl(getNewDataBroker(), pathComputationService, rendererServiceOperations,
notificationPublishService, pceListenerImpl, rendererListenerImpl, networkModelListenerImpl,
- serviceDataStoreOperations);
+ serviceDataStoreOperations, "ServiceHandler");
ListenableFuture<RpcResult<ServiceCreateOutput>> result = servicehandlerImpl.serviceCreate(input);
result.addListener(new Runnable() {
@Override
ServicehandlerImpl servicehandlerImpl =
new ServicehandlerImpl(getNewDataBroker(), pathComputationService, rendererServiceOperations,
notificationPublishService, pceListenerImpl, rendererListenerImpl, networkModelListenerImpl,
- serviceDataStoreOperations);
+ serviceDataStoreOperations, "ServiceHandler");
ListenableFuture<RpcResult<ServiceDeleteOutput>> result =
servicehandlerImpl.serviceDelete(new ServiceDeleteInputBuilder()
.setServiceDeleteReqInfo(new ServiceDeleteReqInfoBuilder().setServiceName("").build()).build());
ServicehandlerImpl servicehandlerImpl =
new ServicehandlerImpl(getNewDataBroker(), pathComputationService, rendererServiceOperations,
notificationPublishService, pceListenerImpl, rendererListenerImpl, networkModelListenerImpl,
- serviceDataStoreOperations);
+ serviceDataStoreOperations, "ServiceHandler");
ListenableFuture<RpcResult<ServiceDeleteOutput>> result = servicehandlerImpl.serviceDelete(input);
result.addListener(new Runnable() {
@Override
ServicehandlerImpl servicehandlerImpl =
new ServicehandlerImpl(dataBroker, pathComputationService, rendererServiceOperations,
notificationPublishService, pceListenerImpl, rendererListenerImpl, networkModelListenerImpl,
- serviceDataStoreOperations);
+ serviceDataStoreOperations, "ServiceHandler");
ServiceCreateInput createInput = ServiceDataUtils.buildServiceCreateInput();
serviceDataStoreOperations.createService(createInput);
ServiceDeleteInput input = ServiceDataUtils.buildServiceDeleteInput();
ServicehandlerImpl servicehandlerImpl =
new ServicehandlerImpl(getNewDataBroker(), pathComputationService, rendererServiceOperations,
notificationPublishService, pceListenerImpl, rendererListenerImpl, networkModelListenerImpl,
- serviceDataStoreOperations);
+ serviceDataStoreOperations, "ServiceHandler");
ListenableFuture<RpcResult<ServiceFeasibilityCheckOutput>> result =
servicehandlerImpl.serviceFeasibilityCheck(new ServiceFeasibilityCheckInputBuilder().build());
result.addListener(new Runnable() {
ServicehandlerImpl servicehandlerImpl =
new ServicehandlerImpl(getNewDataBroker(), pathComputationService, rendererServiceOperations,
notificationPublishService, pceListenerImpl, rendererListenerImpl, networkModelListenerImpl,
- serviceDataStoreOperations);
+ serviceDataStoreOperations, "ServiceHandler");
ListenableFuture<RpcResult<ServiceFeasibilityCheckOutput>> result =
servicehandlerImpl.serviceFeasibilityCheck(input);
result.addListener(new Runnable() {
ServicehandlerImpl servicehandlerImpl =
new ServicehandlerImpl(getNewDataBroker(), pathComputationService, rendererServiceOperations,
notificationPublishService, pceListenerImpl, rendererListenerImpl, networkModelListenerImpl,
- serviceDataStoreOperations);
+ serviceDataStoreOperations, "ServiceHandler");
ListenableFuture<RpcResult<ServiceReconfigureOutput>> result =
servicehandlerImpl.serviceReconfigure(new ServiceReconfigureInputBuilder().setServiceName("").build());
result.addListener(new Runnable() {
ServicehandlerImpl servicehandlerImpl =
new ServicehandlerImpl(getNewDataBroker(), pathComputationService, rendererServiceOperations,
notificationPublishService, pceListenerImpl, rendererListenerImpl, networkModelListenerImpl,
- serviceDataStoreOperations);
+ serviceDataStoreOperations, "ServiceHandler");
ListenableFuture<RpcResult<ServiceReconfigureOutput>> result = servicehandlerImpl.serviceReconfigure(input);
result.addListener(new Runnable() {
ServicehandlerImpl servicehandlerImpl =
new ServicehandlerImpl(dataBroker, pathComputationService, rendererServiceOperations,
notificationPublishService, pceListenerImpl, rendererListenerImpl, networkModelListenerImpl,
- serviceDataStoreOperations);
+ serviceDataStoreOperations, "ServiceHandler");
ServiceCreateInput createInput = ServiceDataUtils.buildServiceCreateInput();
serviceDataStoreOperations.createService(createInput);
ServicehandlerImpl servicehandlerImpl =
new ServicehandlerImpl(getNewDataBroker(), pathComputationService, rendererServiceOperations,
notificationPublishService, pceListenerImpl, rendererListenerImpl, networkModelListenerImpl,
- serviceDataStoreOperations);
+ serviceDataStoreOperations, "ServiceHandler");
ListenableFuture<RpcResult<ServiceRestorationOutput>> result =
servicehandlerImpl.serviceRestoration(new ServiceRestorationInputBuilder().setServiceName("").build());
result.addListener(new Runnable() {
ServicehandlerImpl servicehandlerImpl =
new ServicehandlerImpl(getNewDataBroker(), pathComputationService, rendererServiceOperations,
notificationPublishService, pceListenerImpl, rendererListenerImpl, networkModelListenerImpl,
- serviceDataStoreOperations);
+ serviceDataStoreOperations, "ServiceHandler");
ListenableFuture<RpcResult<ServiceRestorationOutput>> result = servicehandlerImpl.serviceRestoration(input);
result.addListener(new Runnable() {
ServicehandlerImpl servicehandlerImpl =
new ServicehandlerImpl(dataBroker, pathComputationService, rendererServiceOperations,
notificationPublishService, pceListenerImpl, rendererListenerImpl, networkModelListenerImpl,
- serviceDataStoreOperations);
+ serviceDataStoreOperations, "ServiceHandler");
ServiceCreateInput createInput = ServiceDataUtils.buildServiceCreateInput();
serviceDataStoreOperations.createService(createInput);
ServicehandlerImpl servicehandlerImpl =
new ServicehandlerImpl(getNewDataBroker(), pathComputationService, rendererServiceOperations,
notificationPublishService, pceListenerImpl, rendererListenerImpl, networkModelListenerImpl,
- serviceDataStoreOperations);
+ serviceDataStoreOperations, "ServiceHandler");
ListenableFuture<RpcResult<ServiceRerouteOutput>> result =
servicehandlerImpl.serviceReroute(new ServiceRerouteInputBuilder().setServiceName("").build());
result.addListener(new Runnable() {
ServicehandlerImpl servicehandlerImpl =
new ServicehandlerImpl(getNewDataBroker(), pathComputationService, rendererServiceOperations,
notificationPublishService, pceListenerImpl, rendererListenerImpl, networkModelListenerImpl,
- serviceDataStoreOperations);
+ serviceDataStoreOperations, "ServiceHandler");
ListenableFuture<RpcResult<ServiceRerouteOutput>> result = servicehandlerImpl.serviceReroute(input);
result.addListener(new Runnable() {
ServicehandlerImpl servicehandlerImpl =
new ServicehandlerImpl(dataBroker, pathComputationService, rendererServiceOperations,
notificationPublishService, pceListenerImpl, rendererListenerImpl, networkModelListenerImpl,
- serviceDataStoreOperations);
+ serviceDataStoreOperations, "ServiceHandler");
ServiceCreateInput createInput = ServiceDataUtils.buildServiceCreateInput();
serviceDataStoreOperations.createService(createInput);
ServicehandlerImpl servicehandlerImpl =
new ServicehandlerImpl(getNewDataBroker(), pathComputationService, rendererServiceOperations,
notificationPublishService, pceListenerImpl, rendererListenerImpl, networkModelListenerImpl,
- serviceDataStoreOperations);
+ serviceDataStoreOperations, "ServiceHandler");
ListenableFuture<RpcResult<TempServiceDeleteOutput>> result =
servicehandlerImpl.tempServiceDelete(new TempServiceDeleteInputBuilder()
.setCommonId("").build());
ServicehandlerImpl servicehandlerImpl =
new ServicehandlerImpl(getNewDataBroker(), pathComputationService, rendererServiceOperations,
notificationPublishService, pceListenerImpl, rendererListenerImpl, networkModelListenerImpl,
- serviceDataStoreOperations);
+ serviceDataStoreOperations, "ServiceHandler");
ListenableFuture<RpcResult<TempServiceDeleteOutput>> result = servicehandlerImpl.tempServiceDelete(input);
result.addListener(new Runnable() {
@Override
ServicehandlerImpl servicehandlerImpl =
new ServicehandlerImpl(dataBroker, pathComputationService, rendererServiceOperations,
notificationPublishService, pceListenerImpl, rendererListenerImpl, networkModelListenerImpl,
- serviceDataStoreOperations);
+ serviceDataStoreOperations, "ServiceHandler");
TempServiceCreateInput createInput = ServiceDataUtils.buildTempServiceCreateInput();
serviceDataStoreOperations.createTempService(createInput);
ServicehandlerImpl servicehandlerImpl =
new ServicehandlerImpl(getNewDataBroker(), pathComputationService, rendererServiceOperations,
notificationPublishService, pceListenerImpl, rendererListenerImpl, networkModelListenerImpl,
- serviceDataStoreOperations);
+ serviceDataStoreOperations, "ServiceHandler");
ListenableFuture<RpcResult<TempServiceCreateOutput>> result =
servicehandlerImpl.tempServiceCreate(new TempServiceCreateInputBuilder().build());
result.addListener(new Runnable() {
ServicehandlerImpl servicehandlerImpl =
new ServicehandlerImpl(getNewDataBroker(), pathComputationService, rendererServiceOperations,
notificationPublishService, pceListenerImpl, rendererListenerImpl, networkModelListenerImpl,
- serviceDataStoreOperations);
+ serviceDataStoreOperations, "ServiceHandler");
ListenableFuture<RpcResult<TempServiceCreateOutput>> result = servicehandlerImpl.tempServiceCreate(input);
result.addListener(new Runnable() {
--- /dev/null
+version: '2'
+services:
+ zookeeper:
+ image: wurstmeister/zookeeper
+ container_name: nbinotifications_zookeeper
+ ports:
+ - "2181:2181"
+ kafka:
+ image: wurstmeister/kafka
+ container_name: nbinotifications_kafka
+ ports:
+ - "9092:9092"
+ environment:
+ KAFKA_ADVERTISED_HOST_NAME: localhost
+ KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
\ No newline at end of file
--- /dev/null
+#!/usr/bin/env python
+##############################################################################
+# Copyright (c) 2020 Orange, Inc. and others. All rights reserved.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+
+# pylint: disable=no-member
+# pylint: disable=too-many-public-methods
+
+import os
+import sys
+import unittest
+import time
+import requests
+from common import test_utils
+
+
+class TransportNbiNotificationstesting(unittest.TestCase):
+ processes = None
+ cr_serv_sample_data = {"input": {
+ "sdnc-request-header": {
+ "request-id": "e3028bae-a90f-4ddd-a83f-cf224eba0e58",
+ "rpc-action": "service-create",
+ "request-system-id": "appname",
+ "notification-url": "http://localhost:8585/NotificationServer/notify"
+ },
+ "service-name": "service1",
+ "common-id": "ASATT1234567",
+ "connection-type": "service",
+ "service-a-end": {
+ "service-rate": "100",
+ "node-id": "XPDR-A1",
+ "service-format": "Ethernet",
+ "clli": "SNJSCAMCJP8",
+ "tx-direction": {
+ "port": {
+ "port-device-name": "ROUTER_SNJSCAMCJP8_000000.00_00",
+ "port-type": "router",
+ "port-name": "Gigabit Ethernet_Tx.ge-5/0/0.0",
+ "port-rack": "000000.00",
+ "port-shelf": "00"
+ },
+ "lgx": {
+ "lgx-device-name": "LGX Panel_SNJSCAMCJP8_000000.00_00",
+ "lgx-port-name": "LGX Back.3",
+ "lgx-port-rack": "000000.00",
+ "lgx-port-shelf": "00"
+ }
+ },
+ "rx-direction": {
+ "port": {
+ "port-device-name": "ROUTER_SNJSCAMCJP8_000000.00_00",
+ "port-type": "router",
+ "port-name": "Gigabit Ethernet_Rx.ge-5/0/0.0",
+ "port-rack": "000000.00",
+ "port-shelf": "00"
+ },
+ "lgx": {
+ "lgx-device-name": "LGX Panel_SNJSCAMCJP8_000000.00_00",
+ "lgx-port-name": "LGX Back.4",
+ "lgx-port-rack": "000000.00",
+ "lgx-port-shelf": "00"
+ }
+ },
+ "optic-type": "gray"
+ },
+ "service-z-end": {
+ "service-rate": "100",
+ "node-id": "XPDR-C1",
+ "service-format": "Ethernet",
+ "clli": "SNJSCAMCJT4",
+ "tx-direction": {
+ "port": {
+ "port-device-name": "ROUTER_SNJSCAMCJT4_000000.00_00",
+ "port-type": "router",
+ "port-name": "Gigabit Ethernet_Tx.ge-1/0/0.0",
+ "port-rack": "000000.00",
+ "port-shelf": "00"
+ },
+ "lgx": {
+ "lgx-device-name": "LGX Panel_SNJSCAMCJT4_000000.00_00",
+ "lgx-port-name": "LGX Back.29",
+ "lgx-port-rack": "000000.00",
+ "lgx-port-shelf": "00"
+ }
+ },
+ "rx-direction": {
+ "port": {
+ "port-device-name": "ROUTER_SNJSCAMCJT4_000000.00_00",
+ "port-type": "router",
+ "port-name": "Gigabit Ethernet_Rx.ge-1/0/0.0",
+ "port-rack": "000000.00",
+ "port-shelf": "00"
+ },
+ "lgx": {
+ "lgx-device-name": "LGX Panel_SNJSCAMCJT4_000000.00_00",
+ "lgx-port-name": "LGX Back.30",
+ "lgx-port-rack": "000000.00",
+ "lgx-port-shelf": "00"
+ }
+ },
+ "optic-type": "gray"
+ },
+ "due-date": "2016-11-28T00:00:01Z",
+ "operator-contact": "pw1234"
+ }
+ }
+
+ WAITING = 20 # nominal value is 300
+
+ @classmethod
+ def setUpClass(cls):
+ # TODO: for lighty manage the activation of NBI notification feature
+ cls.processes = test_utils.start_tpce()
+ # NBI notification feature is not installed by default in Karaf
+ if "USE_LIGHTY" not in os.environ or os.environ['USE_LIGHTY'] != 'True':
+ print("installing NBI notification feature...")
+ result = test_utils.install_karaf_feature("odl-transportpce-nbinotifications")
+ if result.returncode != 0:
+ cls.init_failed = True
+ print("Restarting OpenDaylight...")
+ test_utils.shutdown_process(cls.processes[0])
+ cls.processes[0] = test_utils.start_karaf()
+ test_utils.process_list[0] = cls.processes[0]
+ cls.init_failed = not test_utils.wait_until_log_contains(
+ test_utils.KARAF_LOG, test_utils.KARAF_OK_START_MSG, time_to_wait=60)
+ if cls.init_failed:
+ print("NBI notification installation feature failed...")
+ test_utils.shutdown_process(cls.processes[0])
+ sys.exit(2)
+ cls.processes = test_utils.start_sims(['xpdra', 'roadma', 'roadmc', 'xpdrc'])
+
+ @classmethod
+ def tearDownClass(cls):
+ # pylint: disable=not-an-iterable
+ for process in cls.processes:
+ test_utils.shutdown_process(process)
+ print("all processes killed")
+
+ def setUp(self): # instruction executed before each test method
+ print("execution of {}".format(self.id().split(".")[-1]))
+
+ def test_01_connect_xpdrA(self):
+ response = test_utils.mount_device("XPDR-A1", 'xpdra')
+ self.assertEqual(response.status_code, requests.codes.created, test_utils.CODE_SHOULD_BE_201)
+
+ def test_02_connect_xpdrC(self):
+ response = test_utils.mount_device("XPDR-C1", 'xpdrc')
+ self.assertEqual(response.status_code, requests.codes.created, test_utils.CODE_SHOULD_BE_201)
+
+ def test_03_connect_rdmA(self):
+ response = test_utils.mount_device("ROADM-A1", 'roadma')
+ self.assertEqual(response.status_code, requests.codes.created, test_utils.CODE_SHOULD_BE_201)
+
+ def test_04_connect_rdmC(self):
+ response = test_utils.mount_device("ROADM-C1", 'roadmc')
+ self.assertEqual(response.status_code, requests.codes.created, test_utils.CODE_SHOULD_BE_201)
+
+ def test_05_connect_xprdA_N1_to_roadmA_PP1(self):
+ response = test_utils.connect_xpdr_to_rdm_request("XPDR-A1", "1", "1",
+ "ROADM-A1", "1", "SRG1-PP1-TXRX")
+ self.assertEqual(response.status_code, requests.codes.ok)
+ res = response.json()
+ self.assertIn('Xponder Roadm Link created successfully', res["output"]["result"])
+ time.sleep(2)
+
+ def test_06_connect_roadmA_PP1_to_xpdrA_N1(self):
+ response = test_utils.connect_rdm_to_xpdr_request("XPDR-A1", "1", "1",
+ "ROADM-A1", "1", "SRG1-PP1-TXRX")
+ self.assertEqual(response.status_code, requests.codes.ok)
+ res = response.json()
+ self.assertIn('Roadm Xponder links created successfully', res["output"]["result"])
+ time.sleep(2)
+
+ def test_07_connect_xprdC_N1_to_roadmC_PP1(self):
+ response = test_utils.connect_xpdr_to_rdm_request("XPDR-C1", "1", "1",
+ "ROADM-C1", "1", "SRG1-PP1-TXRX")
+ self.assertEqual(response.status_code, requests.codes.ok)
+ res = response.json()
+ self.assertIn('Xponder Roadm Link created successfully', res["output"]["result"])
+ time.sleep(2)
+
+ def test_08_connect_roadmC_PP1_to_xpdrC_N1(self):
+ response = test_utils.connect_rdm_to_xpdr_request("XPDR-C1", "1", "1",
+ "ROADM-C1", "1", "SRG1-PP1-TXRX")
+ self.assertEqual(response.status_code, requests.codes.ok)
+ res = response.json()
+ self.assertIn('Roadm Xponder links created successfully', res["output"]["result"])
+ time.sleep(2)
+
+ def test_09_get_notifications_service1(self):
+ data = {
+ "input": {
+ "connection-type": "service",
+ "id-consumer": "consumer",
+ "group-id": "transportpceTest"
+ }
+ }
+ response = test_utils.get_notifications_service_request(data)
+ self.assertEqual(response.status_code, requests.codes.no_content)
+ time.sleep(2)
+
+ def test_10_create_eth_service1(self):
+ self.cr_serv_sample_data["input"]["service-name"] = "service1"
+ response = test_utils.service_create_request(self.cr_serv_sample_data)
+ self.assertEqual(response.status_code, requests.codes.ok)
+ res = response.json()
+ self.assertIn('PCE calculation in progress',
+ res['output']['configuration-response-common']['response-message'])
+ time.sleep(self.WAITING)
+
+ def test_11_get_notifications_service1(self):
+ data = {
+ "input": {
+ "connection-type": "service",
+ "id-consumer": "consumer",
+ "group-id": "transportpceTest"
+ }
+ }
+ response = test_utils.get_notifications_service_request(data)
+ self.assertEqual(response.status_code, requests.codes.ok)
+ res = response.json()
+ self.assertEqual(res['output']['notification-service'][-2]['service-name'], 'service1')
+ self.assertEqual(res['output']['notification-service'][-2]['connection-type'], 'service')
+ self.assertEqual(res['output']['notification-service'][-2]['message'], 'ServiceCreate request received ...')
+ self.assertEqual(res['output']['notification-service'][-1]['service-name'], 'service1')
+ self.assertEqual(res['output']['notification-service'][-1]['message'], 'ServiceCreate request failed ...')
+ self.assertEqual(res['output']['notification-service'][-1]['response-failed'],
+ 'PCE path computation failed !')
+ time.sleep(2)
+
+ def test_12_add_omsAttributes_ROADMA_ROADMC(self):
+ # Config ROADMA-ROADMC oms-attributes
+ data = {"span": {
+ "auto-spanloss": "true",
+ "spanloss-base": 11.4,
+ "spanloss-current": 12,
+ "engineered-spanloss": 12.2,
+ "link-concatenation": [{
+ "SRLG-Id": 0,
+ "fiber-type": "smf",
+ "SRLG-length": 100000,
+ "pmd": 0.5}]}}
+ response = test_utils.add_oms_attr_request("ROADM-A1-DEG2-DEG2-TTP-TXRXtoROADM-C1-DEG1-DEG1-TTP-TXRX", data)
+ self.assertEqual(response.status_code, requests.codes.created)
+
+ def test_13_add_omsAttributes_ROADMC_ROADMA(self):
+ # Config ROADMC-ROADMA oms-attributes
+ data = {"span": {
+ "auto-spanloss": "true",
+ "spanloss-base": 11.4,
+ "spanloss-current": 12,
+ "engineered-spanloss": 12.2,
+ "link-concatenation": [{
+ "SRLG-Id": 0,
+ "fiber-type": "smf",
+ "SRLG-length": 100000,
+ "pmd": 0.5}]}}
+ response = test_utils.add_oms_attr_request("ROADM-C1-DEG1-DEG1-TTP-TXRXtoROADM-A1-DEG2-DEG2-TTP-TXRX", data)
+ self.assertEqual(response.status_code, requests.codes.created)
+
+ # test service-create for Eth service from xpdr to xpdr
+ def test_14_create_eth_service1(self):
+ self.cr_serv_sample_data["input"]["service-name"] = "service1"
+ response = test_utils.service_create_request(self.cr_serv_sample_data)
+ self.assertEqual(response.status_code, requests.codes.ok)
+ res = response.json()
+ self.assertIn('PCE calculation in progress',
+ res['output']['configuration-response-common']['response-message'])
+ time.sleep(self.WAITING)
+
+ def test_15_get_eth_service1(self):
+ response = test_utils.get_service_list_request("services/service1")
+ self.assertEqual(response.status_code, requests.codes.ok)
+ res = response.json()
+ self.assertEqual(
+ res['services'][0]['administrative-state'], 'inService')
+ self.assertEqual(
+ res['services'][0]['service-name'], 'service1')
+ self.assertEqual(
+ res['services'][0]['connection-type'], 'service')
+ self.assertEqual(
+ res['services'][0]['lifecycle-state'], 'planned')
+ time.sleep(2)
+
+ def test_16_get_notifications_service1(self):
+ data = {
+ "input": {
+ "connection-type": "service",
+ "id-consumer": "consumer",
+ "group-id": "transportpceTest"
+ }
+ }
+ response = test_utils.get_notifications_service_request(data)
+ self.assertEqual(response.status_code, requests.codes.ok)
+ res = response.json()
+ self.assertEqual(res['output']['notification-service'][-3]['service-name'], 'service1')
+ self.assertEqual(res['output']['notification-service'][-3]['connection-type'], 'service')
+ self.assertEqual(res['output']['notification-service'][-3]['message'], 'ServiceCreate request received ...')
+ self.assertEqual(res['output']['notification-service'][-2]['service-name'], 'service1')
+ self.assertEqual(res['output']['notification-service'][-2]['message'], 'PCE calculation done OK !')
+ self.assertEqual(res['output']['notification-service'][-1]['service-name'], 'service1')
+ self.assertEqual(res['output']['notification-service'][-1]['message'], 'Service implemented !')
+ time.sleep(2)
+
+ def test_17_delete_eth_service1(self):
+ response = test_utils.service_delete_request("service1")
+ self.assertEqual(response.status_code, requests.codes.ok)
+ res = response.json()
+ self.assertIn('Renderer service delete in progress',
+ res['output']['configuration-response-common']['response-message'])
+ time.sleep(20)
+
+ def test_18_get_notifications_service1(self):
+ data = {
+ "input": {
+ "connection-type": "service",
+ "id-consumer": "consumer",
+ "group-id": "transportpceTest"
+ }
+ }
+ response = test_utils.get_notifications_service_request(data)
+ self.assertEqual(response.status_code, requests.codes.ok)
+ res = response.json()
+ self.assertEqual(res['output']['notification-service'][-2]['service-name'], 'service1')
+ self.assertEqual(res['output']['notification-service'][-2]['connection-type'], 'service')
+ self.assertEqual(res['output']['notification-service'][-2]['message'], 'ServiceDelete request received ...')
+ self.assertEqual(res['output']['notification-service'][-1]['service-name'], 'service1')
+ self.assertEqual(res['output']['notification-service'][-1]['message'], 'Service deleted !')
+ time.sleep(2)
+
+ def test_19_disconnect_XPDRA(self):
+ response = test_utils.unmount_device("XPDR-A1")
+ self.assertEqual(response.status_code, requests.codes.ok, test_utils.CODE_SHOULD_BE_200)
+
+ def test_20_disconnect_XPDRC(self):
+ response = test_utils.unmount_device("XPDR-C1")
+ self.assertEqual(response.status_code, requests.codes.ok, test_utils.CODE_SHOULD_BE_200)
+
+ def test_21_disconnect_ROADMA(self):
+ response = test_utils.unmount_device("ROADM-A1")
+ self.assertEqual(response.status_code, requests.codes.ok, test_utils.CODE_SHOULD_BE_200)
+
+ def test_22_disconnect_ROADMC(self):
+ response = test_utils.unmount_device("ROADM-C1")
+ self.assertEqual(response.status_code, requests.codes.ok, test_utils.CODE_SHOULD_BE_200)
+
+
+if __name__ == "__main__":
+ unittest.main(verbosity=2)
URL_CONFIG_ORDM_NET = "{}/config/ietf-network:networks/network/openroadm-network/"
URL_PORTMAPPING = "{}/config/transportpce-portmapping:network/nodes/"
URL_OPER_SERV_LIST = "{}/operational/org-openroadm-service:service-list/"
+URL_GET_NBINOTIFICATIONS_SERV = "{}/operations/nbi-notifications:get-notifications-service/"
URL_SERV_CREATE = "{}/operations/org-openroadm-service:service-create"
URL_SERV_DELETE = "{}/operations/org-openroadm-service:service-delete"
URL_SERVICE_PATH = "{}/operations/transportpce-device-renderer:service-path"
return get_request(url)
+def get_notifications_service_request(attr):
+ return post_request(URL_GET_NBINOTIFICATIONS_SERV, attr)
+
+
def get_service_list_request(suffix: str):
url = URL_OPER_SERV_LIST + suffix
return get_request(url)
#install honeynode 1.2.1 simulators
{py3,portmapping,topoPortMapping,rspn,topology,pce,olm,end2end}: - sh -c "./install_honeynode.sh 1.2.1"
#patch OLM constant to speed up tests, unnecessary for PCE
- {py3,portmapping,topoPortMapping,rspn,topology,olm,end2end,portmapping221,rspn221,otnrenderer,otnshrenderer,topology221,otn-topology,olm221,otnend2end,end2end221,tapi221}: - sh -c "sed -i'_' 's@=.*//#FUNCTESTVAL=@=@g' ../olm/src/main/java/org/opendaylight/transportpce/olm/util/OlmUtils.java"
+ {py3,portmapping,topoPortMapping,rspn,topology,olm,end2end,portmapping221,rspn221,otnrenderer,otnshrenderer,topology221,otn-topology,olm221,otnend2end,end2end221,tapi221,nbinotifications}: - sh -c "sed -i'_' 's@=.*//#FUNCTESTVAL=@=@g' ../olm/src/main/java/org/opendaylight/transportpce/olm/util/OlmUtils.java"
#build controller, source JDK_JAVA_OPTIONS to remove illegal reflective acces warnings introduced by Java11
- {py3,portmapping,topoPortMapping,rspn,topology,pce,olm,end2end,portmapping221,rspn221,otnrenderer,otnshrenderer,topology221,otntopology,flexgrid,olm221,tapi221,otnend2end,end2end221,gnpy}: - sh -c ". $PWD/reflectwarn.sh && cd .. && mvn clean install -s tests/odl_settings.xml -DskipTests -Dmaven.javadoc.skip=true -Dodlparent.spotbugs.skip -Dodlparent.checkstyle.skip"
- {py3,portmapping,topoPortMapping,rspn,topology,olm,end2end,portmapping221,rspn221,otnrenderer,otnshrenderer,topology221,otn-topology,olm221,otnend2end,end2end221,tapi221}: - sh -c "mv ../olm/src/main/java/org/opendaylight/transportpce/olm/util/OlmUtils.java_ ../olm/src/main/java/org/opendaylight/transportpce/olm/util/OlmUtils.java"
+ {py3,portmapping,topoPortMapping,rspn,topology,pce,olm,end2end,portmapping221,rspn221,otnrenderer,otnshrenderer,topology221,otntopology,flexgrid,olm221,tapi221,otnend2end,end2end221,gnpy,nbinotifications}: - sh -c ". $PWD/reflectwarn.sh && cd .. && mvn clean install -s tests/odl_settings.xml -DskipTests -Dmaven.javadoc.skip=true -Dodlparent.spotbugs.skip -Dodlparent.checkstyle.skip"
+ {py3,portmapping,topoPortMapping,rspn,topology,olm,end2end,portmapping221,rspn221,otnrenderer,otnshrenderer,topology221,otn-topology,olm221,otnend2end,end2end221,tapi221,nbinotifications}: - sh -c "mv ../olm/src/main/java/org/opendaylight/transportpce/olm/util/OlmUtils.java_ ../olm/src/main/java/org/opendaylight/transportpce/olm/util/OlmUtils.java"
#patch Karaf exec for the same reason at runtime
- {py3,portmapping,topoPortMapping,rspn,topology,pce,olm,end2end,portmapping221,rspn221,otnrenderer,otnshrenderer,topology221,otntopology,flexgrid,olm221,tapi221,otnend2end,end2end221,gnpy}: - sh -c "sed -i'_' 's@!/bin/sh@!/bin/sh\'$'\n. $(dirname $0)/../../../../tests/reflectwarn.sh@' ../karaf/target/assembly/bin/karaf"
+ {py3,portmapping,topoPortMapping,rspn,topology,pce,olm,end2end,portmapping221,rspn221,otnrenderer,otnshrenderer,topology221,otntopology,flexgrid,olm221,tapi221,otnend2end,end2end221,gnpy,nbinotifications}: - sh -c "sed -i'_' 's@!/bin/sh@!/bin/sh\'$'\n. $(dirname $0)/../../../../tests/reflectwarn.sh@' ../karaf/target/assembly/bin/karaf"
# the following command would be the straight and right way to support both BSD and GNU sed versions
# sh -c "sed -i'_' '1 a\'$'\n. \$(dirname \$0)/\.\./\.\./\.\./\.\./tests/reflectwarn.sh\n' ../karaf/target/assembly/bin/karaf"
# but tox reinterprets the quotes as
# sh -c 'sed -i'"'"'_'"'"' '"'"'1 a\'"'"'$'"'"'\n. \$(dirname \$0)/\.\./\.\./\.\./\.\./tests/reflectwarn.sh\n'"'"' ../karaf/target/assembly/bin/karaf'
# ,what results in an unexpected different formating (with a $ on the second line and the dot on the third)
#build Lighty if needed
- {py3,portmapping,topoPortMapping,rspn,topology,pce,olm,end2end,portmapping221,rspn221,otnrenderer,otnshrenderer,topology221,otntopology,flexgrid,olm221,tapi221,otnend2end,end2end221,gnpy}: - sh -c 'if [ "$USE_LIGHTY" = "True" ]; then (cd ../lighty && ./build.sh); fi'
+ {py3,portmapping,topoPortMapping,rspn,topology,pce,olm,end2end,portmapping221,rspn221,otnrenderer,otnshrenderer,topology221,otntopology,flexgrid,olm221,tapi221,otnend2end,end2end221,gnpy,nbinotifications}: - sh -c 'if [ "$USE_LIGHTY" = "True" ]; then (cd ../lighty && ./build.sh); fi'
#run 1.2.1 functional tests
{py3,portmapping}: nosetests --with-xunit transportpce_tests/1.2.1/test_portmapping.py
{py3,topoPortMapping}: nosetests --with-xunit transportpce_tests/1.2.1/test_topo_portmapping.py
#E2E 1.2.1 moved at the end before 2.2.1 E2E
#run 2.2.1 functional tests
#install honeynode 2.2.1 simulators
- {py3,portmapping221,rspn221,otnrenderer,otnshrenderer,topology221,otntopology,flexgrid,olm221,tapi221,otnend2end,end2end221}: - sh -c "./install_honeynode.sh 2.2.1"
+ {py3,portmapping221,rspn221,otnrenderer,otnshrenderer,topology221,otntopology,flexgrid,olm221,tapi221,otnend2end,end2end221,nbinotifications}: - sh -c "./install_honeynode.sh 2.2.1"
{py3,portmapping221}: nosetests --with-xunit transportpce_tests/2.2.1/test_portmapping.py
{py3,topology221}: nosetests --with-xunit transportpce_tests/2.2.1/test_topology.py
{py3,otntopology}: nosetests --with-xunit transportpce_tests/2.2.1/test_otn_topology.py
{gnpy}: - sudo docker run -d -p 8008:5000 --name gnpy_tpce_rest1 atriki/gnpyrest:v1.2
{gnpy}: nosetests --with-xunit transportpce_tests/1.2.1/test_gnpy.py
{gnpy}: - sudo docker container rm -f gnpy_tpce_rest1
+ {nbinotifications}: - sudo docker-compose -f ./nbinotifications/docker-compose.yml up -d
+ {nbinotifications}: nosetests --with-xunit transportpce_tests/2.2.1/test_nbinotifications.py
+ {nbinotifications}: - sudo docker-compose -f ./nbinotifications/docker-compose.yml down --rmi all
[testenv:docs]
passenv = http_proxy HTTP_PROXY https_proxy HTTPS_PROXY no_proxy NO_PROXY