re base code
[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 com.thinkaurelius.titan.core.TitanVertex;
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.TitanDao;
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.titan.TitanOperationStatus;
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.datatypes.tosca.ToscaDataDefinition;
51 import org.openecomp.sdc.be.model.Component;
52 import org.openecomp.sdc.be.model.ComponentParametersView;
53 import org.openecomp.sdc.be.model.Service;
54 import org.openecomp.sdc.be.model.User;
55 import org.openecomp.sdc.be.model.jsontitan.operations.ForwardingPathOperation;
56 import org.openecomp.sdc.be.model.jsontitan.operations.ToscaOperationFacade;
57 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
58 import org.openecomp.sdc.be.model.operations.impl.DaoStatusConverter;
59 import org.openecomp.sdc.be.model.operations.impl.UserAdminOperation;
60
61 @org.springframework.stereotype.Component
62 public class ForwardPathMigration implements Migration {
63
64     private TitanDao titanDao;
65     private UserAdminOperation userAdminOperation;
66     private ToscaOperationFacade toscaOperationFacade;
67     private User user = null;
68
69     public ForwardPathMigration(TitanDao titanDao,
70         UserAdminOperation userAdminOperation, ToscaOperationFacade toscaOperationFacade) {
71         this.titanDao = titanDao;
72         this.userAdminOperation = userAdminOperation;
73         this.toscaOperationFacade = toscaOperationFacade;
74     }
75
76     @Override
77     public String description() {
78         return "remove corrupted forwarding paths ";
79     }
80
81     @Override
82     public DBVersion getVersion() {
83         return DBVersion.from(BigInteger.valueOf(1806), BigInteger.valueOf(0));
84     }
85
86     @Override
87     public MigrationResult migrate() {
88         final String userId = ConfigurationManager.getConfigurationManager().getConfiguration().getAutoHealingOwner();
89
90         Either<User, ActionStatus> userData = (Either<User, ActionStatus>) userAdminOperation
91             .getUserData(userId, false);
92         if (userData.isRight()) {
93              return MigrationResult.error(
94                 "failed to delete unused forwarding paths. Failed to resolve user : " + userId + " error " + userData
95                     .right().value());
96         } else {
97             user = userData.left().value();
98         }
99         StorageOperationStatus status = cleanAllServices();
100
101         return status == StorageOperationStatus.OK ? MigrationResult.success()
102             : MigrationResult.error("failed to remove corrupted forwarding paths . Error : " + status);
103
104     }
105
106     private StorageOperationStatus cleanAllServices() {
107         StorageOperationStatus status;
108
109         Map<GraphPropertyEnum, Object> hasProps = new EnumMap<>(GraphPropertyEnum.class);
110         hasProps.put(GraphPropertyEnum.COMPONENT_TYPE, ComponentTypeEnum.SERVICE.name());
111         Map<GraphPropertyEnum, Object> hasNotProps = new HashMap<>();
112         hasNotProps.put(GraphPropertyEnum.IS_DELETED, true);
113         status = titanDao
114             .getByCriteria(VertexTypeEnum.TOPOLOGY_TEMPLATE, hasProps, hasNotProps, JsonParseFlagEnum.ParseAll)
115             .either(this::cleanServices, this::handleError);
116         return status;
117     }
118
119     private StorageOperationStatus cleanServices(List<GraphVertex> containersV) {
120         StorageOperationStatus status = StorageOperationStatus.OK;
121         for (GraphVertex container : containersV) {
122             ComponentParametersView componentParametersView = new ComponentParametersView();
123             componentParametersView.setIgnoreComponentInstances(false);
124             componentParametersView.setIgnoreCapabilities(false);
125             componentParametersView.setIgnoreRequirements(false);
126             componentParametersView.setIgnoreForwardingPath(false);
127             Either<Component, StorageOperationStatus> toscaElement = toscaOperationFacade
128                 .getToscaElement(container.getUniqueId(), componentParametersView);
129             if (toscaElement.isRight()) {
130                 return toscaElement.right().value();
131             }
132             status = fixDataOnGraph(toscaElement.left().value());
133             if (status != StorageOperationStatus.OK) {
134                 break;
135             }
136         }
137         return status;
138     }
139
140
141     private StorageOperationStatus handleError(TitanOperationStatus err) {
142         titanDao.rollback();
143         return DaoStatusConverter
144             .convertTitanStatusToStorageStatus(TitanOperationStatus.NOT_FOUND == err ? TitanOperationStatus.OK : err);
145     }
146
147     private StorageOperationStatus fixDataOnGraph(Component component) {
148         if (!(component instanceof Service)){
149             return StorageOperationStatus.OK;
150         }
151         Service service = (Service) component;
152         Either<GraphVertex, TitanOperationStatus> getResponse = titanDao.getVertexById(service.getUniqueId(),
153             JsonParseFlagEnum.NoParse);
154         if (getResponse.isRight()) {
155             return DaoStatusConverter.convertTitanStatusToStorageStatus(getResponse.right().value());
156
157         }
158         Set<String> ciNames = new HashSet<>();
159         if (service.getComponentInstances() != null && !service.getComponentInstances().isEmpty()) {
160             ciNames = service.getComponentInstances().stream().map(ci -> ci.getName())
161                 .collect(Collectors.toSet());
162         }
163         GraphVertex componentVertex = getResponse.left().value();
164
165         GraphVertex toscaDataVertex;
166         Either<GraphVertex, TitanOperationStatus> groupVertexEither = titanDao.getChildVertex(componentVertex,
167             EdgeLabelEnum.FORWARDING_PATH, JsonParseFlagEnum.ParseJson);
168         if (groupVertexEither.isRight() && groupVertexEither.right().value() == TitanOperationStatus.NOT_FOUND) {
169             return StorageOperationStatus.OK;
170         }
171         if (groupVertexEither.isRight()) {
172             return DaoStatusConverter.convertTitanStatusToStorageStatus(groupVertexEither.right().value());
173         }
174         toscaDataVertex = groupVertexEither.left().value();
175         Map<String, ForwardingPathDataDefinition> forwardingPaths = new HashMap<>(
176             (Map<String, ForwardingPathDataDefinition>) toscaDataVertex.getJson());
177         List<String> toBeDeletedFP = new ArrayList<>();
178         for (Map.Entry<String, ForwardingPathDataDefinition> forwardingPathDataDefinition : forwardingPaths
179             .entrySet()) {
180             Set<String> nodeNames = forwardingPathDataDefinition.getValue().getPathElements()
181                 .getListToscaDataDefinition()
182                 .stream().map(element -> ImmutableSet.of(element.getFromNode(), element.getToNode()))
183                 .flatMap(set -> set.stream()).collect(Collectors.toSet());
184             if (!ciNames.containsAll(nodeNames)) {
185                 toBeDeletedFP.add(forwardingPathDataDefinition.getKey());
186             }
187         }
188         if (toBeDeletedFP.isEmpty()) {
189             titanDao.rollback();
190             return StorageOperationStatus.OK;
191         }
192         toBeDeletedFP.stream().forEach(fpKey -> forwardingPaths.remove(fpKey));
193         toscaDataVertex.setJson(forwardingPaths);
194         Either<GraphVertex, TitanOperationStatus> updatevertexEither = updateOrCopyOnUpdate(
195              toscaDataVertex, componentVertex);
196           if (updatevertexEither.isRight()) {
197             titanDao.rollback();
198             return DaoStatusConverter.convertTitanStatusToStorageStatus(updatevertexEither.right().value());
199         }
200         titanDao.commit();
201         return StorageOperationStatus.OK;
202     }
203
204     private Either<GraphVertex, TitanOperationStatus> cloneDataVertex(GraphVertex dataVertex, GraphVertex toscaElementVertex, Edge edgeToRemove) {
205         EdgeLabelEnum label =  EdgeLabelEnum.FORWARDING_PATH;
206         GraphVertex newDataVertex = new GraphVertex(dataVertex.getLabel());
207         String id = IdBuilderUtils.generateChildId(toscaElementVertex.getUniqueId(), dataVertex.getLabel());
208         newDataVertex.cloneData(dataVertex);
209         newDataVertex.setUniqueId(id);
210
211         Either<GraphVertex, TitanOperationStatus> createVertex = titanDao.createVertex(newDataVertex);
212         if (createVertex.isRight()) {
213             return createVertex;
214         }
215         newDataVertex = createVertex.left().value();
216         TitanOperationStatus createEdge = titanDao.createEdge(toscaElementVertex, newDataVertex, label, titanDao.getEdgeProperties(edgeToRemove));
217         if (createEdge != TitanOperationStatus.OK) {
218                 return Either.right(createEdge);
219         }
220         edgeToRemove.remove();
221         return Either.left(newDataVertex);
222     }
223
224     private Either<GraphVertex, TitanOperationStatus> updateOrCopyOnUpdate(GraphVertex dataVertex, GraphVertex toscaElementVertex ) {
225         EdgeLabelEnum label = EdgeLabelEnum.FORWARDING_PATH;
226         Iterator<Edge> edges = dataVertex.getVertex().edges(Direction.IN, label.name());
227         int edgeCount = 0;
228         Edge edgeToRemove = null;
229         while (edges.hasNext()) {
230             Edge edge = edges.next();
231             ++edgeCount;
232             Vertex outVertex = edge.outVertex();
233             String outId = (String) titanDao.getProperty((TitanVertex) outVertex, GraphPropertyEnum.UNIQUE_ID.getProperty());
234             if (toscaElementVertex.getUniqueId().equals(outId)) {
235                 edgeToRemove = edge;
236             }
237         }
238         if (edgeToRemove == null) {
239             return Either.right(TitanOperationStatus.GENERAL_ERROR);
240         }
241         switch (edgeCount) {
242             case 0:
243                 // error
244                  return Either.right(TitanOperationStatus.GENERAL_ERROR);
245             case 1:
246                 // update
247                 return titanDao.updateVertex(dataVertex);
248             default:
249                 // copy on update
250                 return cloneDataVertex(dataVertex, toscaElementVertex,  edgeToRemove);
251         }
252     }
253 }