Update link status of service-path-list
[transportpce.git] / servicehandler / src / main / java / org / opendaylight / transportpce / servicehandler / listeners / NetworkModelListenerImpl.java
1 /*
2  * Copyright © 2020 Nokia, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.transportpce.servicehandler.listeners;
9
10 import java.util.HashMap;
11 import java.util.Iterator;
12 import java.util.List;
13 import java.util.Map;
14 import java.util.Optional;
15 import java.util.stream.Collectors;
16 import org.eclipse.jdt.annotation.Nullable;
17 import org.opendaylight.mdsal.binding.api.NotificationPublishService;
18 import org.opendaylight.transportpce.common.OperationResult;
19 import org.opendaylight.transportpce.servicehandler.service.ServiceDataStoreOperations;
20 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.networkmodel.rev201116.TopologyUpdateResult;
21 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.networkmodel.rev201116.TopologyUpdateResultBuilder;
22 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.networkmodel.rev201116.TransportpceNetworkmodelListener;
23 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.networkmodel.rev201116.topology.update.result.TopologyChanges;
24 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.networkmodel.rev201116.topology.update.result.TopologyChangesKey;
25 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.state.types.rev191129.State;
26 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev211210.service.list.Services;
27 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev210705.path.description.AToZDirection;
28 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev210705.path.description.AToZDirectionBuilder;
29 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev210705.path.description.ZToADirection;
30 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev210705.path.description.ZToADirectionBuilder;
31 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev210705.path.description.atoz.direction.AToZ;
32 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev210705.path.description.atoz.direction.AToZBuilder;
33 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev210705.path.description.atoz.direction.AToZKey;
34 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev210705.path.description.ztoa.direction.ZToA;
35 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev210705.path.description.ztoa.direction.ZToABuilder;
36 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev210705.path.description.ztoa.direction.ZToAKey;
37 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev210705.pce.resource.Resource;
38 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev210705.pce.resource.ResourceBuilder;
39 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev210705.pce.resource.resource.resource.Link;
40 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev210705.pce.resource.resource.resource.TerminationPoint;
41 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118.service.path.PathDescription;
42 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118.service.path.PathDescriptionBuilder;
43 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.servicepath.rev171017.ServicePathList;
44 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.servicepath.rev171017.service.path.list.ServicePaths;
45 import org.slf4j.Logger;
46 import org.slf4j.LoggerFactory;
47
48 public class NetworkModelListenerImpl implements TransportpceNetworkmodelListener {
49
50     private static final Logger LOG = LoggerFactory.getLogger(NetworkModelListenerImpl.class);
51     private final NotificationPublishService notificationPublishService; // to be used for T-API notification
52     private ServiceDataStoreOperations serviceDataStoreOperations;
53     private TopologyUpdateResult topologyUpdateResult;
54
55     public NetworkModelListenerImpl(NotificationPublishService notificationPublishService,
56                                     ServiceDataStoreOperations serviceDataStoreOperations) {
57         this.notificationPublishService = notificationPublishService;
58         this.serviceDataStoreOperations = serviceDataStoreOperations;
59     }
60
61     @Override
62     public void onTopologyUpdateResult(TopologyUpdateResult notification) {
63         LOG.debug("Topology update notification: {}", notification);
64         if (compareTopologyUpdateResult(notification)) {
65             LOG.warn("TopologyUpdateResult already wired !");
66             return;
67         }
68         topologyUpdateResult = new TopologyUpdateResultBuilder()
69                 .setTopologyChanges(new HashMap<>(notification.getTopologyChanges()))
70                 .build();
71         // Update service datastore and service path description
72         updateServicePaths(notification);
73     }
74
75     /**
76      * Process topology update result.
77      * @param notification the result notification.
78      */
79     protected void updateServicePaths(TopologyUpdateResult notification) {
80         @Nullable
81         Map<TopologyChangesKey, TopologyChanges> topologyChanges = notification.getTopologyChanges();
82         Optional<ServicePathList> servicePathListOptional = this.serviceDataStoreOperations.getServicePaths();
83         if (servicePathListOptional.isEmpty()) {
84             LOG.warn("Enable to retrieve service path list");
85             return;
86         }
87         ServicePathList servicePathList = servicePathListOptional.get();
88         for (ServicePaths servicePaths : servicePathList.getServicePaths().values()) {
89             String serviceName = servicePaths.getServicePathName();
90             PathDescription pathDescription = servicePaths.getPathDescription();
91             // update path descriptions in the datastore
92             Map<AToZKey, AToZ> updatedAtoZ = changePathElementStateAZ(topologyChanges, pathDescription);
93             Map<ZToAKey, ZToA> updatedZtoA = changePathElementStateZA(topologyChanges, pathDescription);
94             OperationResult operationResult = this.serviceDataStoreOperations
95                     .modifyServicePath(buildNewPathDescription(pathDescription, updatedAtoZ, updatedZtoA), serviceName);
96             if (!operationResult.isSuccess()) {
97                 LOG.warn("Service Path not updated in datastore!");
98                 continue;
99             }
100             // update service in the datastore. Only path description with all elements in service can have a service
101             // in service. Therefore we check if all the states of the path description resources are inService
102             Optional<Services> serviceOptional = this.serviceDataStoreOperations.getService(serviceName);
103             if (serviceOptional.isEmpty()) {
104                 LOG.error("Couldn't retrieve service");
105                 continue;
106             }
107             Services services = serviceOptional.get();
108             OperationResult operationResult1 = null;
109             State newState;
110             switch (services.getOperationalState()) {
111                 case InService:
112                     if (allElementsinPathinService(updatedAtoZ, updatedZtoA)) {
113                         LOG.debug("Service {} state does not need to be modified", serviceName);
114                         continue;
115                     }
116                     newState = State.OutOfService;
117                     break;
118                 case OutOfService:
119                     if (!allElementsinPathinService(updatedAtoZ, updatedZtoA)) {
120                         LOG.debug("Service {} state does not need to be modified", serviceName);
121                         continue;
122                     }
123                     newState = State.InService;
124                     break;
125                 default:
126                     LOG.warn("Service {} state not managed", serviceName);
127                     continue;
128             }
129
130
131             LOG.debug("Service={} needs to be updated to {}", serviceName, newState);
132             //if (operationResult1 != null && operationResult1.isSuccess()) {
133             //null check probably no more needed
134             if (this.serviceDataStoreOperations
135                     .modifyService(serviceName, newState, services.getAdministrativeState())
136                     .isSuccess()) {
137                 LOG.info("Service state of {} correctly updated to {} in datastore", serviceName, newState);
138                 continue;
139             }
140             LOG.error("Service state of {} cannot be updated to {} in datastore", serviceName, newState);
141
142         }
143     }
144
145     protected Map<ZToAKey, ZToA> changePathElementStateZA(Map<TopologyChangesKey, TopologyChanges> topologyChanges,
146         PathDescription pathDescription) {
147         Map<ZToAKey, ZToA> newztoaMap = new HashMap<>(pathDescription.getZToADirection().getZToA());
148         List<ZToA> tpResources = pathDescription.getZToADirection().getZToA().values().stream()
149                 .filter(ele -> ele.getResource().getResource() instanceof TerminationPoint)
150                 .collect(Collectors.toList());
151         List<ZToA> linkResources = pathDescription.getZToADirection().getZToA().values().stream()
152             .filter(ele -> ele.getResource().getResource() instanceof Link)
153             .collect(Collectors.toList());
154         for (ZToA ztoA : tpResources) {
155             String ztoAid = ztoA.getId();
156             State ztoAState = ztoA.getResource().getState();
157             TerminationPoint tp = (TerminationPoint) ztoA.getResource().getResource();
158             if (topologyChanges.containsKey(new TopologyChangesKey(tp.getTpNodeId(), tp.getTpId()))
159                 && !topologyChanges.get(new TopologyChangesKey(tp.getTpNodeId(), tp.getTpId())).getState()
160                 .equals(ztoAState)) {
161                 LOG.debug("updating ztoa tp {}", ztoA);
162                 State updatedState = topologyChanges.get(new TopologyChangesKey(tp.getTpNodeId(), tp.getTpId()))
163                     .getState();
164                 Resource updatedResource = new ResourceBuilder()
165                     .setResource(tp)
166                     .setState(updatedState)
167                     .build();
168                 ZToA updatedZToA = new ZToABuilder(ztoA)
169                     .setId(ztoAid)
170                     .setResource(updatedResource)
171                     .build();
172                 newztoaMap.put(updatedZToA.key(), updatedZToA);
173                 for (ZToA ztoALink : linkResources) {
174                     Link link = (Link)ztoALink.getResource().getResource();
175                     if (link.getLinkId().contains(tp.getTpNodeId())
176                             && link.getLinkId().contains(tp.getTpId())
177                             && ztoALink.getResource().getState() != updatedState) {
178                         ZToA updatedZToAlink = new ZToABuilder(ztoALink)
179                             .setId(ztoAid)
180                             .setResource(new ResourceBuilder()
181                                 .setResource(link)
182                                 .setState(updatedState)
183                                 .build())
184                             .build();
185                         newztoaMap.put(updatedZToAlink.key(), updatedZToAlink);
186                     }
187                 }
188             }
189         }
190         return newztoaMap;
191     }
192
193     protected Map<AToZKey, AToZ> changePathElementStateAZ(Map<TopologyChangesKey,
194             TopologyChanges> topologyChanges, PathDescription pathDescription) {
195
196         Map<AToZKey, AToZ> newatozMap = new HashMap<>(pathDescription.getAToZDirection().getAToZ());
197         List<AToZ> tpResources = pathDescription.getAToZDirection().getAToZ().values().stream()
198             .filter(ele -> ele.getResource().getResource() instanceof TerminationPoint)
199             .collect(Collectors.toList());
200         List<AToZ> linkResources = pathDescription.getAToZDirection().getAToZ().values().stream()
201             .filter(ele -> ele.getResource().getResource() instanceof Link)
202             .collect(Collectors.toList());
203         for (AToZ atoZ : tpResources) {
204             String atoZid = atoZ.getId();
205             State atoZState = atoZ.getResource().getState();
206             TerminationPoint tp = (TerminationPoint) atoZ.getResource().getResource();
207             if (topologyChanges.containsKey(new TopologyChangesKey(tp.getTpNodeId(), tp.getTpId()))
208                 && !topologyChanges.get(new TopologyChangesKey(tp.getTpNodeId(), tp.getTpId())).getState()
209                 .equals(atoZState)) {
210                 LOG.debug("updating atoz tp {}", atoZ);
211                 State updatedState = topologyChanges.get(new TopologyChangesKey(tp.getTpNodeId(), tp.getTpId()))
212                     .getState();
213                 Resource updatedResource = new ResourceBuilder()
214                     .setResource(tp)
215                     .setState(updatedState)
216                     .build();
217                 AToZ updatedAToZ = new AToZBuilder(atoZ)
218                     .setId(atoZid)
219                     .setResource(updatedResource)
220                     .build();
221                 newatozMap.put(updatedAToZ.key(), updatedAToZ);
222                 for (AToZ atozLink : linkResources) {
223                     Link link = (Link)atozLink.getResource().getResource();
224                     if (link.getLinkId().contains(tp.getTpNodeId())
225                             && link.getLinkId().contains(tp.getTpId())
226                             && atozLink.getResource().getState() != updatedState) {
227                         AToZ updatedAToZlink = new AToZBuilder(atozLink)
228                             .setId(atoZid)
229                             .setResource(new ResourceBuilder()
230                                 .setResource(link)
231                                 .setState(updatedState)
232                                 .build())
233                             .build();
234                         newatozMap.put(updatedAToZlink.key(), updatedAToZlink);
235                     }
236                 }
237             }
238         }
239         return newatozMap;
240     }
241
242     private PathDescription buildNewPathDescription(PathDescription pathDescription, Map<AToZKey, AToZ> updatedAtoZ,
243                                                     Map<ZToAKey, ZToA> updatedZtoA) {
244         AToZDirection atozDir = new AToZDirectionBuilder(pathDescription.getAToZDirection())
245                 .setAToZ(updatedAtoZ)
246                 .build();
247         ZToADirection ztoaDir = new ZToADirectionBuilder(pathDescription.getZToADirection())
248                 .setZToA(updatedZtoA)
249                 .build();
250         return new PathDescriptionBuilder()
251             .setAToZDirection(atozDir)
252             .setZToADirection(ztoaDir)
253             .build();
254     }
255
256     protected boolean allElementsinPathinService(Map<AToZKey, AToZ> updatedAtoZ, Map<ZToAKey, ZToA> updatedZtoA) {
257         boolean allEleminService = true;
258         Iterator<AToZ> i1 = updatedAtoZ.values().iterator();
259         Iterator<ZToA> i2 = updatedZtoA.values().iterator();
260         // TODO: both directions have same length?
261         while (i1.hasNext() && i2.hasNext()) {
262             if (State.OutOfService.getIntValue() == i1.next().getResource().getState().getIntValue()
263                     || State.OutOfService.getIntValue() == i2.next().getResource().getState().getIntValue()) {
264                 allEleminService = false;
265                 break;
266             }
267         }
268
269         return allEleminService;
270     }
271
272     private boolean compareTopologyUpdateResult(TopologyUpdateResult notification) {
273         return topologyUpdateResult != null
274                 && topologyUpdateResult.getTopologyChanges().equals(notification.getTopologyChanges());
275     }
276
277     public void setserviceDataStoreOperations(ServiceDataStoreOperations serviceData) {
278         this.serviceDataStoreOperations = serviceData;
279     }
280 }