[SDC] rebase 1710 code

Change-Id: I532ed68979fee7840ea8a5395e7e965b155fb9f9
Signed-off-by: Michael Lando <ml636r@att.com>
diff --git a/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1604/ServiceMigration.java b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1604/ServiceMigration.java
index ee5171d..0ef435e 100644
--- a/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1604/ServiceMigration.java
+++ b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1604/ServiceMigration.java
@@ -706,7 +706,7 @@
 		Either<ImmutablePair<ComponentInstanceData, GraphEdge>, TitanOperationStatus> reqInst = titanGenericDao.getParentNode(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.RelationshipInst), rel.getUniqueId(), GraphEdgeLabels.RELATIONSHIP_INST,
 				NodeTypeEnum.ResourceInstance, ComponentInstanceData.class);
 		if (reqInst.isRight()) {
-			log.debug("updateRelations : failed to fetch capabilty component instance for relation {}, error {}", rel.getUniqueId(), reqInst.right().value());
+			log.debug("updateRelations : failed to fetch capability component instance for relation {}, error {}", rel.getUniqueId(), reqInst.right().value());
 			return false;
 		}
 		ComponentInstanceData requirementInstanceData = reqInst.left().value().getLeft();
@@ -917,6 +917,9 @@
 			case CP:
 				originType = OriginTypeEnum.CP;
 				break;
+			case CVFC:
+				originType = OriginTypeEnum.CVFC;
+				break;
 			default:
 				log.debug("updateComponentInstanceType failed, no supported resource type {} for origin resource with id {}", resourceType, originId);
 				return false;
diff --git a/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/Migration1707ArtifactUuidFix.java b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/Migration1707ArtifactUuidFix.java
index c14301a..b3f1382 100644
--- a/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/Migration1707ArtifactUuidFix.java
+++ b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/Migration1707ArtifactUuidFix.java
@@ -103,10 +103,10 @@
 		if (runMode.equals("fix") || runMode.equals("fix_only_services")) {
 			log.info("Mode {}. Start fix", runMode);
 			if (fix(vfLst, serviceList) == false) {
-				log.info("Mode {}. Fix finished withh failure", runMode);
+				log.info("Mode {}. Fix finished with failure", runMode);
 				return false;
 			}
-			log.info("Mode {}. Fix finished withh success", runMode);
+			log.info("Mode {}. Fix finished with success", runMode);
 		}
 
 		return true;
diff --git a/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/Migration1707Config.java b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/Migration1707Config.java
index 21a6ae1..36919d7 100644
--- a/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/Migration1707Config.java
+++ b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/Migration1707Config.java
@@ -271,4 +271,9 @@
     	return new NodeTemplateMissingDataResolver<>();
     }
 
+    @Bean(name = "migration1707MissingInfoFix")
+    public Migration1707MissingInfoFix migration1707MissingInfoFix() {
+        return new Migration1707MissingInfoFix();
+    }
+
 }
diff --git a/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/Migration1707MissingInfoFix.java b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/Migration1707MissingInfoFix.java
new file mode 100644
index 0000000..ff41f12
--- /dev/null
+++ b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/Migration1707MissingInfoFix.java
@@ -0,0 +1,220 @@
+package org.openecomp.sdc.asdctool.impl.migration.v1707;
+
+import fj.data.Either;
+import org.openecomp.sdc.asdctool.impl.migration.v1707.jsonmodel.NodeTemplateMissingDataResolver;
+import org.openecomp.sdc.be.dao.jsongraph.GraphVertex;
+import org.openecomp.sdc.be.dao.jsongraph.TitanDao;
+import org.openecomp.sdc.be.dao.jsongraph.types.EdgeLabelEnum;
+import org.openecomp.sdc.be.dao.jsongraph.types.JsonParseFlagEnum;
+import org.openecomp.sdc.be.dao.jsongraph.types.VertexTypeEnum;
+import org.openecomp.sdc.be.dao.titan.TitanOperationStatus;
+import org.openecomp.sdc.be.datatypes.elements.*;
+import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
+import org.openecomp.sdc.be.datatypes.enums.GraphPropertyEnum;
+import org.openecomp.sdc.be.datatypes.enums.OriginTypeEnum;
+import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum;
+import org.openecomp.sdc.be.datatypes.tosca.ToscaDataDefinition;
+import org.openecomp.sdc.be.model.*;
+import org.openecomp.sdc.be.model.jsontitan.datamodel.ToscaElement;
+import org.openecomp.sdc.be.model.jsontitan.enums.JsonConstantKeysEnum;
+import org.openecomp.sdc.be.model.jsontitan.operations.ToscaOperationFacade;
+import org.openecomp.sdc.be.model.operations.api.IServiceOperation;
+import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.annotation.Resource;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+@org.springframework.stereotype.Component("migration1707MissingInfoFix")
+public class Migration1707MissingInfoFix {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(Migration1707MissingInfoFix.class);
+
+    @Resource(name = "service-operation")
+    private IServiceOperation serviceOperation;
+
+    @Resource(name = "node-template-missing-data-resolver")
+    private NodeTemplateMissingDataResolver nodeTemplateMissingDataResolver;
+
+    @Resource(name = "tosca-operation-facade")
+    private ToscaOperationFacade toscaOperations;
+
+    @Resource(name = "titan-dao")
+    private TitanDao titanDao;
+
+
+    public boolean migrate(){
+        boolean res = updateVFs();
+        if(res)
+            res = updateServices();
+        return res;
+    }
+
+    private ComponentParametersView getFilter() {
+        ComponentParametersView filter = new ComponentParametersView(true);
+        filter.setIgnoreComponentInstances(false);
+        filter.setIgnoreArtifacts(false);
+        filter.setIgnoreGroups(false);
+        filter.setIgnoreComponentInstancesInputs(false);
+        return filter;
+    }
+
+    // if new service has VF instances with no groups - try to fetch them from old graph
+    private boolean oldServiceModelRequired(Component newService) {
+        Predicate<ComponentInstance> vfInstanceWithNoGroups = p -> OriginTypeEnum.VF == p.getOriginType() && (null == p.getGroupInstances() || p.getGroupInstances().isEmpty());
+        return null != newService.getComponentInstances() && newService.getComponentInstances().stream()
+                .anyMatch(vfInstanceWithNoGroups);
+    }
+
+
+
+    private List<GraphVertex> fetchVertices(Map<GraphPropertyEnum, Object> hasProps){
+        Either<List<GraphVertex>, TitanOperationStatus> componentsByCriteria = titanDao.getByCriteria(VertexTypeEnum.TOPOLOGY_TEMPLATE, hasProps, JsonParseFlagEnum.ParseAll);
+        if (componentsByCriteria.isRight()) {
+            LOGGER.debug("couldn't fetch assets from sdctitan");
+            return null;
+        }
+        return componentsByCriteria.left().value();
+    }
+
+    private boolean updateVFs() {
+
+        boolean res = true;
+        Map<GraphPropertyEnum, Object> hasProps = new HashMap<>();
+        hasProps.put(GraphPropertyEnum.COMPONENT_TYPE, ComponentTypeEnum.RESOURCE.name());
+        hasProps.put(GraphPropertyEnum.RESOURCE_TYPE, ResourceTypeEnum.VF.name());
+
+        List<GraphVertex> resources = fetchVertices(hasProps);
+        if(null == resources)
+            return false;
+        ComponentParametersView filter = getFilter();
+        Map<String, ToscaElement> origCompMap = new HashMap<>();
+
+        for (GraphVertex gv : resources) {
+            boolean fixed = true;
+            Either<Component, StorageOperationStatus> toscaElement = toscaOperations.getToscaElement(gv.getUniqueId(), filter);
+            if (toscaElement.isRight()) {
+                LOGGER.debug("Failed to fetch resource {} {}", gv.getUniqueId(), toscaElement.right().value());
+                return false;
+            }
+            Component resource = toscaElement.left().value();
+            Map<String, Boolean> updateMap = new HashMap<>();
+            nodeTemplateMissingDataResolver.updateVFComposition(resource, origCompMap, updateMap);
+            if(updateMap.get(JsonConstantKeysEnum.COMPOSITION.name())){
+                LOGGER.info("applying instance tosca name fix on VF {}", gv.getUniqueId());
+                fixed = toscaOperations.updateComponentInstanceMetadataOfTopologyTemplate(resource).isLeft();
+            }
+            if(updateMap.get(EdgeLabelEnum.GROUPS.name())) {
+                List<GroupDataDefinition> groups = new ArrayList<>(resource.getGroups());
+                LOGGER.info("applying groups vertex fix on VF {}", gv.getUniqueId());
+                fixed = fixed && toscaOperations.updateGroupsOnComponent(resource, ComponentTypeEnum.RESOURCE, groups).isLeft();
+            }
+
+            res = res && fixed;
+            titanDao.commit();
+        }
+        return res;
+    }
+
+    private Map<String, MapPropertiesDataDefinition> buildInstancesInputsMap(Component component){
+        Map<String, MapPropertiesDataDefinition> instanceInputsMap = new HashMap<>();
+        for (Map.Entry<String, List<ComponentInstanceInput>> entry : component.getComponentInstancesInputs().entrySet()) {
+            MapPropertiesDataDefinition inputsMap = new MapPropertiesDataDefinition();
+            inputsMap.setMapToscaDataDefinition(entry.getValue().stream().map(e -> new PropertyDataDefinition(e)).collect(Collectors.toMap(e -> e.getName(), e -> e)));
+            instanceInputsMap.put(entry.getKey(), inputsMap);
+        }
+        return instanceInputsMap;
+    }
+
+
+
+    private Map<String, MapGroupsDataDefinition> buildGroupInstanceMap(Component component) {
+        Map<String, MapGroupsDataDefinition> instGroupsMap = new HashMap<>();
+        for (ComponentInstance instance : component.getComponentInstances()) {
+            if (instance.getGroupInstances() != null) {
+                MapGroupsDataDefinition groupsMap = new MapGroupsDataDefinition();
+                groupsMap.setMapToscaDataDefinition(instance.getGroupInstances().stream().map(e -> new GroupInstanceDataDefinition(e)).collect(Collectors.toMap(e -> e.getName(), e -> e)));
+                instGroupsMap.put(instance.getUniqueId(), groupsMap);
+            }
+        }
+        return instGroupsMap;
+    }
+
+    private <T extends ToscaDataDefinition> boolean updateDataVertex(GraphVertex componentVertex, VertexTypeEnum vertexType, EdgeLabelEnum edgeLabel, Map<String, T> dataMap){
+        Either<GraphVertex, TitanOperationStatus> dataVertexEither = titanDao.getChildVertex(componentVertex, edgeLabel, JsonParseFlagEnum.ParseJson);
+        if (dataVertexEither.isRight()) {
+            if(TitanOperationStatus.NOT_FOUND != dataVertexEither.right().value())
+                return false;
+            return (nodeTemplateMissingDataResolver.topologyTemplateOperation.assosiateElementToData(componentVertex, vertexType, edgeLabel, dataMap)).isLeft();
+        }
+        GraphVertex dataVertex = dataVertexEither.left().value();
+        dataVertex.setJson(dataMap);
+        return (titanDao.updateVertex(dataVertex)).isLeft();
+
+    }
+
+
+    private boolean updateServices(){
+
+        boolean res = true;
+        Map<GraphPropertyEnum, Object> hasProps = new HashMap<>();
+        hasProps.put(GraphPropertyEnum.COMPONENT_TYPE, ComponentTypeEnum.SERVICE.name());
+
+        List<GraphVertex> componentsByCriteria = fetchVertices(hasProps);
+        if(null == componentsByCriteria)
+            return false;
+
+        ComponentParametersView filter = getFilter();
+        Map<String, ToscaElement> origCompMap = new HashMap<>();
+
+        Predicate<ComponentInstance> containsGroupInstances = p -> null != p.getGroupInstances() && !p.getGroupInstances().isEmpty();
+
+        for (GraphVertex gv : componentsByCriteria) {
+
+            boolean fixed = true;
+            Either<org.openecomp.sdc.be.model.Service, StorageOperationStatus> toscaElement = toscaOperations.getToscaElement(gv.getUniqueId(), filter);
+            if (toscaElement.isRight()) {
+                LOGGER.debug("Failed to fetch service {} {}", gv.getUniqueId(), toscaElement.right().value());
+                return false;
+            }
+            Component service = toscaElement.left().value();
+            Component oldService = null;
+
+            if(oldServiceModelRequired(service)){
+                Either<Service, StorageOperationStatus> oldServiceEither = serviceOperation.getService(gv.getUniqueId(), filter, false);
+                if (oldServiceEither.isRight()){
+                    LOGGER.debug("couldn't fetch service {} from old titan", gv.getUniqueId());
+                }else {
+                    oldService = oldServiceEither.left().value();
+                    oldService = oldService.getComponentInstances().stream().anyMatch(containsGroupInstances) ? oldService : null;
+                }
+            }
+
+            Map<String, Boolean> updateMap = new HashMap<>();
+            nodeTemplateMissingDataResolver.updateServiceComposition(service, origCompMap, oldService, updateMap);
+            if(updateMap.get(JsonConstantKeysEnum.COMPOSITION.name())) {
+                LOGGER.info("applying instance tosca name fix on service {}", gv.getUniqueId());
+                fixed = (toscaOperations.updateComponentInstanceMetadataOfTopologyTemplate(service)).isLeft();
+            }
+            if(updateMap.get(EdgeLabelEnum.INST_GROUPS.name())) {
+                Map<String, MapGroupsDataDefinition> groupsMap = buildGroupInstanceMap(service);
+                LOGGER.info("applying groups instances vertex fix on service {}", gv.getUniqueId());
+                fixed = fixed && updateDataVertex(gv, VertexTypeEnum.INST_GROUPS, EdgeLabelEnum.INST_GROUPS, groupsMap);
+            }
+            if(updateMap.get(EdgeLabelEnum.INST_INPUTS.name())) {
+                Map<String, MapPropertiesDataDefinition> instInputs = buildInstancesInputsMap(service);
+                LOGGER.info("applying instances inputs vertex fix on service {}", gv.getUniqueId());
+                fixed = fixed && updateDataVertex(gv, VertexTypeEnum.INST_INPUTS, EdgeLabelEnum.INST_INPUTS, instInputs);
+            }
+            res = res && fixed;
+            titanDao.commit();
+        }
+        return res;
+    }
+}
diff --git a/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/jsonmodel/ComponentMigration.java b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/jsonmodel/ComponentMigration.java
index d69363b..7603a57 100644
--- a/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/jsonmodel/ComponentMigration.java
+++ b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/jsonmodel/ComponentMigration.java
@@ -109,8 +109,8 @@
     protected void setMissingTemplateInfo(List<T> components) {
     	Map<String, ToscaElement> origCompMap = new HashMap<>();
     	for (T component : components) {
-    	    List<ComponentInstance> instances = component.getComponentInstances();
-    	    if(null != instances) {
+            List<ComponentInstance> instances = component.getComponentInstances();
+            if(null != instances) {
                 for (ComponentInstance instance : instances) {
                     nodeTemplateMissingDataResolver.resolveNodeTemplateInfo(instance, origCompMap, component);
                     nodeTemplateMissingDataResolver.fixVFGroupInstances(component, instance);
diff --git a/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/jsonmodel/NodeTemplateMissingDataResolver.java b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/jsonmodel/NodeTemplateMissingDataResolver.java
index 01e3634..c834210 100644
--- a/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/jsonmodel/NodeTemplateMissingDataResolver.java
+++ b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/jsonmodel/NodeTemplateMissingDataResolver.java
@@ -17,23 +17,18 @@
  * limitations under the License.
  * ============LICENSE_END=========================================================
  */
-
 package org.openecomp.sdc.asdctool.impl.migration.v1707.jsonmodel;
-
-
+import fj.data.Either;
+import org.openecomp.sdc.be.dao.jsongraph.types.EdgeLabelEnum;
 import fj.data.Either;
 import org.openecomp.sdc.be.datatypes.elements.ComponentInstanceDataDefinition;
 import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition;
 import org.openecomp.sdc.be.datatypes.enums.OriginTypeEnum;
 import org.openecomp.sdc.be.datatypes.tosca.ToscaDataDefinition;
-import org.openecomp.sdc.be.model.ArtifactDefinition;
-import org.openecomp.sdc.be.model.Component;
-import org.openecomp.sdc.be.model.ComponentInstance;
-import org.openecomp.sdc.be.model.ComponentInstanceInput;
-import org.openecomp.sdc.be.model.GroupDefinition;
-import org.openecomp.sdc.be.model.GroupInstance;
+import org.openecomp.sdc.be.model.*;
 import org.openecomp.sdc.be.model.jsontitan.datamodel.TopologyTemplate;
 import org.openecomp.sdc.be.model.jsontitan.datamodel.ToscaElement;
+import org.openecomp.sdc.be.model.jsontitan.enums.JsonConstantKeysEnum;
 import org.openecomp.sdc.be.model.jsontitan.operations.TopologyTemplateOperation;
 import org.openecomp.sdc.be.model.jsontitan.operations.ToscaElementLifecycleOperation;
 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
@@ -45,6 +40,8 @@
 import javax.annotation.Resource;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.*;
+import java.util.stream.Collectors;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
@@ -59,32 +56,98 @@
     private ToscaElementLifecycleOperation lifecycleOperation;
 	
 	@Resource(name = "topology-template-operation")
-    private TopologyTemplateOperation topologyTemplateOperation;
+    public TopologyTemplateOperation topologyTemplateOperation;
 	
 	public void resolveNodeTemplateInfo(ComponentInstanceDataDefinition vfInst, Map<String, ToscaElement> origCompMap, T component) {
 		lifecycleOperation.resolveToscaComponentName(vfInst, origCompMap);
 		if(OriginTypeEnum.VF == vfInst.getOriginType()) {
-			Map<String, List<ComponentInstanceInput>> componentInstancesInputs = Optional.ofNullable(component.getComponentInstancesInputs()).orElse(new HashMap<>());
-			collectVFInstanceInputs(componentInstancesInputs, origCompMap, vfInst);
+			collectVFInstanceInputs(component, origCompMap, vfInst);
 		}
 	}
+
+
+
+
+	public void updateServiceComposition(Component component, Map<String, ToscaElement> origCompMap, Component oldModelService, Map<String, Boolean> updateMap){
+
+		boolean composition = false;
+		boolean instInputs = false;
+		boolean instGroups = false;
+		List<ComponentInstance> instances = component.getComponentInstances();
+		if(null != instances) {
+			for (ComponentInstance instance : instances) {
+				composition = composition || lifecycleOperation.resolveToscaComponentName(instance, origCompMap);
+				if(OriginTypeEnum.VF == instance.getOriginType()) {
+					instInputs = instInputs || collectVFInstanceInputs(component, origCompMap, instance);
+					instGroups = instGroups || resolveInstGroupsFromOldTitanGraphAndApplyFix(component, instance, oldModelService);
+				}
+			}
+		}
+		updateMap.put(JsonConstantKeysEnum.COMPOSITION.name(), composition);
+		updateMap.put(EdgeLabelEnum.INST_INPUTS.name(), instInputs);
+		updateMap.put(EdgeLabelEnum.INST_GROUPS.name(), instGroups);
+	}
+
+
+	public void updateVFComposition(Component component, Map<String, ToscaElement> origCompMap, Map<String, Boolean> updateMap) {
+
+		boolean composition = false;
+		boolean groups = fixVFGroups(component);
+		List<ComponentInstance> instances = component.getComponentInstances();
+		if(null != instances) {
+			for (ComponentInstance instance : instances) {
+				composition = composition || lifecycleOperation.resolveToscaComponentName(instance, origCompMap);
+			}
+		}
+		updateMap.put(JsonConstantKeysEnum.COMPOSITION.name(), composition);
+		updateMap.put(EdgeLabelEnum.GROUPS.name(), groups);
+	}
+
+
+
+	private boolean resolveInstGroupsFromOldTitanGraphAndApplyFix(Component component, ComponentInstance instance, Component oldService){
+
+		boolean res = false;
+		//info already exists, apply fix if needed
+		if(null != instance.getGroupInstances() && !instance.getGroupInstances().isEmpty()) {
+			res = fixVFGroupInstances(component, instance);
+		//get group instances from old model
+		}else if(null != oldService){
+			ComponentInstance origInstance = oldService.getComponentInstances().stream()
+					.filter(p -> instance.getUniqueId().equals(p.getUniqueId()))
+					.findAny().orElse(null);
+			if(null != origInstance && null != origInstance.getGroupInstances()) {
+				fixVFGroupInstances(oldService, origInstance);
+				instance.setGroupInstances(origInstance.getGroupInstances());
+				res = true;
+			}
+		}
+		return res;
+	}
 	
-	private void collectVFInstanceInputs(Map<String, List<ComponentInstanceInput>> instInputs, Map<String, ToscaElement> origCompMap, ComponentInstanceDataDefinition vfInst) {
+	private boolean collectVFInstanceInputs(Component component, Map<String, ToscaElement> origCompMap, ComponentInstanceDataDefinition vfInst) {
+		boolean res = false;
 		String ciUid = vfInst.getUniqueId();
 		String origCompUid = vfInst.getComponentUid();
+		if(null == component.getComponentInstancesInputs())
+			component.setComponentInstancesInputs(new HashMap<>());
+		Map<String, List<ComponentInstanceInput>> componentInstInputs = component.getComponentInstancesInputs();
 		Either<ToscaElement, StorageOperationStatus> origComp = fetchToscaElement(origCompMap, vfInst, origCompUid);
         if(origComp.isRight())
-        	return;
+        	return false;
 		Map<String, PropertyDataDefinition> origVFInputs = ((TopologyTemplate)origComp.left().value()).getInputs();
 		if (origVFInputs != null && !origVFInputs.isEmpty()) {
+			res = true;
 			Map<String, ComponentInstanceInput> collectedVFInputs = origVFInputs.values().stream()
 					                                                                       .collect(Collectors.toMap(PropertyDataDefinition::getName, ComponentInstanceInput::new));
-			List<ComponentInstanceInput> instInputList = instInputs.get(ciUid);
+
+			List<ComponentInstanceInput> instInputList = componentInstInputs.get(ciUid);
 			Map<String, ComponentInstanceInput> existingInstInputs = ToscaDataDefinition.listToMapByName(instInputList);
 			collectedVFInputs.putAll(existingInstInputs);
 			List<ComponentInstanceInput> mergedList = new ArrayList<>(collectedVFInputs.values());
-			instInputs.put(ciUid, mergedList);	
+			componentInstInputs.put(ciUid, mergedList);
 		}
+		return res;
 	}
 
 	private Either<ToscaElement, StorageOperationStatus> fetchToscaElement(Map<String, ToscaElement> origCompMap, ComponentInstanceDataDefinition vfInst, String origCompUid) {
@@ -201,22 +264,23 @@
 		return artifactLabel;
 	}
 	
-	protected boolean fixVFGroups(Component component){
-		boolean res = true;
-		
+	public boolean fixVFGroups(Component component){
+		boolean res = false;
+
 		Map<String, ArtifactDefinition> deploymentArtifacts = component.getDeploymentArtifacts();
 		List<GroupDefinition> groups = component.getGroups();
 		if (groups == null || groups.isEmpty()) {
-			LOGGER.debug("No  groups  in component {} id {} ",  component.getName(), component.getUniqueId());
+			LOGGER.debug("No groups in component {} id {} ",  component.getName(), component.getUniqueId());
 			return res;
 		}	
 				
 		for (GroupDefinition group : groups) {
 			if (group.getType().equals(Constants.DEFAULT_GROUP_VF_MODULE) && deploymentArtifacts != null) {
 				if (isProblematicGroup(group, component.getName(), deploymentArtifacts)) {
-					List<String> groupArtifacts = new ArrayList<String>(group.getArtifacts());
-					group.getArtifacts().clear();
-					group.getArtifactsUuid().clear();
+					res = true;
+					List<String> groupArtifacts = null == group.getArtifacts()? new ArrayList<>() : new ArrayList<>(group.getArtifacts());
+					group.setArtifacts(new ArrayList<>());
+					group.setArtifactsUuid(new ArrayList<>());
 					for (String artifactId : groupArtifacts) {
 						String artifactlabel = findArtifactLabelFromArtifactId(artifactId);
 						LOGGER.debug("fix group:  group name {} artifactId for fix {} artifactlabel {} ", group.getName(), artifactId, artifactlabel);
@@ -229,19 +293,16 @@
 							if (correctArtifactUUID != null && !correctArtifactUUID.isEmpty()) {
 								group.getArtifactsUuid().add(correctArtifactUUID);
 							}
-
 						}
 					}
 				}
 			}
-			
-		}		
-		
+		}
 		return res;
 	}
 	
-	protected boolean fixVFGroupInstances(Component component, ComponentInstance instance){
-		boolean res = true;
+	public boolean fixVFGroupInstances(Component component, ComponentInstance instance){
+		boolean res = false;
 		
 		Map<String, ArtifactDefinition> deploymentArtifacts = instance.getDeploymentArtifacts();
 		List<GroupInstance> groupInstances = instance.getGroupInstances();
@@ -252,10 +313,9 @@
 		for (GroupInstance group : groupInstances) {
 			if (group.getType().equals(Constants.DEFAULT_GROUP_VF_MODULE)) {
 				if (isProblematicGroupInstance(group, instance.getName(), component.getName(), deploymentArtifacts)) {
-
-					LOGGER.debug("Migration1707ArtifactUuidFix  fix group:  resource id {}, group name {} ", component.getUniqueId(), group.getName());
-					List<String> groupArtifacts = Optional.ofNullable(group.getArtifacts()).orElse(new ArrayList<>());
-
+					res = true;
+					LOGGER.debug("Migration1707ArtifactUuidFix fix group: resource id {}, group name {} ", component.getUniqueId(), group.getName());
+					List<String> groupArtifacts = null == group.getArtifacts()? new ArrayList<>() : new ArrayList<>(group.getArtifacts());
 					group.setArtifacts(new ArrayList<>());
 					group.setArtifactsUuid(new ArrayList<>());
 					group.setGroupInstanceArtifacts(new ArrayList<>());
@@ -285,12 +345,9 @@
 							}
 						}
 					}
-
 				}
 			}
 		}
-		
 		return res;
 	}
-
 }
diff --git a/asdctool/src/main/java/org/openecomp/sdc/asdctool/main/MigrationMenu.java b/asdctool/src/main/java/org/openecomp/sdc/asdctool/main/MigrationMenu.java
index dd9fa86..600ebf8 100644
--- a/asdctool/src/main/java/org/openecomp/sdc/asdctool/main/MigrationMenu.java
+++ b/asdctool/src/main/java/org/openecomp/sdc/asdctool/main/MigrationMenu.java
@@ -33,12 +33,7 @@
 import org.openecomp.sdc.asdctool.impl.migration.v1610.TitanFixUtils;
 import org.openecomp.sdc.asdctool.impl.migration.v1610.ToscaArtifactsAlignment;
 import org.openecomp.sdc.asdctool.impl.migration.v1702.Migration1702;
-import org.openecomp.sdc.asdctool.impl.migration.v1707.Migration1707;
-import org.openecomp.sdc.asdctool.impl.migration.v1707.Migration1707ArtifactUuidFix;
-import org.openecomp.sdc.asdctool.impl.migration.v1707.Migration1707Config;
-import org.openecomp.sdc.asdctool.impl.migration.v1707.DistributionStatusUpdate;
-import org.openecomp.sdc.asdctool.impl.migration.v1707.Migration1707VnfFix;
-import org.openecomp.sdc.asdctool.impl.migration.v1707.VfModulesPropertiesAdding;
+import org.openecomp.sdc.asdctool.impl.migration.v1707.*;
 import org.openecomp.sdc.be.config.ConfigurationManager;
 import org.openecomp.sdc.common.api.ConfigurationSource;
 import org.openecomp.sdc.common.impl.ExternalConfiguration;
@@ -53,17 +48,17 @@
 	private static final String SERVICE_MIGARTION_BEAN = "serviceMigrationBean";
 
 	private static enum MigrationOperationEnum {
-		MIGRATION_1602_1604("migrate-1602-1604", SERVICE_MIGARTION_BEAN), 
-		ALIGN_DERIVED_FROM_1604("align-derived-from-1604", "derivedFromAlignment"), 
-		MIGRATE_1604_1607("migrate-1604-1607", SERVICE_MIGARTION_BEAN), 
-		ALIGN_VFC_NAMES_1604("align-vfc-names-1604", "vfcNamingAlignmentBean"), 
-		TEST_REMOVE_HEAT_PLACEHOLDERS("testremoveheatplaceholders",	SERVICE_MIGARTION_BEAN), 
-		TEST_ADD_GROUP_UUIDS("testaddgroupuuids", SERVICE_MIGARTION_BEAN), 
-		ALIGN_GROUPS("align-groups", "groupsAlignment"), 
-		CLEAN_CSAR("clean-csar", "csarMigration"), 
-		POPULATE_COMPONENT_CACHE("populate-component-cache", "populateComponentCache"), 
-		FIX_PROPERTIES("fix-properties", "titanFixUtils"), 
-		ALIGN_TOSCA_ARTIFACTS("align-tosca-artifacts", "toscaArtifactsAlignment"), 
+		MIGRATION_1602_1604("migrate-1602-1604", SERVICE_MIGARTION_BEAN),
+		ALIGN_DERIVED_FROM_1604("align-derived-from-1604", "derivedFromAlignment"),
+		MIGRATE_1604_1607("migrate-1604-1607", SERVICE_MIGARTION_BEAN),
+		ALIGN_VFC_NAMES_1604("align-vfc-names-1604", "vfcNamingAlignmentBean"),
+		TEST_REMOVE_HEAT_PLACEHOLDERS("testremoveheatplaceholders",	SERVICE_MIGARTION_BEAN),
+		TEST_ADD_GROUP_UUIDS("testaddgroupuuids", SERVICE_MIGARTION_BEAN),
+		ALIGN_GROUPS("align-groups", "groupsAlignment"),
+		CLEAN_CSAR("clean-csar", "csarMigration"),
+		POPULATE_COMPONENT_CACHE("populate-component-cache", "populateComponentCache"),
+		FIX_PROPERTIES("fix-properties", "titanFixUtils"),
+		ALIGN_TOSCA_ARTIFACTS("align-tosca-artifacts", "toscaArtifactsAlignment"),
 		FIX_ICONS("fix-icons", "titanFixUtils"),
 		MIGRATION_1610_1702("migrate-1610-1702", "migration1702"),
 		MIGRATION_1702_1707("migrate-1702-1707", "migration1707"),
@@ -71,7 +66,8 @@
 		VFMODULES_PROPERTIES_ADDING("vfModules-properties-adding", "vfModulesPropertiesAdding"),
 		MIGRATION_1707_RELATIONS_FIX("fix-relations-after-migration-1707", "migration1707relationsFix"),
 		MIGRATION_1707_VNF_FIX("fix-vnf-after-migration-1707", "migration1707vnfFix"),
-		MIGRATION_1707_UUID_FIX("fix-UUID-1707", "migration1707UuidFix");
+		MIGRATION_1707_UUID_FIX("fix-UUID-1707", "migration1707UuidFix"),
+		MIGRATION_1707_MISSING_INFO_FIX("fix-missing-info-1707", "migration1707MissingInfoFix");
 		// UPDATE_DATA_TYPES("update_data_types", "updateDataTypes");
 
 		private String value, beanName;
@@ -225,7 +221,7 @@
 				ToscaArtifactsAlignment toscaArtifactsAlignment = (ToscaArtifactsAlignment) context.getBean(operationEnum.getBeanName());
 				boolean isSuccessful = toscaArtifactsAlignment.alignToscaArtifacts();
 				if (isSuccessful) {
-					log.info("Tosca Artifacts alignment was finished successfull");
+					log.info("Tosca Artifacts alignment was finished successfully");
 					System.exit(0);
 				} else {
 					log.info("Tosca Artifacts alignment has failed");
@@ -233,20 +229,20 @@
 				}
 				break;
 			case MIGRATION_1610_1702:
-				log.info("Start ASDC migration from 1610 to 1702");
+				log.info("Start SDC migration from 1610 to 1702");
 				Migration1702 migration = (Migration1702) context.getBean(operationEnum.getBeanName());
 				isSuccessful = migration.migrate(appConfigDir);
 				if (isSuccessful) {
-					log.info("ASDC migration from 1610 to 1702 was finished successful");
+					log.info("SDC migration from 1610 to 1702 was finished successful");
 					System.exit(0);
 				} else{
-					log.info("ASDC migration from 1610 to 1702 has failed");
+					log.info("SDC migration from 1610 to 1702 has failed");
 					System.exit(2);
 				}
-			
+
 				break;
 			case MIGRATION_1702_1707://this migration is currently not needed, but will be commented out for production env
-				log.info("Start ASDC migration from 1702 to 1707");
+//				log.info("Start SDC migration from 1702 to 1707");
 				Migration1707 migration1707 = (Migration1707) context.getBean(operationEnum.getBeanName());
 				isSuccessful = migration1707.migrate();
 				if (isSuccessful) {
@@ -278,8 +274,8 @@
 				}
 				String fixServices = args[3];
 				String runMode = args[4];
-				log.info("Start fixing artifact UUID after 1707 migration with arguments run with configutation [{}] , for [{}] services", runMode, fixServices);
-				
+				log.info("Start fixing artifact UUID after 1707 migration with arguments run with configuration [{}] , for [{}] services", runMode, fixServices);
+
 				Migration1707ArtifactUuidFix migrationFix = (Migration1707ArtifactUuidFix) context.getBean(operationEnum.getBeanName());
 				isSuccessful = migrationFix.migrate(fixServices,  runMode);
 				if (isSuccessful) {
@@ -290,6 +286,20 @@
 				}
 				System.exit(0);
 				break;
+			case MIGRATION_1707_MISSING_INFO_FIX:
+
+				log.info("Start fixing missing group and instance info after 1707 migration");
+
+				Migration1707MissingInfoFix migration1707Fix = (Migration1707MissingInfoFix) context.getBean(operationEnum.getBeanName());
+				isSuccessful = migration1707Fix.migrate();
+				if (isSuccessful) {
+					log.info("Fixing groups and node templates missing info  was finished successfully");
+				} else{
+					log.info("Fixing groups and node templates missing info has failed");
+					System.exit(2);
+				}
+				System.exit(0);
+				break;
 			default:
 				usageAndExit();
 			}
@@ -330,5 +340,6 @@
 		System.out.println("Usage: fix-relations-after-migration-1707 <configuration dir>");
 		System.out.println("Usage: fix-vnf-after-migration-1707 <configuration dir>");
 		System.out.println("Usage: fix-UUID-1707 <configuration dir> <all/distributed_only> <services/service_vf/fix/fix_only_services>");
+		System.out.println("Usage: fix-missing-info-1707 <configuration dir>");
 	}
 }
diff --git a/asdctool/src/main/java/org/openecomp/sdc/asdctool/migration/config/MigrationSpringConfig.java b/asdctool/src/main/java/org/openecomp/sdc/asdctool/migration/config/MigrationSpringConfig.java
new file mode 100644
index 0000000..0457c21
--- /dev/null
+++ b/asdctool/src/main/java/org/openecomp/sdc/asdctool/migration/config/MigrationSpringConfig.java
@@ -0,0 +1,59 @@
+package org.openecomp.sdc.asdctool.migration.config;
+
+import org.openecomp.sdc.asdctool.migration.core.SdcMigrationTool;
+import org.openecomp.sdc.asdctool.migration.core.task.Migration;
+import org.openecomp.sdc.asdctool.migration.resolver.MigrationResolver;
+import org.openecomp.sdc.asdctool.migration.resolver.SpringBeansMigrationResolver;
+import org.openecomp.sdc.asdctool.migration.service.SdcRepoService;
+import org.openecomp.sdc.be.dao.cassandra.CassandraClient;
+import org.openecomp.sdc.be.dao.cassandra.MigrationTasksDao;
+import org.openecomp.sdc.be.dao.config.DAOSpringConfig;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Configuration
+@Import(DAOSpringConfig.class)
+@ComponentScan({"org.openecomp.sdc.asdctool.migration.tasks",//migration tasks
+                "org.openecomp.sdc.be.model.operations.impl",
+                "org.openecomp.sdc.be.model.cache",
+                "org.openecomp.sdc.be.dao.titan",
+                "org.openecomp.sdc.be.dao.cassandra",
+                "org.openecomp.sdc.be.model.jsontitan.operations",
+                "org.openecomp.sdc.be.dao.jsongraph"})
+public class MigrationSpringConfig {
+
+    @Autowired(required=false)
+    private List<Migration> migrations = new ArrayList<>();
+
+    @Bean(name = "sdc-migration-tool")
+    public SdcMigrationTool sdcMigrationTool(MigrationResolver migrationResolver, SdcRepoService sdcRepoService) {
+        return new SdcMigrationTool(migrationResolver, sdcRepoService);
+    }
+
+    @Bean(name = "spring-migrations-resolver")
+    public SpringBeansMigrationResolver migrationResolver(SdcRepoService sdcRepoService) {
+        return new SpringBeansMigrationResolver(migrations, sdcRepoService);
+    }
+
+    @Bean(name = "sdc-repo-service")
+    public SdcRepoService sdcRepoService(MigrationTasksDao migrationTasksDao) {
+        return new SdcRepoService(migrationTasksDao);
+    }
+
+    @Bean(name = "sdc-migration-tasks-cassandra-dao")
+    public MigrationTasksDao migrationTasksDao() {
+        return new MigrationTasksDao();
+    }
+
+    @Bean(name = "cassandra-client")
+    public CassandraClient cassandraClient() {
+        return new CassandraClient();
+    }
+
+}
diff --git a/asdctool/src/main/java/org/openecomp/sdc/asdctool/migration/core/DBVersion.java b/asdctool/src/main/java/org/openecomp/sdc/asdctool/migration/core/DBVersion.java
new file mode 100644
index 0000000..003a27a
--- /dev/null
+++ b/asdctool/src/main/java/org/openecomp/sdc/asdctool/migration/core/DBVersion.java
@@ -0,0 +1,95 @@
+package org.openecomp.sdc.asdctool.migration.core;
+
+import java.math.BigInteger;
+
+public class DBVersion implements Comparable<DBVersion>{
+
+    private static final String VERSION_PARTS_SEPARATOR = "\\.";
+    private static final int MAJOR_PART_IDX = 0;
+    private static final int MINOR_PART_IDX = 1;
+    private BigInteger major;
+    private BigInteger minor;
+
+    /**
+     * The current db version. should be tested against real db to verify it is compatible to the db version
+     */
+    public static final DBVersion CURRENT_VERSION = new DBVersion(1710, 0);
+
+    private DBVersion(BigInteger major, BigInteger minor) {
+        this.major = major;
+        this.minor = minor;
+    }
+
+    private DBVersion(int major, int minor) {
+        this.major = BigInteger.valueOf(major);
+        this.minor = BigInteger.valueOf(minor);
+    }
+
+    public BigInteger getMajor() {
+        return major;
+    }
+
+    public BigInteger getMinor() {
+        return minor;
+    }
+
+    public static DBVersion from(BigInteger major, BigInteger minor) {
+        return new DBVersion(major, minor);
+    }
+
+    public static DBVersion fromString(String version) {
+        String[] split = version.split(VERSION_PARTS_SEPARATOR);
+        if (split.length != 2) {
+            throw new MigrationException("version must be of pattern: <major>.<minor>");
+        }
+        return new DBVersion(getVersionPart(split[MAJOR_PART_IDX]),
+                             getVersionPart(split[MINOR_PART_IDX]));
+
+    }
+
+    private static BigInteger getVersionPart(String versionPart) {
+        try {
+            return new BigInteger(versionPart);
+        } catch (NumberFormatException e) {
+            throw new MigrationException(String.format("version part %s is non numeric", versionPart));
+        }
+    }
+
+    @Override
+    public String toString() {
+        return String.format("%s.%s", major, minor);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        DBVersion dbVersion = (DBVersion) o;
+
+        return major.equals(dbVersion.major) && minor.equals(dbVersion.minor);
+    }
+
+    @Override
+    public int hashCode() {
+        int result = major.hashCode();
+        result = 31 * result + minor.hashCode();
+        return result;
+    }
+
+    @Override
+    public int compareTo(DBVersion o) {
+        if (o == null) {
+            return 1;
+        }
+        int majorsComparision = this.major.compareTo(o.major);
+        if (majorsComparision != 0) {
+            return majorsComparision;
+        }
+        int minorsComparision = this.minor.compareTo(o.minor);
+        if (minorsComparision != 0) {
+            return minorsComparision;
+        }
+        return 0;
+    }
+}
diff --git a/asdctool/src/main/java/org/openecomp/sdc/asdctool/migration/core/MigrationException.java b/asdctool/src/main/java/org/openecomp/sdc/asdctool/migration/core/MigrationException.java
new file mode 100644
index 0000000..e9e8053
--- /dev/null
+++ b/asdctool/src/main/java/org/openecomp/sdc/asdctool/migration/core/MigrationException.java
@@ -0,0 +1,13 @@
+package org.openecomp.sdc.asdctool.migration.core;
+
+public class MigrationException extends RuntimeException {
+
+    public MigrationException(String message) {
+        super(message);
+    }
+
+    public MigrationException(String message, RuntimeException e) {
+        super(message, e);
+    }
+
+}
diff --git a/asdctool/src/main/java/org/openecomp/sdc/asdctool/migration/core/SdcMigrationTool.java b/asdctool/src/main/java/org/openecomp/sdc/asdctool/migration/core/SdcMigrationTool.java
new file mode 100644
index 0000000..e2691dc
--- /dev/null
+++ b/asdctool/src/main/java/org/openecomp/sdc/asdctool/migration/core/SdcMigrationTool.java
@@ -0,0 +1,62 @@
+package org.openecomp.sdc.asdctool.migration.core;
+
+import org.openecomp.sdc.asdctool.migration.core.execution.MigrationExecutionResult;
+import org.openecomp.sdc.asdctool.migration.core.execution.MigrationExecutorImpl;
+import org.openecomp.sdc.asdctool.migration.core.task.Migration;
+import org.openecomp.sdc.asdctool.migration.core.task.MigrationResult;
+import org.openecomp.sdc.asdctool.migration.resolver.MigrationResolver;
+import org.openecomp.sdc.asdctool.migration.service.SdcRepoService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+
+public class SdcMigrationTool {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(SdcMigrationTool.class);
+
+    private MigrationResolver migrationsResolver;
+
+    private SdcRepoService sdcRepoService;
+
+    public SdcMigrationTool(MigrationResolver migrationsResolver, SdcRepoService sdcRepoService) {
+        this.migrationsResolver = migrationsResolver;
+        this.sdcRepoService = sdcRepoService;
+    }
+
+    public SdcMigrationTool() {
+    }
+
+    public boolean migrate(boolean enforceAll) {
+        LOGGER.info("starting migration process");
+        handleEnforceMigrationFlag(enforceAll);
+        List<Migration> migrations = migrationsResolver.resolveMigrations();
+        LOGGER.info("there are {} migrations task to execute", migrations.size());
+        for (Migration migration : migrations) {
+            try {
+                MigrationExecutionResult executionResult = new MigrationExecutorImpl().execute(migration);
+                if (migrationHasFailed(executionResult)) {
+                    LOGGER.error("migration {} with version {} has failed. error msg: {}", migration.getClass().getName(), migration.getVersion().toString(), executionResult.getMsg());
+                    return false;
+                }
+                sdcRepoService.createMigrationTask(executionResult.toMigrationTaskEntry());
+            } catch (RuntimeException e) {
+                LOGGER.error("migration {} with version {} has failed. error msg: {}", migration.getClass().getName(), migration.getVersion().toString(), e);
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private boolean migrationHasFailed(MigrationExecutionResult migrationResult) {
+        return migrationResult.getMigrationStatus().equals(MigrationResult.MigrationStatus.FAILED);
+    }
+
+    private void handleEnforceMigrationFlag(boolean enforceAll) {
+        if (enforceAll) {
+            LOGGER.info("enforcing migration for current version");
+            sdcRepoService.clearTasksForCurrentMajor();
+        }
+    }
+
+}
diff --git a/asdctool/src/main/java/org/openecomp/sdc/asdctool/migration/core/execution/MigrationExecutionResult.java b/asdctool/src/main/java/org/openecomp/sdc/asdctool/migration/core/execution/MigrationExecutionResult.java
new file mode 100644
index 0000000..4ebec6e
--- /dev/null
+++ b/asdctool/src/main/java/org/openecomp/sdc/asdctool/migration/core/execution/MigrationExecutionResult.java
@@ -0,0 +1,70 @@
+package org.openecomp.sdc.asdctool.migration.core.execution;
+
+import org.openecomp.sdc.asdctool.migration.core.DBVersion;
+import org.openecomp.sdc.asdctool.migration.core.task.MigrationResult;
+import org.openecomp.sdc.be.resources.data.MigrationTaskEntry;
+
+import java.util.Date;
+
+public class MigrationExecutionResult {
+
+    private MigrationResult.MigrationStatus migrationStatus;
+    private String msg;
+    private double executionTime;
+    private DBVersion version;
+    private String taskName;
+
+    public MigrationTaskEntry toMigrationTaskEntry() {
+        MigrationTaskEntry migrationTaskEntry = new MigrationTaskEntry();
+        migrationTaskEntry.setMajorVersion(this.getVersion().getMajor().longValue());
+        migrationTaskEntry.setMinorVersion(this.getVersion().getMinor().longValue());
+        migrationTaskEntry.setTimestamp(new Date());
+        migrationTaskEntry.setTaskName(this.getTaskName());
+        migrationTaskEntry.setTaskStatus(this.getMigrationStatus().name());
+        migrationTaskEntry.setMessage(this.getMsg());
+        migrationTaskEntry.setExecutionTime(this.getExecutionTime());
+        return migrationTaskEntry;
+    }
+
+
+    public MigrationResult.MigrationStatus getMigrationStatus() {
+        return migrationStatus;
+    }
+
+    void setMigrationStatus(MigrationResult.MigrationStatus migrationStatus) {
+        this.migrationStatus = migrationStatus;
+    }
+
+    public String getMsg() {
+        return msg;
+    }
+
+    void setMsg(String msg) {
+        this.msg = msg;
+    }
+
+    double getExecutionTime() {
+        return executionTime;
+    }
+
+    void setExecutionTime(double executionTime) {
+        this.executionTime = executionTime;
+    }
+
+    public DBVersion getVersion() {
+        return version;
+    }
+
+    public void setVersion(DBVersion version) {
+        this.version = version;
+    }
+
+    String getTaskName() {
+        return taskName;
+    }
+
+    void setTaskName(String taskName) {
+        this.taskName = taskName;
+    }
+
+}
diff --git a/asdctool/src/main/java/org/openecomp/sdc/asdctool/migration/core/execution/MigrationExecutor.java b/asdctool/src/main/java/org/openecomp/sdc/asdctool/migration/core/execution/MigrationExecutor.java
new file mode 100644
index 0000000..aba5056
--- /dev/null
+++ b/asdctool/src/main/java/org/openecomp/sdc/asdctool/migration/core/execution/MigrationExecutor.java
@@ -0,0 +1,15 @@
+package org.openecomp.sdc.asdctool.migration.core.execution;
+
+import org.openecomp.sdc.asdctool.migration.core.MigrationException;
+import org.openecomp.sdc.asdctool.migration.core.task.Migration;
+
+public interface MigrationExecutor {
+
+    /**
+     * @param migration the migration to execute
+     * @return a {@link MigrationExecutionResult} with the relevant data on the current migration execution;
+     * @throws MigrationException in case there was an unexpected exception during migration
+     */
+    MigrationExecutionResult execute(Migration migration) throws MigrationException;
+
+}
diff --git a/asdctool/src/main/java/org/openecomp/sdc/asdctool/migration/core/execution/MigrationExecutorImpl.java b/asdctool/src/main/java/org/openecomp/sdc/asdctool/migration/core/execution/MigrationExecutorImpl.java
new file mode 100644
index 0000000..2e4d3ba
--- /dev/null
+++ b/asdctool/src/main/java/org/openecomp/sdc/asdctool/migration/core/execution/MigrationExecutorImpl.java
@@ -0,0 +1,47 @@
+package org.openecomp.sdc.asdctool.migration.core.execution;
+
+import org.openecomp.sdc.asdctool.migration.core.MigrationException;
+import org.openecomp.sdc.asdctool.migration.core.task.Migration;
+import org.openecomp.sdc.asdctool.migration.core.task.MigrationResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.util.StopWatch;
+
+
+public class MigrationExecutorImpl implements MigrationExecutor {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(MigrationExecutorImpl.class);
+
+    @Override
+    public MigrationExecutionResult execute(Migration migration) throws MigrationException {
+        try {
+            LOGGER.info("starting migration {}. description: {}. version {}", migration.getClass().getName(), migration.description(),  migration.getVersion().toString());
+            StopWatch stopWatch = new StopWatch();
+            stopWatch.start();
+            MigrationResult migrationResult = migration.migrate();
+            stopWatch.stop();
+            double executionTime = stopWatch.getTotalTimeSeconds();
+            return logAndCreateExecutionResult(migration, migrationResult, executionTime);
+        } catch (RuntimeException e) {
+            LOGGER.error("migration {} has failed!", migration.description(), e);
+            throw new MigrationException("migration %s failed!!!", e);
+
+        }
+    }
+
+    private MigrationExecutionResult logAndCreateExecutionResult(Migration migration, MigrationResult migrationResult, double executionTime) {
+        LOGGER.info("finished migration {}. with version {}. migration status: {}, migration message: {}, execution time: {}", migration.getClass().getName(),  migration.getVersion().toString(), migrationResult.getMigrationStatus().name(), migrationResult.getMsg(), executionTime);
+        return createMigrationTask(migration, migrationResult, executionTime);
+    }
+
+    private MigrationExecutionResult createMigrationTask(Migration migration, MigrationResult migrationResult, double totalTimeSeconds) {
+        MigrationExecutionResult migrationExecutionResult = new MigrationExecutionResult();
+        migrationExecutionResult.setExecutionTime(totalTimeSeconds);
+        migrationExecutionResult.setMigrationStatus(migrationResult.getMigrationStatus());
+        migrationExecutionResult.setMsg(migrationResult.getMsg());
+        migrationExecutionResult.setTaskName(migration.getClass().getName());
+        migrationExecutionResult.setVersion(migration.getVersion());
+        return migrationExecutionResult;
+    }
+
+}
diff --git a/asdctool/src/main/java/org/openecomp/sdc/asdctool/migration/core/task/Migration.java b/asdctool/src/main/java/org/openecomp/sdc/asdctool/migration/core/task/Migration.java
new file mode 100644
index 0000000..58f201a
--- /dev/null
+++ b/asdctool/src/main/java/org/openecomp/sdc/asdctool/migration/core/task/Migration.java
@@ -0,0 +1,14 @@
+package org.openecomp.sdc.asdctool.migration.core.task;
+
+
+import org.openecomp.sdc.asdctool.migration.core.DBVersion;
+
+public interface Migration {
+
+    String description();
+
+    DBVersion getVersion();
+
+    MigrationResult migrate();
+
+}
diff --git a/asdctool/src/main/java/org/openecomp/sdc/asdctool/migration/core/task/MigrationResult.java b/asdctool/src/main/java/org/openecomp/sdc/asdctool/migration/core/task/MigrationResult.java
new file mode 100644
index 0000000..8c4c090
--- /dev/null
+++ b/asdctool/src/main/java/org/openecomp/sdc/asdctool/migration/core/task/MigrationResult.java
@@ -0,0 +1,31 @@
+package org.openecomp.sdc.asdctool.migration.core.task;
+
+public class MigrationResult {
+
+    private String msg;
+    private MigrationStatus migrationStatus;
+
+    public String getMsg() {
+        return msg;
+    }
+
+    public void setMsg(String msg) {
+        this.msg = msg;
+    }
+
+    public MigrationStatus getMigrationStatus() {
+        return migrationStatus;
+    }
+
+    public void setMigrationStatus(MigrationStatus migrationStatus) {
+        this.migrationStatus = migrationStatus;
+    }
+
+    public enum MigrationStatus {
+        COMPLETED,
+        COMPLETED_WITH_ERRORS,
+        FAILED
+    }
+
+
+}
diff --git a/asdctool/src/main/java/org/openecomp/sdc/asdctool/migration/main/MigrationMenu.java b/asdctool/src/main/java/org/openecomp/sdc/asdctool/migration/main/MigrationMenu.java
new file mode 100644
index 0000000..1e8a533
--- /dev/null
+++ b/asdctool/src/main/java/org/openecomp/sdc/asdctool/migration/main/MigrationMenu.java
@@ -0,0 +1,100 @@
+package org.openecomp.sdc.asdctool.migration.main;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.DefaultParser;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+import org.openecomp.sdc.asdctool.migration.config.MigrationSpringConfig;
+import org.openecomp.sdc.asdctool.migration.core.SdcMigrationTool;
+import org.openecomp.sdc.be.config.ConfigurationManager;
+import org.openecomp.sdc.common.api.ConfigurationSource;
+import org.openecomp.sdc.common.impl.ExternalConfiguration;
+import org.openecomp.sdc.common.impl.FSConfigurationSource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+
+public class MigrationMenu {
+
+    private final static Logger LOGGER = LoggerFactory.getLogger(MigrationMenu.class);
+
+    public static void main(String[] args) {
+        CommandLine commandLine = initCmdLineOptions(args);
+        String appConfigDir = commandLine.getOptionValue("c");
+        boolean enforceAll = commandLine.hasOption("e");
+        uploadConfiguration(appConfigDir);
+        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MigrationSpringConfig.class);
+        doMigrate(enforceAll, context);
+
+    }
+
+    private static void doMigrate(boolean enforceAll, AnnotationConfigApplicationContext context) {
+        SdcMigrationTool migrationTool = context.getBean(SdcMigrationTool.class);
+        boolean migrate = migrationTool.migrate(enforceAll);
+        if (migrate) {
+            LOGGER.info("migration completed successfully");
+            System.exit(0);
+        } else {
+            LOGGER.error("migration failed");
+            System.exit(1);
+        }
+    }
+
+    private static CommandLine initCmdLineOptions(String[] args) {
+        Options options = buildCmdLineOptions();
+        CommandLineParser parser = new DefaultParser();
+        try {
+            // parse the command line arguments
+            return parser.parse( options, args );
+        }
+        catch( ParseException exp ) {
+            // oops, something went wrong
+            System.err.println( "Parsing failed.  Reason: " + exp.getMessage() );
+            usageAndExit(options);
+        }
+        return null;
+    }
+
+    private static void usageAndExit(Options options) {
+        HelpFormatter formatter = new HelpFormatter();
+        formatter.printHelp( "yy", options );
+        System.exit(1);
+    }
+
+    private static Options buildCmdLineOptions() {
+        Option configPath = buildConfigPathOption();
+
+        Option enforceAll = buildEnforceAllOption();
+
+        Options options = new Options();
+        options.addOption(configPath);
+        options.addOption(enforceAll);
+        return options;
+    }
+
+    private static Option buildEnforceAllOption() {
+        return Option.builder("e")
+                .longOpt("enforceAll")
+                .desc("enforce running all migration steps for current version")
+                .build();
+    }
+
+    private static Option buildConfigPathOption() {
+        return Option.builder("c")
+                    .longOpt("configFolderPath")
+                    .required()
+                    .hasArg()
+                    .desc("path to sdc configuration folder - required")
+                    .build();
+    }
+
+    private static void uploadConfiguration(String appConfigDir) {
+        ConfigurationSource configurationSource = new FSConfigurationSource(ExternalConfiguration.getChangeListener(), appConfigDir);
+        ConfigurationManager configurationManager = new ConfigurationManager(configurationSource);
+    }
+
+
+}
diff --git a/asdctool/src/main/java/org/openecomp/sdc/asdctool/migration/resolver/MigrationResolver.java b/asdctool/src/main/java/org/openecomp/sdc/asdctool/migration/resolver/MigrationResolver.java
new file mode 100644
index 0000000..b272d45
--- /dev/null
+++ b/asdctool/src/main/java/org/openecomp/sdc/asdctool/migration/resolver/MigrationResolver.java
@@ -0,0 +1,16 @@
+package org.openecomp.sdc.asdctool.migration.resolver;
+
+
+import org.openecomp.sdc.asdctool.migration.core.task.Migration;
+
+import java.util.List;
+
+public interface MigrationResolver {
+
+    /**
+     *
+     * @return a list of {@code T}
+     */
+    List<Migration> resolveMigrations();
+
+}
diff --git a/asdctool/src/main/java/org/openecomp/sdc/asdctool/migration/resolver/SpringBeansMigrationResolver.java b/asdctool/src/main/java/org/openecomp/sdc/asdctool/migration/resolver/SpringBeansMigrationResolver.java
new file mode 100644
index 0000000..4af5d76
--- /dev/null
+++ b/asdctool/src/main/java/org/openecomp/sdc/asdctool/migration/resolver/SpringBeansMigrationResolver.java
@@ -0,0 +1,45 @@
+package org.openecomp.sdc.asdctool.migration.resolver;
+
+
+import org.openecomp.sdc.asdctool.migration.core.DBVersion;
+import org.openecomp.sdc.asdctool.migration.core.task.Migration;
+import org.openecomp.sdc.asdctool.migration.service.SdcRepoService;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class SpringBeansMigrationResolver implements MigrationResolver {
+
+    private List<Migration> migrations = new ArrayList<>();
+
+    private SdcRepoService sdcRepoService;
+
+    public SpringBeansMigrationResolver(List<Migration> migrations, SdcRepoService sdcRepoService) {
+        this.migrations = migrations;
+        this.sdcRepoService = sdcRepoService;
+    }
+
+    @Override
+    public List<Migration> resolveMigrations() {
+        migrations.sort(Comparator.comparing(Migration::getVersion));
+        return resolveNonExecutedMigrations();
+    }
+
+    //package private for testing
+    void setMigrations(List<Migration> migrations) {
+        this.migrations = migrations;
+    }
+
+    private List<Migration> resolveNonExecutedMigrations() {
+        DBVersion latestDBVersion = sdcRepoService.getLatestDBVersion();
+        return migrations.stream()
+                .filter(mig -> isMigrationVersionGreaterThanLatestVersion(latestDBVersion, mig))
+                .collect(Collectors.toList());
+    }
+
+    private boolean isMigrationVersionGreaterThanLatestVersion(DBVersion latestDBVersion, Migration mig) {
+        return mig.getVersion().compareTo(latestDBVersion) > 0;
+    }
+}
diff --git a/asdctool/src/main/java/org/openecomp/sdc/asdctool/migration/service/SdcRepoService.java b/asdctool/src/main/java/org/openecomp/sdc/asdctool/migration/service/SdcRepoService.java
new file mode 100644
index 0000000..2888ecb
--- /dev/null
+++ b/asdctool/src/main/java/org/openecomp/sdc/asdctool/migration/service/SdcRepoService.java
@@ -0,0 +1,34 @@
+package org.openecomp.sdc.asdctool.migration.service;
+
+import org.openecomp.sdc.asdctool.migration.core.DBVersion;
+import org.openecomp.sdc.be.dao.cassandra.MigrationTasksDao;
+import org.openecomp.sdc.be.resources.data.MigrationTaskEntry;
+
+import java.math.BigInteger;
+
+public class SdcRepoService {
+
+    private MigrationTasksDao migrationTasksDao;
+
+    public SdcRepoService(MigrationTasksDao migrationTasksDao) {
+        this.migrationTasksDao = migrationTasksDao;
+    }
+
+    public DBVersion getLatestDBVersion() {
+        BigInteger currentMajorVersion = DBVersion.CURRENT_VERSION.getMajor();
+        BigInteger latestMinorVersion = migrationTasksDao.getLatestMinorVersion(currentMajorVersion);
+        return latestMinorVersion == null ? DBVersion.from(currentMajorVersion, BigInteger.valueOf(Integer.MIN_VALUE)) : DBVersion.from(currentMajorVersion, latestMinorVersion);
+    }
+
+    public void clearTasksForCurrentMajor() {
+        BigInteger currentMajorVersion = DBVersion.CURRENT_VERSION.getMajor();
+        migrationTasksDao.deleteAllTasksForVersion(currentMajorVersion);
+    }
+
+    public void createMigrationTask(MigrationTaskEntry migrationTaskEntry) {
+        migrationTasksDao.createMigrationTask(migrationTaskEntry);
+    }
+
+
+
+}
diff --git a/asdctool/src/main/java/org/openecomp/sdc/asdctool/migration/tasks/mig1710/ExampleMigration.java b/asdctool/src/main/java/org/openecomp/sdc/asdctool/migration/tasks/mig1710/ExampleMigration.java
new file mode 100644
index 0000000..1302dc2
--- /dev/null
+++ b/asdctool/src/main/java/org/openecomp/sdc/asdctool/migration/tasks/mig1710/ExampleMigration.java
@@ -0,0 +1,27 @@
+//package org.openecomp.sdc.asdctool.migration.tasks.mig1710;//package org.openecomp.sdc.migration.tasks.mig1710;
+//
+//import org.openecomp.sdc.asdctool.migration.core.DBVersion;
+//import org.openecomp.sdc.asdctool.migration.core.task.Migration;
+//import org.openecomp.sdc.asdctool.migration.core.task.MigrationResult;
+//import org.springframework.stereotype.Component;
+//
+//@Component
+//public class ExampleMigration implements Migration {
+//
+//    @Override
+//    public String description() {
+//        return "some description";
+//    }
+//
+//    @Override
+//    public DBVersion getVersion() {
+//        return DBVersion.fromString("1710.0");
+//    }
+//
+//    @Override
+//    public MigrationResult migrate() {
+//        MigrationResult migrationResult = new MigrationResult();
+//        migrationResult.setMigrationStatus(MigrationResult.MigrationStatus.COMPLETED);
+//        return migrationResult;
+//    }
+//}
\ No newline at end of file
diff --git a/asdctool/src/main/resources/config/configuration.yaml b/asdctool/src/main/resources/config/configuration.yaml
index b998e2c..0421d65 100644
--- a/asdctool/src/main/resources/config/configuration.yaml
+++ b/asdctool/src/main/resources/config/configuration.yaml
@@ -507,6 +507,7 @@
         - { name: sdcaudit, replicationStrategy: SimpleStrategy, replicationInfo: ['1']}
         - { name: sdcartifact, replicationStrategy: SimpleStrategy, replicationInfo: ['1']}
         - { name: sdccomponent, replicationStrategy: SimpleStrategy, replicationInfo: ['1']}
+        - { name: sdcrepository, replicationStrategy: SimpleStrategy, replicationInfo: ['1']}
         
        
 switchoverDetector:
diff --git a/asdctool/src/main/resources/config/logback.xml b/asdctool/src/main/resources/config/logback.xml
index 0426a32..dadc525 100644
--- a/asdctool/src/main/resources/config/logback.xml
+++ b/asdctool/src/main/resources/config/logback.xml
@@ -4,7 +4,16 @@
 	<property scope="system" name="ECOMP-subcomponent-name" value="SDC-TOOL" />
 	<property name="default-log-pattern"
 		value="%d{yyyy-MM-dd'T'HH:mm:ss.SSSXXX}|%X{uuid}|%X{serviceInstanceID}|%thread||${ECOMP-subcomponent-name}|%X{userId}|%level|%X{alarmSeverity}|%X{localAddr}|${beFqdn}|%X{remoteAddr}|%logger{35}|%X{timer}|ActivityType=&lt;%M&gt;, Desc=&lt;%msg&gt;%n" />
-	
+
+
+	<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+		<layout class="ch.qos.logback.classic.PatternLayout">
+			<encoder>
+				<pattern>${default-log-pattern}</pattern>
+			</encoder>
+		</layout>
+	</appender>
+
 	<appender name="DEBUG_ROLLING"
 		class="ch.qos.logback.core.rolling.RollingFileAppender">
 		<file>${HOME}/asdctool/logs/${ECOMP-component-name}/${ECOMP-subcomponent-name}/debug.log</file>
@@ -65,4 +74,8 @@
 		<appender-ref ref="MALFORMED_DATA"/>
 	</logger>
 
+	<logger name="org.openecomp.sdc.asdctool.migration" level="INFO" >
+		<appender-ref ref="STDOUT"/>
+	</logger>
+
 </configuration>
\ No newline at end of file
diff --git a/asdctool/src/main/resources/scripts/postMigration1707Fix.sh b/asdctool/src/main/resources/scripts/postMigration1707Fix.sh
new file mode 100644
index 0000000..56a16db
--- /dev/null
+++ b/asdctool/src/main/resources/scripts/postMigration1707Fix.sh
@@ -0,0 +1,35 @@
+#!/bin/bash
+
+##############################
+# Data Migration 1707
+##############################
+
+CURRENT_DIR=`pwd`
+BASEDIR=$(dirname $0)
+
+if [ ${BASEDIR:0:1} = "/" ]
+then
+                FULL_PATH=$BASEDIR
+else
+                FULL_PATH=$CURRENT_DIR/$BASEDIR
+fi
+
+source ${FULL_PATH}/baseOperation.sh
+
+mainClass="org.openecomp.sdc.asdctool.main.MigrationMenu"
+
+command="java $JVM_LOG_FILE -Xmx6000M -cp $JARS $mainClass fix-missing-info-1707 $@"
+echo $command
+
+$command
+result=$?
+
+
+
+echo "***********************************"
+echo "***** $result *********************"
+echo "***********************************"
+
+exit $result
+
+
diff --git a/asdctool/src/main/resources/scripts/sdc-migration.sh b/asdctool/src/main/resources/scripts/sdc-migration.sh
new file mode 100644
index 0000000..1616890
--- /dev/null
+++ b/asdctool/src/main/resources/scripts/sdc-migration.sh
@@ -0,0 +1,36 @@
+#!/bin/bash
+
+##############################
+# Data Migration
+##############################
+
+CURRENT_DIR=`pwd`
+BASEDIR=$(dirname $0)
+
+if [ ${BASEDIR:0:1} = "/" ]
+then
+                FULL_PATH=$BASEDIR
+else
+                FULL_PATH=$CURRENT_DIR/$BASEDIR
+fi
+
+source ${FULL_PATH}/baseOperation.sh
+
+mainClass="org.openecomp.sdc.asdctool.migration.main.MigrationMenu"
+
+command="java $JVM_LOG_FILE -Xmx6000M -cp $JARS $mainClass $@"
+echo $command
+
+$command
+result=$?
+
+
+
+echo "***********************************"
+echo "***** $result *********************"
+echo "***********************************"
+
+exit $result
+
+
+
diff --git a/asdctool/src/test/java/org/openecomp/sdc/asdctool/migration/DummyMigrationFactory.java b/asdctool/src/test/java/org/openecomp/sdc/asdctool/migration/DummyMigrationFactory.java
new file mode 100644
index 0000000..b16951e
--- /dev/null
+++ b/asdctool/src/test/java/org/openecomp/sdc/asdctool/migration/DummyMigrationFactory.java
@@ -0,0 +1,72 @@
+package org.openecomp.sdc.asdctool.migration;
+
+
+import org.openecomp.sdc.asdctool.migration.core.DBVersion;
+import org.openecomp.sdc.asdctool.migration.core.task.Migration;
+import org.openecomp.sdc.asdctool.migration.core.task.MigrationResult;
+
+public class DummyMigrationFactory {
+
+    public static Migration SUCCESSFUL_MIGRATION = new Migration() {
+        @Override
+        public String description() {
+            return "success mig";
+        }
+
+        @Override
+        public DBVersion getVersion() {
+            return DBVersion.fromString("1710.22");
+        }
+
+        @Override
+        public MigrationResult migrate() {
+            MigrationResult migrationResult = new MigrationResult();
+            migrationResult.setMigrationStatus(MigrationResult.MigrationStatus.COMPLETED);
+            migrationResult.setMsg("myMsg");
+            return migrationResult;
+        }
+    };
+
+    public static Migration FAILED_MIGRATION = new Migration() {
+        @Override
+        public String description() {
+            return "failed mig";
+        }
+
+        @Override
+        public DBVersion getVersion() {
+            return DBVersion.fromString("1710.22");
+        }
+
+        @Override
+        public MigrationResult migrate() {
+            MigrationResult migrationResult = new MigrationResult();
+            migrationResult.setMigrationStatus(MigrationResult.MigrationStatus.FAILED);
+            migrationResult.setMsg("myMsg");
+            return migrationResult;
+        }
+    };
+
+    public static Migration getMigration(String version, MigrationResult.MigrationStatus status) {
+        return new Migration() {
+            @Override
+            public String description() {
+                return "success mig";
+            }
+
+            @Override
+            public DBVersion getVersion() {
+                return DBVersion.fromString(version);
+            }
+
+            @Override
+            public MigrationResult migrate() {
+                MigrationResult migrationResult = new MigrationResult();
+                migrationResult.setMigrationStatus(status);
+                migrationResult.setMsg("myMsg");
+                return migrationResult;
+            }
+        };
+    }
+
+}
diff --git a/asdctool/src/test/java/org/openecomp/sdc/asdctool/migration/core/DBVersionTest.java b/asdctool/src/test/java/org/openecomp/sdc/asdctool/migration/core/DBVersionTest.java
new file mode 100644
index 0000000..4e5fd3a
--- /dev/null
+++ b/asdctool/src/test/java/org/openecomp/sdc/asdctool/migration/core/DBVersionTest.java
@@ -0,0 +1,57 @@
+package org.openecomp.sdc.asdctool.migration.core;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertEquals;
+
+public class DBVersionTest {
+
+
+    @DataProvider(name = "invalidVersionStringsProvider")
+    private Object[][] invalidVersionStringsProvider() {
+        return new Object[][] {
+                {"1.1.1"},
+                {"1.a"},
+                {"a.1"},
+                {"1"}
+        };
+    }
+
+    @Test(dataProvider = "invalidVersionStringsProvider", expectedExceptions = MigrationException.class)
+    public void testFromString_invalidVersionString(String invalidVersion) {
+        DBVersion.fromString(invalidVersion);
+    }
+
+    @DataProvider(name = "validVersionStringsProvider")
+    private Object[][] validVersionStringsProvider() {
+        return new Object[][] {
+                {"1.1", "1.1"},
+                {"10100.0001", "10100.1"},
+                {"000.1", "0.1"},
+                {"01.00001000", "1.1000"},
+        };
+    }
+
+    @Test(dataProvider = "validVersionStringsProvider")
+    public void testFromString(String validString, String expectedVersionString) {
+        assertEquals(expectedVersionString, DBVersion.fromString(validString).toString());
+    }
+
+    @DataProvider(name = "versionComparisionProvider")
+    public static Object[][] versionComparisionProvider() {
+        return new Object[][] {
+                {"1.1", "001.00001", 0},
+                {"10.1", "0010.00001", 0},
+                {"1.1", "001.000010", -1},
+                {"1.1", "0010.00001", -1},
+                {"10.10", "0010.00001", 1},
+                {"1.1", "001.00", 1},
+        };
+    }
+
+    @Test(dataProvider = "versionComparisionProvider")
+    public void testVersionCompareTo2(String firstVersion, String otherVersion, int expectedComparisionResult) throws Exception {
+        assertEquals(DBVersion.fromString(firstVersion).compareTo(DBVersion.fromString(otherVersion)), expectedComparisionResult);
+    }
+}
diff --git a/asdctool/src/test/java/org/openecomp/sdc/asdctool/migration/core/SdcMigrationToolTest.java b/asdctool/src/test/java/org/openecomp/sdc/asdctool/migration/core/SdcMigrationToolTest.java
new file mode 100644
index 0000000..b181322
--- /dev/null
+++ b/asdctool/src/test/java/org/openecomp/sdc/asdctool/migration/core/SdcMigrationToolTest.java
@@ -0,0 +1,101 @@
+package org.openecomp.sdc.asdctool.migration.core;
+
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.mockito.internal.verification.Times;
+import org.openecomp.sdc.asdctool.migration.core.task.Migration;
+import org.openecomp.sdc.asdctool.migration.core.task.MigrationResult;
+import org.openecomp.sdc.asdctool.migration.resolver.MigrationResolver;
+import org.openecomp.sdc.asdctool.migration.service.SdcRepoService;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import java.util.Arrays;
+import java.util.Collections;
+
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class SdcMigrationToolTest {
+
+    @InjectMocks
+    private SdcMigrationTool testInstance = spy(SdcMigrationTool.class);
+
+    @Mock
+    private MigrationResolver migrationResolverMock;
+
+    @Mock
+    private SdcRepoService sdcRepoServiceMock;
+
+    @BeforeMethod
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    @Test
+    public void testMigrate_noMigrations() throws Exception {
+        when(migrationResolverMock.resolveMigrations()).thenReturn(Collections.emptyList());
+        testInstance.migrate(false);
+        verify(sdcRepoServiceMock, new Times(0)).clearTasksForCurrentMajor();
+        verify(sdcRepoServiceMock, new Times(0)).createMigrationTask(Mockito.any());
+    }
+
+    @Test
+    public void testMigrate_enforceFlag_removeAllMigrationTasksForCurrentVersion() throws Exception {
+        when(migrationResolverMock.resolveMigrations()).thenReturn(Collections.emptyList());
+        testInstance.migrate(true);
+        verify(sdcRepoServiceMock, new Times(1)).clearTasksForCurrentMajor();
+    }
+
+    @Test
+    public void testMigrate_stopAfterFirstFailure() throws Exception {
+        when(migrationResolverMock.resolveMigrations()).thenReturn(Arrays.asList(new SuccessfulMigration(), new FailedMigration(), new SuccessfulMigration()));
+        testInstance.migrate(false);
+        verify(sdcRepoServiceMock, new Times(0)).clearTasksForCurrentMajor();
+        verify(sdcRepoServiceMock, new Times(1)).createMigrationTask(Mockito.any());
+
+    }
+
+    private class FailedMigration implements Migration {
+
+        @Override
+        public String description() {
+            return null;
+        }
+
+        @Override
+        public DBVersion getVersion() {
+            return DBVersion.fromString("1710.22");
+        }
+
+        @Override
+        public MigrationResult migrate() {
+            MigrationResult migrationResult = new MigrationResult();
+            migrationResult.setMigrationStatus(MigrationResult.MigrationStatus.FAILED);
+            return migrationResult;
+        }
+    }
+
+    private class SuccessfulMigration implements Migration {
+
+        @Override
+        public String description() {
+            return null;
+        }
+
+        @Override
+        public DBVersion getVersion() {
+            return DBVersion.fromString("1710.22");
+        }
+
+        @Override
+        public MigrationResult migrate() {
+            MigrationResult migrationResult = new MigrationResult();
+            migrationResult.setMigrationStatus(MigrationResult.MigrationStatus.COMPLETED);
+            return migrationResult;
+        }
+    }
+}
diff --git a/asdctool/src/test/java/org/openecomp/sdc/asdctool/migration/core/execution/MigrationExecutorImplTest.java b/asdctool/src/test/java/org/openecomp/sdc/asdctool/migration/core/execution/MigrationExecutorImplTest.java
new file mode 100644
index 0000000..763d6c8
--- /dev/null
+++ b/asdctool/src/test/java/org/openecomp/sdc/asdctool/migration/core/execution/MigrationExecutorImplTest.java
@@ -0,0 +1,47 @@
+package org.openecomp.sdc.asdctool.migration.core.execution;
+
+import org.openecomp.sdc.asdctool.migration.core.DBVersion;
+import org.openecomp.sdc.asdctool.migration.core.task.Migration;
+import org.openecomp.sdc.asdctool.migration.core.task.MigrationResult;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+
+public class MigrationExecutorImplTest {
+
+    @Test
+    public void testExecuteMigration() throws Exception {
+        MigrationExecutionResult execute = new MigrationExecutorImpl().execute(new DummyMigration());
+
+    }
+
+    private void assertMigrationTaskEntryByMigrationExecutionResult(MigrationExecutionResult executionResult, Migration migration, MigrationResult result) {
+        assertEquals(executionResult.getMsg(), result.getMsg());
+        assertEquals(executionResult.getMigrationStatus().name(), result.getMigrationStatus());
+        assertEquals(executionResult.getTaskName(), migration.getClass().getName());
+        assertEquals(executionResult.getVersion(), migration.getVersion());
+        assertNotNull(executionResult.getExecutionTime());
+    }
+
+    private class DummyMigration implements Migration {
+
+        @Override
+        public String description() {
+            return null;
+        }
+
+        @Override
+        public DBVersion getVersion() {
+            return DBVersion.fromString("1710.22");
+        }
+
+        @Override
+        public MigrationResult migrate() {
+            MigrationResult migrationResult = new MigrationResult();
+            migrationResult.setMigrationStatus(MigrationResult.MigrationStatus.COMPLETED);
+            migrationResult.setMsg("myMsg");
+            return migrationResult;
+        }
+    }
+}
diff --git a/asdctool/src/test/java/org/openecomp/sdc/asdctool/migration/resolver/SpringBeansMigrationResolverTest.java b/asdctool/src/test/java/org/openecomp/sdc/asdctool/migration/resolver/SpringBeansMigrationResolverTest.java
new file mode 100644
index 0000000..6084608
--- /dev/null
+++ b/asdctool/src/test/java/org/openecomp/sdc/asdctool/migration/resolver/SpringBeansMigrationResolverTest.java
@@ -0,0 +1,84 @@
+package org.openecomp.sdc.asdctool.migration.resolver;
+
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.openecomp.sdc.asdctool.migration.core.DBVersion;
+import org.openecomp.sdc.asdctool.migration.core.task.Migration;
+import org.openecomp.sdc.asdctool.migration.core.task.MigrationResult;
+import org.openecomp.sdc.asdctool.migration.service.SdcRepoService;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import static org.mockito.Mockito.when;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+public class SpringBeansMigrationResolverTest {
+
+    @InjectMocks
+    private SpringBeansMigrationResolver testInstance;
+
+    @Mock
+    private SdcRepoService sdcRepoServiceMock;
+
+    private List<Migration> migrations = Arrays.asList(createMigration("1710.1"), createMigration("1710.22"), createMigration("1707.12"), createMigration("1710.3"));
+
+
+    @BeforeMethod
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        testInstance.setMigrations(migrations);
+    }
+
+    @Test
+    public void testResolveMigrations_getMigrationsWithVersionGreaterThanLatest() throws Exception {
+        when(sdcRepoServiceMock.getLatestDBVersion()).thenReturn(DBVersion.fromString("1710.2"));
+        List<Migration> resolvedMigrations = testInstance.resolveMigrations();
+        assertEquals(resolvedMigrations.size(), 2);
+        assertEquals(resolvedMigrations.get(0).getVersion(), DBVersion.fromString("1710.3"));
+        assertEquals(resolvedMigrations.get(1).getVersion(), DBVersion.fromString("1710.22"));
+    }
+
+    @Test
+    public void testResolveMigration_noLatestVersionForCurrentMajorVersion() throws Exception {
+        when(sdcRepoServiceMock.getLatestDBVersion()).thenReturn(DBVersion.fromString("1710.-1"));
+        List<Migration> resolvedMigrations = testInstance.resolveMigrations();
+        assertEquals(resolvedMigrations.size(), 3);
+        assertEquals(resolvedMigrations.get(0).getVersion(), DBVersion.fromString("1710.1"));
+        assertEquals(resolvedMigrations.get(1).getVersion(), DBVersion.fromString("1710.3"));
+        assertEquals(resolvedMigrations.get(2).getVersion(), DBVersion.fromString("1710.22"));
+    }
+
+    @Test
+    public void testResolveMigrations_emptyMigrationsList() throws Exception {
+        testInstance.setMigrations(Collections.emptyList());
+        when(sdcRepoServiceMock.getLatestDBVersion()).thenReturn(DBVersion.fromString("1710.-1"));
+        List<Migration> resolvedMigrations = testInstance.resolveMigrations();
+        assertTrue(resolvedMigrations.isEmpty());
+    }
+
+    private Migration createMigration(String version) {
+        return new Migration() {
+            @Override
+            public String description() {
+                return null;
+            }
+
+            @Override
+            public DBVersion getVersion() {
+                return DBVersion.fromString(version);
+            }
+
+            @Override
+            public MigrationResult migrate() {
+                return null;
+            }
+        };
+    }
+
+}
diff --git a/asdctool/src/test/java/org/openecomp/sdc/asdctool/migration/scanner/ClassScanner.java b/asdctool/src/test/java/org/openecomp/sdc/asdctool/migration/scanner/ClassScanner.java
new file mode 100644
index 0000000..a2bf623
--- /dev/null
+++ b/asdctool/src/test/java/org/openecomp/sdc/asdctool/migration/scanner/ClassScanner.java
@@ -0,0 +1,81 @@
+package org.openecomp.sdc.asdctool.migration.scanner;
+
+import org.apache.commons.io.FileUtils;
+import org.openecomp.sdc.asdctool.migration.core.MigrationException;
+
+import java.io.File;
+import java.lang.reflect.Modifier;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * scan and instantiate classes of given type in the class path
+ */
+public class ClassScanner {
+
+
+    private ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
+
+    public <T> List<T> getAllClassesOfType(String basePackage, Class<T> ofType) {
+        Collection<File> allClassesInPackage = getAllClassesInPackage(basePackage);
+        List<T> loadedClasses = new ArrayList<>();
+        for (File clazzFile : allClassesInPackage) {
+            Optional<T> instance = loadAndInstantiateClass(getClassReference(clazzFile), ofType);
+            instance.ifPresent(loadedClasses::add);
+        }
+        return loadedClasses;
+    }
+
+    private <T> Optional<T> loadAndInstantiateClass(String classReference, Class<T> ofType)  {
+        try {
+            return instantiateClassOfType(classReference, ofType);
+        }catch (ClassNotFoundException e) {
+            //log
+            throw new MigrationException(String.format("could not find class %s of type %s. cause: %s", classReference, ofType.toGenericString(), e.getMessage()));
+        } catch (IllegalAccessException e1) {
+            //log
+            throw new MigrationException(String.format("could not instantiate class %s of type %s. class is not accessible. cause: %s", classReference, ofType.toGenericString(), e1.getMessage()));
+        } catch (InstantiationException e2) {
+            //log
+            throw new MigrationException(String.format("could not instantiate class %s of type %s. cause: %s", classReference, ofType.toGenericString(), e2.getMessage()));
+        }
+    }
+
+    private <T> Optional<T> instantiateClassOfType(String classReference, Class<T> ofType) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
+        String className = classReference.replaceAll(".class$", "").replaceAll(".class", "");
+        Class<?> aClass = classLoader.loadClass(className);
+        if (ofType.isAssignableFrom(aClass) && isInstantiateAbleClass(aClass)){
+            return Optional.of((T) aClass.newInstance());
+        }
+        return Optional.empty();
+    }
+
+    private boolean isInstantiateAbleClass(Class<?> clazz) {
+        return !Modifier.isAbstract(clazz.getModifiers()) && !clazz.isEnum() && !clazz.isAnonymousClass() && !clazz.isInterface();
+    }
+
+    private Collection<File> getAllClassesInPackage(String fromPackage) {
+        String path = fromPackage.replace(".", "/");
+        URL resource = classLoader.getResource(path);
+        if (noMigrationTasks(resource)) {
+            return Collections.emptyList();
+        }
+        return FileUtils.listFiles(new File(resource.getFile()), new String[]{"class"}, true);
+    }
+
+    private boolean noMigrationTasks(URL resource) {
+        return resource == null;
+    }
+
+    private String getClassReference(File classFile) {
+        String asPackage = classFile.getPath().replace(File.separator, ".");
+        String classes = "classes.";
+        return asPackage.substring(asPackage.indexOf(classes) + classes.length());
+    }
+
+
+}
diff --git a/asdctool/src/test/java/org/openecomp/sdc/asdctool/migration/service/SdcRepoServiceTest.java b/asdctool/src/test/java/org/openecomp/sdc/asdctool/migration/service/SdcRepoServiceTest.java
new file mode 100644
index 0000000..f8e9abe
--- /dev/null
+++ b/asdctool/src/test/java/org/openecomp/sdc/asdctool/migration/service/SdcRepoServiceTest.java
@@ -0,0 +1,55 @@
+package org.openecomp.sdc.asdctool.migration.service;
+
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.internal.verification.Times;
+import org.openecomp.sdc.asdctool.migration.core.DBVersion;
+import org.openecomp.sdc.be.dao.cassandra.MigrationTasksDao;
+import org.openecomp.sdc.be.resources.data.MigrationTaskEntry;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import java.math.BigInteger;
+
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.testng.Assert.assertEquals;
+
+public class SdcRepoServiceTest {
+
+    @InjectMocks
+    private SdcRepoService testInstance;
+
+    @Mock
+    private MigrationTasksDao migrationTasksDaoMock;
+
+    @BeforeMethod
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    @Test
+    public void testGetLatestVersion_noMinorVersionForCurrentVersion() throws Exception {
+        when(migrationTasksDaoMock.getLatestMinorVersion(DBVersion.CURRENT_VERSION.getMajor())).thenReturn(null);
+        DBVersion latestDBVersion = testInstance.getLatestDBVersion();
+        assertEquals(latestDBVersion.getMajor(), DBVersion.CURRENT_VERSION.getMajor());
+        assertEquals(latestDBVersion.getMinor(), BigInteger.valueOf(Integer.MIN_VALUE));
+    }
+
+    @Test
+    public void testGetLatestVersion() throws Exception {
+        when(migrationTasksDaoMock.getLatestMinorVersion(DBVersion.CURRENT_VERSION.getMajor())).thenReturn(BigInteger.TEN);
+        DBVersion latestDBVersion = testInstance.getLatestDBVersion();
+        assertEquals(latestDBVersion.getMajor(), DBVersion.CURRENT_VERSION.getMajor());
+        assertEquals(latestDBVersion.getMinor(), BigInteger.TEN);
+    }
+
+    @Test
+    public void testCreateMigrationTask() throws Exception {
+        MigrationTaskEntry taskEntry =  new MigrationTaskEntry();
+        testInstance.createMigrationTask(taskEntry);
+        verify(migrationTasksDaoMock, new Times(1)).createMigrationTask(taskEntry);
+    }
+
+}
diff --git a/asdctool/src/test/java/org/openecomp/sdc/asdctool/migration/task/MigrationTasksTest.java b/asdctool/src/test/java/org/openecomp/sdc/asdctool/migration/task/MigrationTasksTest.java
new file mode 100644
index 0000000..037d51b
--- /dev/null
+++ b/asdctool/src/test/java/org/openecomp/sdc/asdctool/migration/task/MigrationTasksTest.java
@@ -0,0 +1,56 @@
+package org.openecomp.sdc.asdctool.migration.task;
+
+import org.apache.commons.lang.StringUtils;
+import org.openecomp.sdc.asdctool.migration.core.DBVersion;
+import org.openecomp.sdc.asdctool.migration.core.task.Migration;
+import org.openecomp.sdc.asdctool.migration.scanner.ClassScanner;
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+
+public class MigrationTasksTest  {
+
+    public static final String MIGRATIONS_BASE_PACKAGE = "org.openecomp.sdc.asdctool.migration.tasks";
+    private List<Migration> migrations;
+
+    @BeforeMethod
+    public void setUp() throws Exception {
+        ClassScanner classScanner = new ClassScanner();
+        migrations = classScanner.getAllClassesOfType(MIGRATIONS_BASE_PACKAGE, Migration.class);
+    }
+
+    @Test
+    public void testNoTasksWithSameVersion() throws Exception {
+        Map<DBVersion, List<Migration>> migrationsByVersion = migrations.stream().collect(Collectors.groupingBy(Migration::getVersion));
+        migrationsByVersion.forEach((version, migrations) -> {
+            if (migrations.size() > 1) {
+                System.out.println(String.format("the following migration tasks have the same version %s. versions must be unique", version.toString()));
+                Assert.fail(String.format("migration tasks %s has same version %s. migration tasks versions must be unique.", getMigrationsNameAsString(migrations), version.toString()));
+            }
+        });
+    }
+
+    @Test
+    public void testNoTaskWithVersionGreaterThanCurrentVersion() throws Exception {
+        Set<Migration> migrationsWithVersionsGreaterThanCurrent = migrations.stream().filter(mig -> mig.getVersion().compareTo(DBVersion.CURRENT_VERSION) > 0)
+                .collect(Collectors.toSet());
+
+        if (!migrationsWithVersionsGreaterThanCurrent.isEmpty()) {
+            Assert.fail(String.format("migrations tasks %s have version which is greater than DBVersion.CURRENT_VERSION %s. did you forget to update current version?",
+                               getMigrationsNameAsString(migrationsWithVersionsGreaterThanCurrent),
+                               DBVersion.CURRENT_VERSION.toString()));
+        }
+    }
+
+    private String getMigrationsNameAsString(Collection<Migration> migrations) {
+        return StringUtils.join(migrations.stream().map(mig -> mig.getClass().getName()).collect(Collectors.toList()), ",");
+    }
+}