816aa50f4dbdf88838d8384c4df4bc61de994e9d
[ccsdk/features.git] /
1 /*
2  * ============LICENSE_START========================================================================
3  * ONAP : ccsdk feature sdnr wt
4  * =================================================================================================
5  * Copyright (C) 2020 highstreet technologies GmbH Intellectual Property. All rights reserved.
6  * =================================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
8  * in compliance with the License. You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software distributed under the License
13  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
14  * or implied. See the License for the specific language governing permissions and limitations under
15  * the License.
16  * ============LICENSE_END==========================================================================
17  */
18 package org.onap.ccsdk.features.sdnr.wt.devicemanager.onf14.impl;
19
20 import java.util.ArrayList;
21 import java.util.List;
22 import java.util.Optional;
23 import org.eclipse.jdt.annotation.NonNull;
24 import org.eclipse.jdt.annotation.Nullable;
25 import org.onap.ccsdk.features.sdnr.wt.dataprovider.model.DataProvider;
26 import org.onap.ccsdk.features.sdnr.wt.devicemanager.ne.service.NetworkElement;
27 import org.onap.ccsdk.features.sdnr.wt.devicemanager.ne.service.NetworkElementService;
28 import org.onap.ccsdk.features.sdnr.wt.devicemanager.service.DeviceManagerServiceProvider;
29 import org.onap.ccsdk.features.sdnr.wt.devicemanager.service.FaultService;
30 import org.onap.ccsdk.features.sdnr.wt.devicemanager.types.FaultData;
31 import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.Capabilities;
32 import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.NetconfAccessor;
33 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
34 import org.opendaylight.yang.gen.v1.urn.onf.yang.air._interface._2._0.rev200121.LAYERPROTOCOLNAMETYPEAIRLAYER;
35 import org.opendaylight.yang.gen.v1.urn.onf.yang.air._interface._2._0.rev200121.LayerProtocol1;
36 import org.opendaylight.yang.gen.v1.urn.onf.yang.air._interface._2._0.rev200121.SEVERITYTYPE;
37 import org.opendaylight.yang.gen.v1.urn.onf.yang.air._interface._2._0.rev200121.SEVERITYTYPECRITICAL;
38 import org.opendaylight.yang.gen.v1.urn.onf.yang.air._interface._2._0.rev200121.SEVERITYTYPEMAJOR;
39 import org.opendaylight.yang.gen.v1.urn.onf.yang.air._interface._2._0.rev200121.SEVERITYTYPEMINOR;
40 import org.opendaylight.yang.gen.v1.urn.onf.yang.air._interface._2._0.rev200121.SEVERITYTYPENONALARMED;
41 import org.opendaylight.yang.gen.v1.urn.onf.yang.air._interface._2._0.rev200121.SEVERITYTYPEWARNING;
42 import org.opendaylight.yang.gen.v1.urn.onf.yang.air._interface._2._0.rev200121.air._interface.current.problems.CurrentProblemList;
43 import org.opendaylight.yang.gen.v1.urn.onf.yang.air._interface._2._0.rev200121.air._interface.lp.spec.AirInterfacePac;
44 import org.opendaylight.yang.gen.v1.urn.onf.yang.air._interface._2._0.rev200121.air._interface.pac.AirInterfaceCurrentProblems;
45 import org.opendaylight.yang.gen.v1.urn.onf.yang.core.model._1._4.rev191127.ControlConstruct;
46 import org.opendaylight.yang.gen.v1.urn.onf.yang.core.model._1._4.rev191127.LAYERPROTOCOLNAMETYPE;
47 import org.opendaylight.yang.gen.v1.urn.onf.yang.core.model._1._4.rev191127.UniversalId;
48 import org.opendaylight.yang.gen.v1.urn.onf.yang.core.model._1._4.rev191127.control.construct.Equipment;
49 import org.opendaylight.yang.gen.v1.urn.onf.yang.core.model._1._4.rev191127.control.construct.EquipmentKey;
50 import org.opendaylight.yang.gen.v1.urn.onf.yang.core.model._1._4.rev191127.control.construct.LogicalTerminationPoint;
51 import org.opendaylight.yang.gen.v1.urn.onf.yang.core.model._1._4.rev191127.control.construct.LogicalTerminationPointKey;
52 import org.opendaylight.yang.gen.v1.urn.onf.yang.core.model._1._4.rev191127.equipment.ContainedHolder;
53 import org.opendaylight.yang.gen.v1.urn.onf.yang.core.model._1._4.rev191127.logical.termination.point.LayerProtocol;
54 import org.opendaylight.yang.gen.v1.urn.onf.yang.core.model._1._4.rev191127.logical.termination.point.LayerProtocolKey;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.NetworkElementConnectionBuilder;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.NetworkElementDeviceType;
58 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
59 import org.opendaylight.yangtools.concepts.ListenerRegistration;
60 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
61 import org.opendaylight.yangtools.yang.binding.NotificationListener;
62 import org.opendaylight.yangtools.yang.common.QName;
63 import org.slf4j.Logger;
64 import org.slf4j.LoggerFactory;
65
66 /**
67  * Repesentation of ONF Core model 1.4 device Top level element is "ControlConstruct" (replaces "NetworkElement" of
68  * older ONF Version)
69  */
70 public class Onf14NetworkElement implements NetworkElement {
71
72     private static final Logger log = LoggerFactory.getLogger(Onf14NetworkElement.class);
73
74     protected static final InstanceIdentifier<ControlConstruct> CONTROLCONSTRUCT_IID =
75             InstanceIdentifier.builder(ControlConstruct.class).build();
76
77     private static final int EQUIPMENTROOTLEVEL = 0;
78
79     private final NetconfAccessor netconfAccessor;
80     private final DataProvider databaseService;
81     private final Onf14ToInternalDataModel onf14Mapper;
82     private final @NonNull FaultService faultService;
83
84     // for storing the Equipment UUIDs that are inserted in the DB
85     private final List<String> equipmentUuidList = new ArrayList<String>();
86
87     // air interface related members
88     private final List<TechnologySpecificPacKeys> airInterfaceList = new ArrayList<TechnologySpecificPacKeys>();
89     private ListenerRegistration<NotificationListener> airInterfaceNotificationListenerHandler;
90     private @NonNull final Onf14AirInterfaceNotificationListener airInterfaceNotificationListener;
91
92     Onf14NetworkElement(NetconfAccessor netconfAccess, DeviceManagerServiceProvider serviceProvider) {
93         log.info("Create {}", Onf14NetworkElement.class.getSimpleName());
94         this.netconfAccessor = netconfAccess;
95         this.databaseService = serviceProvider.getDataProvider();
96         this.faultService = serviceProvider.getFaultService();
97         this.onf14Mapper = new Onf14ToInternalDataModel();
98         this.airInterfaceNotificationListenerHandler = null;
99         airInterfaceNotificationListener = new Onf14AirInterfaceNotificationListener(netconfAccess, serviceProvider);
100     }
101
102     public void initialReadFromNetworkElement() {
103
104         // reading the inventory (CoreModel 1.4 Equipment Model) and adding it to the DB
105         readEquipmentData();
106
107         FaultData resultList = new FaultData();
108
109         int problems = faultService.removeAllCurrentProblemsOfNode(netconfAccessor.getNodeId());
110         log.debug("Removed all {} problems from database at registration", problems);
111
112         readAllAirInterfaceCurrentProblems(resultList);
113         log.debug("NETCONF read current problems completed. Got back {} problems.", resultList.size());
114
115         faultService.initCurrentProblemStatus(netconfAccessor.getNodeId(), resultList);
116         log.debug("DB write current problems completed");
117
118     }
119
120     public void readAllAirInterfaceCurrentProblems(FaultData resultList) {
121
122         int idxStart; // Start index for debug messages
123
124         for (TechnologySpecificPacKeys key : airInterfaceList) {
125             idxStart = resultList.size();
126
127             readAirInterfaceCurrentProblemForLtp(key.getLtpUuid(), key.getLocalId(), resultList);
128             debugResultList(key.getLtpUuid().getValue(), resultList, idxStart);
129         }
130     }
131
132     /**
133      * @param nNode
134      * set core-model-capability
135      */
136     public void setCoreModel(@NonNull NetconfNode nNode) {
137         NetworkElementConnectionBuilder eb = new NetworkElementConnectionBuilder();
138         log.info("In setCoreModel for Onf14NetworkElement");
139         String namespaceRevision;
140         QName QNAME_COREMODEL14 = QName.create("urn:onf:yang:core-model-1-4", "2019-11-27", "core-model-1-4").intern();
141
142         Capabilities availableCapabilities = Capabilities.getAvailableCapabilities(nNode);
143         namespaceRevision = availableCapabilities.getRevisionForNamespace(QNAME_COREMODEL14);
144         log.info("In setCoreModel for Onf14NetworkElement- namespaceRevision = "+namespaceRevision);
145         if (Capabilities.isNamespaceSupported(namespaceRevision)) {
146             eb.setCoreModelCapability(namespaceRevision);
147         } else {
148             eb.setCoreModelCapability("Unsupported");
149         }
150         databaseService.updateNetworkConnection22(eb.build(), netconfAccessor.getNodeId().getValue());
151     }
152     
153     @Override
154     public void register() {
155         // Set core-model revision value in "core-model-capability" field
156         setCoreModel(netconfAccessor.getNetconfNode());
157         initialReadFromNetworkElement();
158         // Register netconf stream
159         airInterfaceNotificationListenerHandler =
160                 netconfAccessor.doRegisterNotificationListener(airInterfaceNotificationListener);
161         netconfAccessor.registerNotificationsStream(NetconfAccessor.DefaultNotificationsStream);
162     }
163
164     @Override
165     public void deregister() {}
166
167
168     @Override
169     public NodeId getNodeId() {
170         return netconfAccessor.getNodeId();
171     }
172
173     @Override
174     public <L extends NetworkElementService> Optional<L> getService(Class<L> clazz) {
175         return Optional.empty();
176     }
177
178     @Override
179     public void warmstart() {}
180
181     @Override
182     public Optional<NetconfAccessor> getAcessor() {
183         return Optional.of(netconfAccessor);
184     }
185
186     @Override
187     public NetworkElementDeviceType getDeviceType() {
188         return NetworkElementDeviceType.Wireless;
189     }
190
191     public static org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.SeverityType mapSeverity(
192             Class<? extends SEVERITYTYPE> severity) {
193
194         if (severity != null) {
195             if (severity.getTypeName() == SEVERITYTYPECRITICAL.class.getName()) {
196                 return org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.SeverityType.Critical;
197             } else if (severity.getTypeName() == SEVERITYTYPEMAJOR.class.getName()) {
198                 return org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.SeverityType.Major;
199             } else if (severity.getTypeName() == SEVERITYTYPEMINOR.class.getName()) {
200                 return org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.SeverityType.Minor;
201             } else if (severity.getTypeName() == SEVERITYTYPEWARNING.class.getName()) {
202                 return org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.SeverityType.Warning;
203             } else if (severity.getTypeName() == SEVERITYTYPENONALARMED.class.getName()) {
204                 return org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.SeverityType.NonAlarmed;
205             }
206         }
207
208         return org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.SeverityType.NonAlarmed;
209     }
210
211     private void readEquipmentData() {
212
213         Optional<ControlConstruct> controlConstruct = readControlConstruct(netconfAccessor);
214
215         if (controlConstruct.isPresent()) {
216             // the top-level-equipment list contains the root objects of the Equipment Model
217             log.debug("Getting list of topLevelEquipment for mountpoint {}", netconfAccessor.getNodeId());
218             @Nullable
219             List<UniversalId> topLevelEquipment = controlConstruct.get().getTopLevelEquipment();
220
221             if (topLevelEquipment != null) {
222                 for (UniversalId uuid : topLevelEquipment) {
223                     log.debug("Got back topLevelEquipment with uuid {}", uuid.getValue());
224
225                     // adding all root Equipment objects to the DB
226                     @Nullable
227                     Equipment equipmentInstance = readEquipmentInstance(netconfAccessor, uuid);
228                     if (equipmentInstance != null) {
229                         // recursively adding the root equipment and all its children into the DB
230                         addEquipmentToDb(equipmentInstance, null, EQUIPMENTROOTLEVEL);
231                     }
232                 }
233             }
234         }
235
236         // storing all the airInterface LTP UUIDs internally, for later usage
237         readAirInterfaceKeys(controlConstruct);
238     }
239
240     private void addEquipmentToDb(Equipment currentEq, Equipment parentEq, long treeLevel) {
241
242         // if the Equipment UUID is already in the list, it was already processed
243         // needed for solving possible circular dependencies
244         if (equipmentUuidList.contains(currentEq.getUuid().getValue())) {
245             log.debug("Not adding equipment with uuid {} because it was aleady added...",
246                     currentEq.getUuid().getValue());
247             return;
248         }
249
250         // we add this to our internal list, such that we avoid circular dependencies
251         equipmentUuidList.add(currentEq.getUuid().getValue());
252         log.debug("Adding equipment with uuid {} to the database...", currentEq.getUuid().getValue());
253
254         // we add our current equipment to the database
255         databaseService.writeInventory(
256                 onf14Mapper.getInternalEquipment(netconfAccessor.getNodeId(), currentEq, parentEq, treeLevel));
257
258         // we iterate the kids of our current equipment and add them to the database recursively
259         // the actual reference is here: /core-model:control-construct/equipment/contained-holder/occupying-fru
260         @NonNull
261         List<ContainedHolder> holderList = currentEq.nonnullContainedHolder();
262
263         for (ContainedHolder holder : holderList) {
264             @Nullable
265             UniversalId occupyingFru = holder.getOccupyingFru();
266             if (occupyingFru != null) {
267                 @Nullable
268                 Equipment childEq = readEquipmentInstance(netconfAccessor, occupyingFru);
269
270                 if (childEq != null) {
271                     // current becomes parent and tree level increases by 1
272                     addEquipmentToDb(childEq, currentEq, treeLevel + 1);
273                 }
274             }
275         }
276     }
277
278     private void readAirInterfaceKeys(Optional<ControlConstruct> controlConstruct) {
279
280         if (controlConstruct.isPresent()) {
281             @NonNull
282             List<LogicalTerminationPoint> ltpList = controlConstruct.get().nonnullLogicalTerminationPoint();
283             log.debug("Iterating the LTP list for node {}", netconfAccessor.getNodeId().getValue());
284
285             // iterating all the Logical Termination Point list
286             for (LogicalTerminationPoint ltp : ltpList) {
287                 @NonNull
288                 List<LayerProtocol> lpList = ltp.nonnullLayerProtocol();
289                 // the Layer Protocol list should contain only one item, since we have an 1:1 relationship between the LTP and the LP
290                 if (lpList.size() != 1) {
291                     log.debug("Layer protocol has no 1:1 relationship with the LTP.");
292                     return;
293                 }
294                 // accessing the LP, which should be only 1
295                 LayerProtocol lp = lpList.get(0);
296                 @Nullable
297                 Class<? extends LAYERPROTOCOLNAMETYPE> layerProtocolName = lp.getLayerProtocolName();
298                 if (layerProtocolName != null) {
299                     // it the LTP has an airInterface technology extension, the layer protocol name is air-layer
300                     if (layerProtocolName.getTypeName() == LAYERPROTOCOLNAMETYPEAIRLAYER.class.getName()) {
301                         TechnologySpecificPacKeys airInterfaceKey =
302                                 new TechnologySpecificPacKeys(ltp.getUuid(), lp.getLocalId());
303                         airInterfaceList.add(airInterfaceKey);
304                         log.debug("Adding Ltp with uuid {} and local-id {} to the air-interface list",
305                                 ltp.getUuid().getValue(), lp.getLocalId());
306                     }
307                 }
308             }
309         }
310     }
311
312     private void readAirInterfaceCurrentProblemForLtp(UniversalId ltpUuid, String localId, FaultData resultList) {
313
314         final Class<AirInterfacePac> clazzPac = AirInterfacePac.class;
315
316         log.info("DBRead Get current problems for class {} from mountpoint {} for LTP uuid {} and local-id {}",
317                 clazzPac.getSimpleName(), netconfAccessor.getNodeId().getValue(), ltpUuid.getValue(), localId);
318
319         // constructing the IID needs the augmentation exposed byy the air-interface-2-0 model
320         InstanceIdentifier<AirInterfaceCurrentProblems> airInterfaceCurrentProblem_IID =
321                 InstanceIdentifier.builder(ControlConstruct.class)
322                         .child(LogicalTerminationPoint.class, new LogicalTerminationPointKey(ltpUuid))
323                         .child(LayerProtocol.class, new LayerProtocolKey(localId)).augmentation(LayerProtocol1.class)
324                         .child(AirInterfacePac.class).child(AirInterfaceCurrentProblems.class).build();
325
326         // reading all the current-problems list for this specific LTP and LP
327         AirInterfaceCurrentProblems problems = netconfAccessor.getTransactionUtils().readData(
328                 netconfAccessor.getDataBroker(), LogicalDatastoreType.OPERATIONAL, airInterfaceCurrentProblem_IID);
329
330         if (problems == null) {
331             log.debug("DBRead Id {} no AirInterfaceCurrentProblems", ltpUuid);
332         } else if (problems.getCurrentProblemList() == null) {
333             log.debug("DBRead Id {} empty CurrentProblemList", ltpUuid);
334         } else {
335             for (CurrentProblemList problem : problems.nonnullCurrentProblemList()) {
336                 resultList.add(netconfAccessor.getNodeId(), (int) problem.getSequenceNumber(), problem.getTimestamp(),
337                         ltpUuid.getValue(), problem.getProblemName(), mapSeverity(problem.getProblemSeverity()));
338             }
339         }
340     }
341
342     private Optional<ControlConstruct> readControlConstruct(NetconfAccessor netconfAccessor) {
343         return Optional.ofNullable(netconfAccessor.getTransactionUtils().readData(netconfAccessor.getDataBroker(),
344                 LogicalDatastoreType.OPERATIONAL, CONTROLCONSTRUCT_IID));
345     }
346
347     private @Nullable Equipment readEquipmentInstance(NetconfAccessor accessData, UniversalId equipmentUuid) {
348
349         final Class<?> clazzPac = Equipment.class;
350
351         log.info("DBRead Get equipment for class {} from mountpoint {} for uuid {}", clazzPac.getSimpleName(),
352                 accessData.getNodeId().getValue(), equipmentUuid.getValue());
353
354         InstanceIdentifier<Equipment> equipmentIID = InstanceIdentifier.builder(ControlConstruct.class)
355                 .child(Equipment.class, new EquipmentKey(equipmentUuid)).build();
356
357         return accessData.getTransactionUtils().readData(accessData.getDataBroker(), LogicalDatastoreType.OPERATIONAL,
358                 equipmentIID);
359     }
360
361     // defining a structure that can map the LP local-id and its corresponding LTP uuid
362     private class TechnologySpecificPacKeys {
363
364         private UniversalId ltpUuid;
365         private String localId;
366
367         public TechnologySpecificPacKeys(UniversalId uuid, String lId) {
368             this.ltpUuid = uuid;
369             this.localId = lId;
370         }
371
372         public UniversalId getLtpUuid() {
373             return ltpUuid;
374         }
375
376         public String getLocalId() {
377             return localId;
378         }
379
380         public void setLtpUuid(UniversalId uuid) {
381             this.ltpUuid = uuid;
382         }
383
384         public void setLocalId(String lId) {
385             this.localId = lId;
386         }
387     }
388
389
390     /**
391      * LOG the newly added problems of the interface pac
392      *
393      * @param idxStart
394      * @param uuid
395      * @param resultList
396      */
397     private void debugResultList(String uuid, FaultData resultList, int idxStart) {
398         StringBuilder sb = new StringBuilder();
399         int idx = 0;
400         for (int t = idxStart; t < resultList.size(); t++) {
401             sb.append(idx++);
402             sb.append(":{");
403             sb.append(resultList.get(t));
404             sb.append('}');
405         }
406         log.debug("Found problems {} {}", uuid, sb);
407     }
408
409 }