Merge "Optimize cm-handle registration with CPS-DMI Plugin to upload yang model"
[ccsdk/features.git] / sdnr / wt / devicemanager-o-ran-sc / o-ran / ru-fh / provider / src / main / java / org / onap / ccsdk / features / sdnr / wt / devicemanager / oran / impl / ORanNetworkElement.java
1 /*
2  * ============LICENSE_START========================================================================
3  * ONAP : ccsdk feature sdnr wt
4  * =================================================================================================
5  * Copyright (C) 2019 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.oran.impl;
19
20 import com.fasterxml.jackson.core.JsonProcessingException;
21 import java.util.Collection;
22 import java.util.Collections;
23 import java.util.List;
24 import java.util.Optional;
25 import org.eclipse.jdt.annotation.NonNull;
26 import org.eclipse.jdt.annotation.Nullable;
27 import org.onap.ccsdk.features.sdnr.wt.common.YangHelper;
28 import org.onap.ccsdk.features.sdnr.wt.dataprovider.model.DataProvider;
29 import org.onap.ccsdk.features.sdnr.wt.devicemanager.ne.service.NetworkElement;
30 import org.onap.ccsdk.features.sdnr.wt.devicemanager.ne.service.NetworkElementService;
31 import org.onap.ccsdk.features.sdnr.wt.devicemanager.service.DeviceManagerServiceProvider;
32 import org.onap.ccsdk.features.sdnr.wt.devicemanager.service.VESCollectorService;
33 import org.onap.ccsdk.features.sdnr.wt.devicemanager.types.VESCommonEventHeaderPOJO;
34 import org.onap.ccsdk.features.sdnr.wt.devicemanager.types.VESPNFRegistrationFieldsPOJO;
35 import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.Capabilities;
36 import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.NetconfAccessor;
37 import org.onap.ccsdk.features.sdnr.wt.netconfnodestateservice.NetconfBindingAccessor;
38 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
39 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.hardware.rev180313.Hardware;
40 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.hardware.rev180313.hardware.Component;
41 import org.opendaylight.yang.gen.v1.urn.onap.system.rev201026.System1;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev201110.Guicutthrough;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev201110.Inventory;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev201110.NetworkElementDeviceType;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netconf.callhome.server.rev201015.NetconfCallhomeServer;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netconf.callhome.server.rev201015.netconf.callhome.server.AllowedDevices;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netconf.callhome.server.rev201015.netconf.callhome.server.allowed.devices.Device;
48 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
49 import org.opendaylight.yangtools.concepts.ListenerRegistration;
50 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
51 import org.opendaylight.yangtools.yang.binding.NotificationListener;
52 import org.opendaylight.yangtools.yang.common.QName;
53 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory;
55
56 public class ORanNetworkElement implements NetworkElement {
57
58     private static final Logger LOG = LoggerFactory.getLogger(ORanNetworkElement.class);
59
60     public static final QName ONAP_SYSTEM =
61             org.opendaylight.yang.gen.v1.urn.onap.system.rev201026.$YangModuleInfoImpl.getInstance().getName();
62     private static final InstanceIdentifier<System1> SYSTEM1_IID = InstanceIdentifier
63             .builder(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.system.rev140806.System.class)
64             .augmentation(System1.class).build();
65
66     private final NetconfBindingAccessor netconfAccessor;
67     private final DataProvider databaseService;
68     private final ORanRegistrationToVESpnfRegistrationMapper mapper;
69     private final VESCollectorService vesCollectorService;
70
71     private ListenerRegistration<NotificationListener> oRanListenerRegistrationResult;
72     private @NonNull final ORanChangeNotificationListener oRanListener;
73     private ListenerRegistration<NotificationListener> oRanFaultListenerRegistrationResult;
74     private @NonNull final ORanFaultNotificationListener oRanFaultListener;
75
76     ORanNetworkElement(NetconfBindingAccessor netconfAccess, DeviceManagerServiceProvider serviceProvider) {
77         LOG.info("Create {}", ORanNetworkElement.class.getSimpleName());
78         // Read parameters
79         this.netconfAccessor = netconfAccess;
80
81         // Get services
82         this.databaseService = serviceProvider.getDataProvider();
83         this.vesCollectorService = serviceProvider.getVESCollectorService();
84
85         this.mapper = new ORanRegistrationToVESpnfRegistrationMapper(netconfAccessor, vesCollectorService);
86
87         // Register callbacks
88         this.oRanListenerRegistrationResult = null;
89         this.oRanListener = new ORanChangeNotificationListener(netconfAccessor, serviceProvider);
90
91         this.oRanFaultListenerRegistrationResult = null;
92         this.oRanFaultListener = new ORanFaultNotificationListener(netconfAccessor, vesCollectorService,
93                 serviceProvider.getFaultService(), serviceProvider.getWebsocketService(), databaseService);
94     }
95
96     private Collection<Component> initialReadFromNetworkElement() {
97         Collection<Component> componentList;
98         Hardware hardware = readHardware();
99         if (hardware != null) {
100             componentList = YangHelper.getCollection(hardware.nonnullComponent());
101             List<Inventory> inventoryList =
102                     ORanToInternalDataModel.getInventoryList(netconfAccessor.getNodeId(), componentList);
103             databaseService.writeInventory(netconfAccessor.getNodeId().getValue(), inventoryList);
104         } else {
105             componentList = Collections.emptyList();
106         }
107
108         Optional<Guicutthrough> oGuicutthrough = ORanToInternalDataModel.getGuicutthrough(getOnapSystemData());
109         if (oGuicutthrough.isPresent()) {
110             databaseService.writeGuiCutThroughData(oGuicutthrough.get(), netconfAccessor.getNodeId().getValue());
111         }
112         return componentList;
113     }
114
115     @Override
116     public NetworkElementDeviceType getDeviceType() {
117         return NetworkElementDeviceType.ORAN;
118     }
119
120     @Override
121     public void register() {
122         // Read data from device
123         Collection<Component> componentList = initialReadFromNetworkElement();
124         oRanFaultListener.setComponentList(componentList);
125         // Publish the mountpoint to VES if enabled
126         publishMountpointToVES(componentList);
127         // Register call back class for receiving notifications
128         this.oRanListenerRegistrationResult = netconfAccessor.doRegisterNotificationListener(oRanListener);
129         this.oRanFaultListenerRegistrationResult = netconfAccessor.doRegisterNotificationListener(oRanFaultListener);
130         // Register notifications stream
131         if (netconfAccessor.isNotificationsRFC5277Supported()) {
132             netconfAccessor.registerNotificationsStream();
133         }
134     }
135
136     @Override
137     public void deregister() {
138         if (oRanListenerRegistrationResult != null) {
139             this.oRanListenerRegistrationResult.close();
140         }
141         if (oRanFaultListenerRegistrationResult != null) {
142             this.oRanFaultListenerRegistrationResult.close();
143         } ;
144         databaseService.clearGuiCutThroughEntriesOfNode(getMountpointId());
145     }
146
147     @Override
148     public NodeId getNodeId() {
149         return netconfAccessor.getNodeId();
150     }
151
152     @Override
153     public <L extends NetworkElementService> Optional<L> getService(Class<L> clazz) {
154         return Optional.empty();
155     }
156
157     @Override
158     public void warmstart() {}
159
160     @Override
161     public Optional<NetconfAccessor> getAcessor() {
162         return Optional.of(netconfAccessor);
163     }
164
165     // Private functions
166
167     private String getMountpointId() {
168         return getNodeId().getValue();
169     }
170
171     // Read from device
172     /**
173      * Read system data with GUI cut through information from device if ONAP_SYSTEM YANG is supported.
174      *
175      * @return System1 data with GUI cut through information or null if not available.
176      */
177     private @Nullable System1 getOnapSystemData() {
178         LOG.info("Get System1 for class {} from mountpoint {}", netconfAccessor.getNodeId().getValue());
179         Capabilities x = netconfAccessor.getCapabilites();
180         LOG.info("Capabilites: {}", x);
181         if (x.isSupportingNamespace(ONAP_SYSTEM)) {
182             @Nullable
183             System1 res = netconfAccessor.getTransactionUtils().readData(netconfAccessor.getDataBroker(),
184                     LogicalDatastoreType.OPERATIONAL, SYSTEM1_IID);
185             LOG.debug("Result of System1 = {}", res);
186             return res;
187         } else {
188             LOG.debug("No GUI cut through support");
189             return null;
190         }
191     }
192
193     private Hardware readHardware() {
194         final Class<Hardware> clazzPac = Hardware.class;
195         LOG.info("DBRead Get hardware for class {} from mountpoint {}", clazzPac.getSimpleName(),
196                 netconfAccessor.getNodeId().getValue());
197         InstanceIdentifier<Hardware> hardwareIID = InstanceIdentifier.builder(clazzPac).build();
198         Hardware res = netconfAccessor.getTransactionUtils().readData(netconfAccessor.getDataBroker(),
199                 LogicalDatastoreType.OPERATIONAL, hardwareIID);
200         LOG.debug("Result of Hardware = {}", res);
201         return res;
202     }
203
204     // VES related
205     private void publishMountpointToVES(Collection<Component> componentList) {
206
207         LOG.debug("In publishMountpointToVES()");
208
209         /*
210          * 1. Check if this device is in the list of allowed-devices. 2. If device
211          * exists in allowed-devices, then create VES pnfRegistration event and publish
212          * to VES
213          */
214         if (inAllowedDevices(getMountpointId())) {
215             if (vesCollectorService.getConfig().isVESCollectorEnabled()) {
216                 for (Component component : ORanToInternalDataModel.getRootComponents(componentList)) {
217                     // Just get one component. At the moment we don't care which one. Also since
218                     // there is only one management address, we assume there will be only one
219                     // chassis.
220                     // If the device supports subtended configuration then it is assumed that the
221                     // Chassis containing the management interface will be the root component and
222                     // there will be only one root.
223                     VESCommonEventHeaderPOJO header = mapper.mapCommonEventHeader(component);
224                     VESPNFRegistrationFieldsPOJO body = mapper.mapPNFRegistrationFields(component);
225                     try {
226                         vesCollectorService.publishVESMessage(vesCollectorService.generateVESEvent(header, body));
227                     } catch (JsonProcessingException e) {
228                         LOG.warn("Error while serializing VES Event to String ", e);
229                         e.printStackTrace();
230                     }
231                 }
232             }
233         }
234     }
235
236     private boolean inAllowedDevices(String mountpointName) {
237         final InstanceIdentifier<AllowedDevices> ALL_DEVICES =
238                 InstanceIdentifier.create(NetconfCallhomeServer.class).child(AllowedDevices.class);
239
240         AllowedDevices allowedDevices = netconfAccessor.getTransactionUtils().readData(
241                 netconfAccessor.getControllerBindingDataBroker(), LogicalDatastoreType.CONFIGURATION, ALL_DEVICES);
242
243         if (allowedDevices != null) {
244             Collection<Device> deviceList = YangHelper.getCollection(allowedDevices.nonnullDevice());
245             for (Device device : deviceList) {
246                 LOG.info("Device in allowed-devices is - {}", device.getUniqueId());
247                 if (device.getUniqueId().equals(netconfAccessor.getNodeId().getValue())) {
248                     LOG.info("Mountpoint is part of allowed-devices list");
249                     return true;
250                 }
251             }
252         }
253
254         LOG.info("Mountpoint {} is not part of allowed-devices list", mountpointName);
255         return false;
256     }
257
258 }