Upgrade SDC from Titan to Janus Graph
[sdc.git] / asdctool / src / main / java / org / openecomp / sdc / asdctool / migration / tasks / mig1806 / ForwardPathMigration.java
1 /*
2  * Copyright © 2016-2018 European Support Limited
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package org.openecomp.sdc.asdctool.migration.tasks.mig1806;
18
19 import com.google.common.collect.ImmutableSet;
20 import org.janusgraph.core.JanusGraphVertex;
21 import fj.data.Either;
22 import java.math.BigInteger;
23 import java.util.ArrayList;
24 import java.util.EnumMap;
25 import java.util.HashMap;
26 import java.util.HashSet;
27 import java.util.Iterator;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.Set;
31 import java.util.stream.Collectors;
32 import org.apache.tinkerpop.gremlin.structure.Direction;
33 import org.apache.tinkerpop.gremlin.structure.Edge;
34 import org.apache.tinkerpop.gremlin.structure.Vertex;
35 import org.openecomp.sdc.asdctool.migration.core.DBVersion;
36 import org.openecomp.sdc.asdctool.migration.core.task.Migration;
37 import org.openecomp.sdc.asdctool.migration.core.task.MigrationResult;
38 import org.openecomp.sdc.be.config.ConfigurationManager;
39 import org.openecomp.sdc.be.dao.api.ActionStatus;
40 import org.openecomp.sdc.be.dao.jsongraph.GraphVertex;
41 import org.openecomp.sdc.be.dao.jsongraph.JanusGraphDao;
42 import org.openecomp.sdc.be.dao.jsongraph.types.EdgeLabelEnum;
43 import org.openecomp.sdc.be.dao.jsongraph.types.JsonParseFlagEnum;
44 import org.openecomp.sdc.be.dao.jsongraph.types.VertexTypeEnum;
45 import org.openecomp.sdc.be.dao.jsongraph.utils.IdBuilderUtils;
46 import org.openecomp.sdc.be.dao.janusgraph.JanusGraphOperationStatus;
47 import org.openecomp.sdc.be.datatypes.elements.ForwardingPathDataDefinition;
48 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
49 import org.openecomp.sdc.be.datatypes.enums.GraphPropertyEnum;
50 import org.openecomp.sdc.be.model.Component;
51 import org.openecomp.sdc.be.model.ComponentParametersView;
52 import org.openecomp.sdc.be.model.Service;
53 import org.openecomp.sdc.be.model.User;
54 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ToscaOperationFacade;
55 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
56 import org.openecomp.sdc.be.model.operations.impl.DaoStatusConverter;
57 import org.openecomp.sdc.be.model.operations.impl.UserAdminOperation;
58
59 @org.springframework.stereotype.Component
60 public class ForwardPathMigration implements Migration {
61
62     private JanusGraphDao janusGraphDao;
63     private UserAdminOperation userAdminOperation;
64     private ToscaOperationFacade toscaOperationFacade;
65     private User user = null;
66
67     public ForwardPathMigration(JanusGraphDao janusGraphDao,
68         UserAdminOperation userAdminOperation, ToscaOperationFacade toscaOperationFacade) {
69         this.janusGraphDao = janusGraphDao;
70         this.userAdminOperation = userAdminOperation;
71         this.toscaOperationFacade = toscaOperationFacade;
72     }
73
74     @Override
75     public String description() {
76         return "remove corrupted forwarding paths ";
77     }
78
79     @Override
80     public DBVersion getVersion() {
81         return DBVersion.from(BigInteger.valueOf(1806), BigInteger.valueOf(0));
82     }
83
84     @Override
85     public MigrationResult migrate() {
86         final String userId = ConfigurationManager.getConfigurationManager().getConfiguration().getAutoHealingOwner();
87
88         Either<User, ActionStatus> userData = (Either<User, ActionStatus>) userAdminOperation
89             .getUserData(userId, false);
90         if (userData.isRight()) {
91              return MigrationResult.error(
92                 "failed to delete unused forwarding paths. Failed to resolve user : " + userId + " error " + userData
93                     .right().value());
94         } else {
95             user = userData.left().value();
96         }
97         StorageOperationStatus status = cleanAllServices();
98
99         return status == StorageOperationStatus.OK ? MigrationResult.success()
100             : MigrationResult.error("failed to remove corrupted forwarding paths . Error : " + status);
101
102     }
103
104     private StorageOperationStatus cleanAllServices() {
105         StorageOperationStatus status;
106
107         Map<GraphPropertyEnum, Object> hasProps = new EnumMap<>(GraphPropertyEnum.class);
108         hasProps.put(GraphPropertyEnum.COMPONENT_TYPE, ComponentTypeEnum.SERVICE.name());
109         Map<GraphPropertyEnum, Object> hasNotProps = new HashMap<>();
110         hasNotProps.put(GraphPropertyEnum.IS_DELETED, true);
111         status = janusGraphDao
112             .getByCriteria(VertexTypeEnum.TOPOLOGY_TEMPLATE, hasProps, hasNotProps, JsonParseFlagEnum.ParseAll)
113             .either(this::cleanServices, this::handleError);
114         return status;
115     }
116
117     private StorageOperationStatus cleanServices(List<GraphVertex> containersV) {
118         StorageOperationStatus status = StorageOperationStatus.OK;
119         for (GraphVertex container : containersV) {
120             ComponentParametersView componentParametersView = new ComponentParametersView();
121             componentParametersView.setIgnoreComponentInstances(false);
122             componentParametersView.setIgnoreCapabilities(false);
123             componentParametersView.setIgnoreRequirements(false);
124             componentParametersView.setIgnoreForwardingPath(false);
125             Either<Component, StorageOperationStatus> toscaElement = toscaOperationFacade
126                 .getToscaElement(container.getUniqueId(), componentParametersView);
127             if (toscaElement.isRight()) {
128                 return toscaElement.right().value();
129             }
130             status = fixDataOnGraph(toscaElement.left().value());
131             if (status != StorageOperationStatus.OK) {
132                 break;
133             }
134         }
135         return status;
136     }
137
138
139     private StorageOperationStatus handleError(JanusGraphOperationStatus err) {
140         janusGraphDao.rollback();
141         return DaoStatusConverter
142             .convertJanusGraphStatusToStorageStatus(
143                 JanusGraphOperationStatus.NOT_FOUND == err ? JanusGraphOperationStatus.OK : err);
144     }
145
146     private StorageOperationStatus fixDataOnGraph(Component component) {
147         if (!(component instanceof Service)){
148             return StorageOperationStatus.OK;
149         }
150         Service service = (Service) component;
151         Either<GraphVertex, JanusGraphOperationStatus> getResponse = janusGraphDao.getVertexById(service.getUniqueId(),
152             JsonParseFlagEnum.NoParse);
153         if (getResponse.isRight()) {
154             return DaoStatusConverter.convertJanusGraphStatusToStorageStatus(getResponse.right().value());
155
156         }
157         Set<String> ciNames = new HashSet<>();
158         if (service.getComponentInstances() != null && !service.getComponentInstances().isEmpty()) {
159             ciNames = service.getComponentInstances().stream().map(ci -> ci.getName())
160                 .collect(Collectors.toSet());
161         }
162         GraphVertex componentVertex = getResponse.left().value();
163
164         GraphVertex toscaDataVertex;
165         Either<GraphVertex, JanusGraphOperationStatus> groupVertexEither = janusGraphDao.getChildVertex(componentVertex,
166             EdgeLabelEnum.FORWARDING_PATH, JsonParseFlagEnum.ParseJson);
167         if (groupVertexEither.isRight() && groupVertexEither.right().value() == JanusGraphOperationStatus.NOT_FOUND) {
168             return StorageOperationStatus.OK;
169         }
170         if (groupVertexEither.isRight()) {
171             return DaoStatusConverter.convertJanusGraphStatusToStorageStatus(groupVertexEither.right().value());
172         }
173         toscaDataVertex = groupVertexEither.left().value();
174         Map<String, ForwardingPathDataDefinition> forwardingPaths = new HashMap<>(
175             (Map<String, ForwardingPathDataDefinition>) toscaDataVertex.getJson());
176         List<String> toBeDeletedFP = new ArrayList<>();
177         for (Map.Entry<String, ForwardingPathDataDefinition> forwardingPathDataDefinition : forwardingPaths
178             .entrySet()) {
179             Set<String> nodeNames = forwardingPathDataDefinition.getValue().getPathElements()
180                 .getListToscaDataDefinition()
181                 .stream().map(element -> ImmutableSet.of(element.getFromNode(), element.getToNode()))
182                 .flatMap(set -> set.stream()).collect(Collectors.toSet());
183             if (!ciNames.containsAll(nodeNames)) {
184                 toBeDeletedFP.add(forwardingPathDataDefinition.getKey());
185             }
186         }
187         if (toBeDeletedFP.isEmpty()) {
188             janusGraphDao.rollback();
189             return StorageOperationStatus.OK;
190         }
191         toBeDeletedFP.stream().forEach(fpKey -> forwardingPaths.remove(fpKey));
192         toscaDataVertex.setJson(forwardingPaths);
193         Either<GraphVertex, JanusGraphOperationStatus> updatevertexEither = updateOrCopyOnUpdate(
194              toscaDataVertex, componentVertex);
195           if (updatevertexEither.isRight()) {
196             janusGraphDao.rollback();
197             return DaoStatusConverter.convertJanusGraphStatusToStorageStatus(updatevertexEither.right().value());
198         }
199         janusGraphDao.commit();
200         return StorageOperationStatus.OK;
201     }
202
203     private Either<GraphVertex, JanusGraphOperationStatus> cloneDataVertex(GraphVertex dataVertex, GraphVertex toscaElementVertex, Edge edgeToRemove) {
204         EdgeLabelEnum label =  EdgeLabelEnum.FORWARDING_PATH;
205         GraphVertex newDataVertex = new GraphVertex(dataVertex.getLabel());
206         String id = IdBuilderUtils.generateChildId(toscaElementVertex.getUniqueId(), dataVertex.getLabel());
207         newDataVertex.cloneData(dataVertex);
208         newDataVertex.setUniqueId(id);
209
210         Either<GraphVertex, JanusGraphOperationStatus> createVertex = janusGraphDao.createVertex(newDataVertex);
211         if (createVertex.isRight()) {
212             return createVertex;
213         }
214         newDataVertex = createVertex.left().value();
215         JanusGraphOperationStatus
216             createEdge = janusGraphDao
217             .createEdge(toscaElementVertex, newDataVertex, label, janusGraphDao.getEdgeProperties(edgeToRemove));
218         if (createEdge != JanusGraphOperationStatus.OK) {
219                 return Either.right(createEdge);
220         }
221         edgeToRemove.remove();
222         return Either.left(newDataVertex);
223     }
224
225     private Either<GraphVertex, JanusGraphOperationStatus> updateOrCopyOnUpdate(GraphVertex dataVertex, GraphVertex toscaElementVertex ) {
226         EdgeLabelEnum label = EdgeLabelEnum.FORWARDING_PATH;
227         Iterator<Edge> edges = dataVertex.getVertex().edges(Direction.IN, label.name());
228         int edgeCount = 0;
229         Edge edgeToRemove = null;
230         while (edges.hasNext()) {
231             Edge edge = edges.next();
232             ++edgeCount;
233             Vertex outVertex = edge.outVertex();
234             String outId = (String) janusGraphDao
235                 .getProperty((JanusGraphVertex) outVertex, GraphPropertyEnum.UNIQUE_ID.getProperty());
236             if (toscaElementVertex.getUniqueId().equals(outId)) {
237                 edgeToRemove = edge;
238             }
239         }
240         if (edgeToRemove == null) {
241             return Either.right(JanusGraphOperationStatus.GENERAL_ERROR);
242         }
243         switch (edgeCount) {
244             case 0:
245                 // error
246                  return Either.right(JanusGraphOperationStatus.GENERAL_ERROR);
247             case 1:
248                 // update
249                 return janusGraphDao.updateVertex(dataVertex);
250             default:
251                 // copy on update
252                 return cloneDataVertex(dataVertex, toscaElementVertex,  edgeToRemove);
253         }
254     }
255 }