OVSDB-438: missing operational node
[ovsdb.git] / hwvtepsouthbound / hwvtepsouthbound-impl / src / main / java / org / opendaylight / ovsdb / hwvtepsouthbound / HwvtepTableReader.java
1 /*
2  * Copyright (c) 2017 Ericsson India Global Services Pvt Ltd. 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.ovsdb.hwvtepsouthbound;
9
10 import com.google.common.collect.Lists;
11
12 import java.util.ArrayList;
13 import java.util.Arrays;
14 import java.util.Collections;
15 import java.util.HashMap;
16 import java.util.List;
17 import java.util.Map;
18 import java.util.Optional;
19 import java.util.concurrent.ExecutionException;
20 import java.util.function.Function;
21 import java.util.stream.Collectors;
22
23 import org.opendaylight.ovsdb.lib.message.TableUpdate;
24 import org.opendaylight.ovsdb.lib.message.TableUpdates;
25 import org.opendaylight.ovsdb.lib.notation.Condition;
26 import org.opendaylight.ovsdb.lib.notation.Row;
27 import org.opendaylight.ovsdb.lib.notation.UUID;
28 import org.opendaylight.ovsdb.lib.operations.Operation;
29 import org.opendaylight.ovsdb.lib.operations.OperationResult;
30 import org.opendaylight.ovsdb.lib.operations.Select;
31 import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
32 import org.opendaylight.ovsdb.lib.schema.GenericTableSchema;
33 import org.opendaylight.ovsdb.lib.schema.typed.TypedBaseTable;
34 import org.opendaylight.ovsdb.lib.schema.typed.TyperUtils;
35 import org.opendaylight.ovsdb.schema.hardwarevtep.ACL;
36 import org.opendaylight.ovsdb.schema.hardwarevtep.ACLEntry;
37 import org.opendaylight.ovsdb.schema.hardwarevtep.ArpSourcesLocal;
38 import org.opendaylight.ovsdb.schema.hardwarevtep.ArpSourcesRemote;
39 import org.opendaylight.ovsdb.schema.hardwarevtep.Global;
40 import org.opendaylight.ovsdb.schema.hardwarevtep.LogicalRouter;
41 import org.opendaylight.ovsdb.schema.hardwarevtep.LogicalSwitch;
42 import org.opendaylight.ovsdb.schema.hardwarevtep.Manager;
43 import org.opendaylight.ovsdb.schema.hardwarevtep.McastMacsLocal;
44 import org.opendaylight.ovsdb.schema.hardwarevtep.McastMacsRemote;
45 import org.opendaylight.ovsdb.schema.hardwarevtep.PhysicalLocator;
46 import org.opendaylight.ovsdb.schema.hardwarevtep.PhysicalLocatorSet;
47 import org.opendaylight.ovsdb.schema.hardwarevtep.PhysicalPort;
48 import org.opendaylight.ovsdb.schema.hardwarevtep.PhysicalSwitch;
49 import org.opendaylight.ovsdb.schema.hardwarevtep.Tunnel;
50 import org.opendaylight.ovsdb.schema.hardwarevtep.UcastMacsLocal;
51 import org.opendaylight.ovsdb.schema.hardwarevtep.UcastMacsRemote;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitches;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacs;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteUcastMacs;
55 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
56 import org.opendaylight.yangtools.yang.binding.Identifiable;
57 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
58 import org.slf4j.Logger;
59 import org.slf4j.LoggerFactory;
60
61 import static org.opendaylight.ovsdb.lib.operations.Operations.op;
62
63 public class HwvtepTableReader {
64
65     private static final Logger LOG = LoggerFactory.getLogger(HwvtepTableReader.class);
66
67     private final Class alltables[] = new Class[] {
68             ACLEntry.class,
69             ACL.class,
70             ArpSourcesLocal.class,
71             Global.class,
72             ArpSourcesRemote.class,
73             LogicalRouter.class,
74             Manager.class,
75             LogicalSwitch.class,
76             McastMacsLocal.class,
77             PhysicalLocator.class,
78             McastMacsRemote.class,
79             PhysicalPort.class,
80             Tunnel.class,
81             PhysicalLocatorSet.class,
82             PhysicalSwitch.class,
83             UcastMacsLocal.class,
84             UcastMacsRemote.class
85     };
86
87     private final Map<Class, Function<InstanceIdentifier, List<Condition>>> whereClauseGetterMap = new HashMap();
88     private final Map<Class, Class> tableMap = new HashMap();
89     private final Map<Class, TypedBaseTable> tables = new HashMap<>();
90
91     private final HwvtepConnectionInstance connectionInstance;
92
93     public HwvtepTableReader(HwvtepConnectionInstance connectionInstance) {
94         this.connectionInstance = connectionInstance;
95         DatabaseSchema dbSchema = null;
96         try {
97             dbSchema = connectionInstance.getSchema(HwvtepSchemaConstants.HARDWARE_VTEP).get();
98         } catch (InterruptedException | ExecutionException e) {
99             LOG.warn("Not able to fetch schema for database {} from device {}",
100                     HwvtepSchemaConstants.HARDWARE_VTEP, connectionInstance.getConnectionInfo(), e);
101         }
102
103         tableMap.put(RemoteMcastMacs.class, McastMacsRemote.class);
104         tableMap.put(RemoteUcastMacs.class, UcastMacsRemote.class);
105         tableMap.put(LogicalSwitches.class, LogicalSwitch.class);
106         tableMap.put(TerminationPoint.class, PhysicalLocator.class);
107
108         whereClauseGetterMap.put(RemoteMcastMacs.class, new RemoteMcastMacWhereClauseGetter());
109         whereClauseGetterMap.put(RemoteUcastMacs.class, new RemoteUcastMacWhereClauseGetter());
110         whereClauseGetterMap.put(LogicalSwitches.class, new LogicalSwitchWhereClauseGetter());
111         whereClauseGetterMap.put(TerminationPoint.class, new LocatorWhereClauseGetter());
112
113         tables.put(McastMacsRemote.class, TyperUtils.getTypedRowWrapper(dbSchema, McastMacsRemote.class, null));
114         tables.put(UcastMacsRemote.class, TyperUtils.getTypedRowWrapper(dbSchema, UcastMacsRemote.class, null));
115         tables.put(LogicalSwitch.class, TyperUtils.getTypedRowWrapper(dbSchema, LogicalSwitch.class, null));
116         tables.put(PhysicalLocator.class, TyperUtils.getTypedRowWrapper(dbSchema, PhysicalLocator.class, null));
117     }
118
119     class RemoteMcastMacWhereClauseGetter implements Function<InstanceIdentifier, List<Condition>> {
120         @Override
121         public List<Condition> apply(InstanceIdentifier iid) {
122             InstanceIdentifier<RemoteMcastMacs> macIid = iid;
123             String mac = macIid.firstKeyOf(RemoteMcastMacs.class).getMacEntryKey().getValue();
124             InstanceIdentifier<LogicalSwitches> lsIid = (InstanceIdentifier<LogicalSwitches>) macIid.firstKeyOf(
125                     RemoteMcastMacs.class).getLogicalSwitchRef().getValue();
126             UUID lsUUID = connectionInstance.getDeviceInfo().getUUID(LogicalSwitches.class, lsIid);
127             if (lsUUID == null) {
128                 LOG.error("Could not find uuid for ls key {}", lsIid);
129                 return null;
130             }
131
132             McastMacsRemote macTable = (McastMacsRemote) tables.get(McastMacsRemote.class);
133             ArrayList<Condition> conditions = new ArrayList<>();
134             conditions.add(macTable.getLogicalSwitchColumn().getSchema().opEqual(lsUUID));
135             conditions.add(macTable.getMacColumn().getSchema().opEqual(mac));
136             return conditions;
137         }
138     }
139
140     class RemoteUcastMacWhereClauseGetter implements Function<InstanceIdentifier, List<Condition>> {
141         @Override
142         public List<Condition> apply(InstanceIdentifier iid) {
143             InstanceIdentifier<RemoteUcastMacs> macIid = iid;
144             String mac = macIid.firstKeyOf(RemoteUcastMacs.class).getMacEntryKey().getValue();
145             InstanceIdentifier<LogicalSwitches> lsIid = (InstanceIdentifier<LogicalSwitches>) macIid.firstKeyOf(
146                     RemoteUcastMacs.class).getLogicalSwitchRef().getValue();
147             UUID lsUUID = connectionInstance.getDeviceInfo().getUUID(LogicalSwitches.class, lsIid);
148             if (lsUUID == null) {
149                 LOG.error("Could not find uuid for ls key {}", lsIid);
150                 return null;
151             }
152
153             UcastMacsRemote macTable = (UcastMacsRemote) tables.get(UcastMacsRemote.class);
154             ArrayList<Condition> conditions = new ArrayList<>();
155             conditions.add(macTable.getLogicalSwitchColumn().getSchema().opEqual(lsUUID));
156             conditions.add(macTable.getMacColumn().getSchema().opEqual(mac));
157             return conditions;
158         }
159     }
160
161     class LogicalSwitchWhereClauseGetter implements Function<InstanceIdentifier, List<Condition>> {
162         @Override
163         public List<Condition> apply(InstanceIdentifier iid) {
164             InstanceIdentifier<LogicalSwitches> lsIid = iid;
165             String lsName = lsIid.firstKeyOf(LogicalSwitches.class).getHwvtepNodeName().getValue();
166             LogicalSwitch logicalSwitch = (LogicalSwitch) tables.get(LogicalSwitch.class);
167             return Lists.newArrayList(logicalSwitch.getNameColumn().getSchema().opEqual(lsName));
168         }
169     }
170
171     class LocatorWhereClauseGetter implements Function<InstanceIdentifier, List<Condition>> {
172         @Override
173         public List<Condition> apply(InstanceIdentifier iid) {
174             InstanceIdentifier<TerminationPoint> tepIid = iid;
175             String locatorIp = tepIid.firstKeyOf(TerminationPoint.class).getTpId().getValue();
176             locatorIp = locatorIp.substring(locatorIp.indexOf(":") + 1);
177             LOG.info("Locator ip to look for {}", locatorIp);
178             PhysicalLocator locatorTable = (PhysicalLocator) tables.get(PhysicalLocator.class);
179             return Lists.newArrayList(locatorTable.getDstIpColumn().getSchema().opEqual(locatorIp));
180         }
181     }
182
183     public Optional<TypedBaseTable> getHwvtepTableEntryUUID(Class<? extends Identifiable> cls,
184                                                             InstanceIdentifier iid,
185                                                             UUID existingUUID) {
186         try {
187             DatabaseSchema dbSchema = null;
188             TypedBaseTable globalRow = null;
189             Class<TypedBaseTable> tableClass = tableMap.get(cls);
190             try {
191                 dbSchema = connectionInstance.getSchema(HwvtepSchemaConstants.HARDWARE_VTEP).get();
192             } catch (InterruptedException | ExecutionException e) {
193                 LOG.warn("Not able to fetch schema for database {} from device {}",
194                         HwvtepSchemaConstants.HARDWARE_VTEP, connectionInstance.getConnectionInfo(), e);
195             }
196
197             if (dbSchema != null) {
198                 GenericTableSchema hwvtepSchema = TyperUtils.getTableSchema(dbSchema, tableClass);
199
200                 List<String> hwvtepTableColumn = new ArrayList<>();
201                 hwvtepTableColumn.addAll(hwvtepSchema.getColumns());
202                 Select<GenericTableSchema> selectOperation = op.select(hwvtepSchema);
203                 selectOperation.setColumns(hwvtepTableColumn);
204
205                 if (existingUUID != null) {
206                     TypedBaseTable table = tables.get(tableClass);
207                     LOG.info("Setting uuid condition {} ", existingUUID);
208                     selectOperation.where(table.getUuidColumn().getSchema().opEqual(existingUUID));
209                 } else {
210                     if (whereClauseGetterMap.get(cls) != null) {
211                         List<Condition> conditions = whereClauseGetterMap.get(cls).apply(iid);
212                         if (conditions != null) {
213                             if (conditions.size() == 2) {
214                                 selectOperation.where(conditions.get(0)).and(conditions.get(1));
215                             } else {
216                                 selectOperation.where(conditions.get(0));
217                             }
218                         } else {
219                             LOG.error("Could not get where conditions for cls {} key {}", cls, iid);
220                             return Optional.empty();
221                         }
222                     } else {
223                         LOG.error("Could not get where class for cls {} ", cls);
224                         return Optional.empty();
225                     }
226                 }
227                 ArrayList<Operation> operations = new ArrayList<>();
228                 operations.add(selectOperation);
229                 try {
230                     List<OperationResult> results = connectionInstance.transact(dbSchema, operations).get();
231                     if (results != null && !results.isEmpty()) {
232                         OperationResult selectResult = results.get(0);
233                         if (selectResult.getRows() != null && !selectResult.getRows().isEmpty()) {
234                             globalRow = TyperUtils.getTypedRowWrapper(
235                                     dbSchema, tableClass, selectResult.getRows().get(0));
236                         }
237                     }
238                 } catch (InterruptedException | ExecutionException e) {
239                     LOG.warn("Not able to fetch hardware_vtep table row from device {}",
240                             connectionInstance.getConnectionInfo(), e);
241                 }
242             }
243             LOG.trace("Fetched {} from hardware_vtep schema", globalRow);
244             if (globalRow != null && globalRow.getUuid() != null) {
245                 return Optional.of(globalRow);
246             }
247             return Optional.empty();
248         } catch (Throwable e) {
249             LOG.error("Failed to get the hwvtep row for iid {} {} ", iid, e);
250             return Optional.empty();
251         }
252     }
253
254     public List<TypedBaseTable> getHwvtepTableEntries(Class<? extends Identifiable> cls) {
255         try {
256             List<TypedBaseTable> tableRows = new ArrayList<>();
257             DatabaseSchema dbSchema = null;
258             TypedBaseTable globalRow = null;
259             Class<TypedBaseTable> tableClass = tableMap.get(cls);
260             try {
261                 dbSchema = connectionInstance.getSchema(HwvtepSchemaConstants.HARDWARE_VTEP).get();
262             } catch (InterruptedException | ExecutionException e) {
263                 LOG.error("Not able to fetch schema for database {} from device {}",
264                         HwvtepSchemaConstants.HARDWARE_VTEP, connectionInstance.getConnectionInfo(), e);
265             }
266
267             if (dbSchema != null) {
268                 GenericTableSchema hwvtepSchema = TyperUtils.getTableSchema(dbSchema, tableClass);
269
270                 List<String> hwvtepTableColumn = new ArrayList<>();
271                 hwvtepTableColumn.addAll(hwvtepSchema.getColumns());
272                 Select<GenericTableSchema> selectOperation = op.select(hwvtepSchema);
273                 selectOperation.setColumns(hwvtepTableColumn);
274
275                 ArrayList<Operation> operations = Lists.newArrayList(selectOperation);
276                 try {
277                     List<OperationResult> results = connectionInstance.transact(dbSchema, operations).get();
278                     if (results != null && !results.isEmpty()) {
279                         for (OperationResult selectResult : results) {
280                             if (selectResult.getRows() != null && !selectResult.getRows().isEmpty()) {
281                                 for (Row<GenericTableSchema> row : selectResult.getRows()) {
282                                     tableRows.add(TyperUtils.getTypedRowWrapper(dbSchema, tableClass, row));
283                                 }
284                             }
285                         }
286                     }
287                 } catch (InterruptedException | ExecutionException e) {
288                     LOG.error("Not able to fetch hardware_vtep table row from device {}",
289                             connectionInstance.getConnectionInfo(), e);
290                 }
291             }
292             return tableRows;
293         } catch (Throwable e) {
294             LOG.error("Failed to get the hwvtep ", e);
295         }
296         return Collections.emptyList();
297     }
298
299     public TableUpdates readAllTables() throws ExecutionException, InterruptedException {
300         Map<String, TableUpdate> tableUpdates =  new HashMap<>();
301         DatabaseSchema dbSchema = connectionInstance.getSchema(HwvtepSchemaConstants.HARDWARE_VTEP).get();
302
303         List<Operation> operations = Arrays.asList(alltables).stream()
304                 .map(tableClass -> TyperUtils.getTableSchema(dbSchema, tableClass))
305                 .map(tableSchema -> buildSelectOperationFor(tableSchema))
306                 .collect(Collectors.toList());
307
308         List<OperationResult> results = connectionInstance.transact(dbSchema, operations).get();
309         if (results != null && !results.isEmpty()) {
310             results.stream()
311                     .filter(result -> result.getRows() != null)
312                     .flatMap(result -> result.getRows().stream())
313                     .forEach(row -> {
314                         tableUpdates.compute(row.getTableSchema().getName(), (tableName, tableUpdate) -> {
315                             if (tableUpdate == null) {
316                                 tableUpdate = new TableUpdate();
317                             }
318                             tableUpdate.addRow(getRowUuid(row), null, row);
319                             return tableUpdate;
320                         });
321                     });
322         }
323         return new TableUpdates(tableUpdates);
324     }
325
326     private Select<GenericTableSchema> buildSelectOperationFor(GenericTableSchema tableSchema) {
327         Select<GenericTableSchema> selectOpearation = op.select(tableSchema);
328         selectOpearation.setColumns(new ArrayList<>(tableSchema.getColumns()));
329         return selectOpearation;
330     }
331
332     private UUID getRowUuid(Row<GenericTableSchema> row) {
333         return row.getColumns().stream()
334                 .filter(column -> column.getSchema().getName().equals("_uuid"))
335                 .map(column -> (UUID) column.getData())
336                 .findFirst().orElse(new UUID("test"));
337     }
338 }