You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kylin.apache.org by xx...@apache.org on 2021/04/21 02:38:43 UTC
[kylin] branch kylin-on-parquet-v2 updated: KYLIN-4923
CubeMigration Tools support migrate meta from 2.x/3.x cluster to 4.0
cluster
This is an automated email from the ASF dual-hosted git repository.
xxyu pushed a commit to branch kylin-on-parquet-v2
in repository https://gitbox.apache.org/repos/asf/kylin.git
The following commit(s) were added to refs/heads/kylin-on-parquet-v2 by this push:
new e6ca98d KYLIN-4923 CubeMigration Tools support migrate meta from 2.x/3.x cluster to 4.0 cluster
e6ca98d is described below
commit e6ca98d9e047efee4e6505e55f5aca573c9c0052
Author: zhengshengjun <sh...@sina.com>
AuthorDate: Mon Mar 8 16:52:50 2021 +0800
KYLIN-4923 CubeMigration Tools support migrate meta from 2.x/3.x cluster to 4.0 cluster
---
.../org/apache/kylin/tool/CubeMigrationCLI.java | 274 +++++++++++++++------
1 file changed, 197 insertions(+), 77 deletions(-)
diff --git a/tool/src/main/java/org/apache/kylin/tool/CubeMigrationCLI.java b/tool/src/main/java/org/apache/kylin/tool/CubeMigrationCLI.java
index 8a18f25..fd978a3 100644
--- a/tool/src/main/java/org/apache/kylin/tool/CubeMigrationCLI.java
+++ b/tool/src/main/java/org/apache/kylin/tool/CubeMigrationCLI.java
@@ -18,26 +18,38 @@
package org.apache.kylin.tool;
+import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
+import java.io.ByteArrayOutputStream;
+import java.io.ByteArrayInputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.Locale;
+import java.util.Arrays;
+
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.OptionBuilder;
+import org.apache.commons.cli.OptionGroup;
import org.apache.commons.cli.Options;
+import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.FileUtil;
import org.apache.hadoop.fs.Path;
import org.apache.kylin.common.KylinConfig;
+import org.apache.kylin.common.KylinVersion;
import org.apache.kylin.common.StorageURL;
import org.apache.kylin.common.persistence.JsonSerializer;
import org.apache.kylin.common.persistence.RawResource;
import org.apache.kylin.common.persistence.ResourceStore;
import org.apache.kylin.common.persistence.Serializer;
+import org.apache.kylin.common.persistence.ContentReader;
import org.apache.kylin.common.restclient.RestClient;
import org.apache.kylin.common.util.AbstractApplication;
import org.apache.kylin.common.util.HadoopUtil;
@@ -55,7 +67,10 @@ import org.apache.kylin.metadata.model.TableDesc;
import org.apache.kylin.metadata.model.TableRef;
import org.apache.kylin.metadata.model.TableExtDesc;
import org.apache.kylin.metadata.model.DataModelManager;
+import org.apache.kylin.metadata.model.IStorageAware;
+import org.apache.kylin.metadata.model.IEngineAware;
import org.apache.kylin.metadata.project.ProjectInstance;
+import org.apache.kylin.metadata.project.ProjectManager;
import org.apache.kylin.metadata.realization.RealizationStatusEnum;
import org.apache.kylin.metadata.realization.RealizationType;
import org.slf4j.Logger;
@@ -82,110 +97,161 @@ public class CubeMigrationCLI extends AbstractApplication {
protected Configuration conf;
protected boolean doAclCopy = false;
protected boolean doOverwrite = false;
- protected boolean doMigrateSegment = true;
+ protected boolean doMigrateSegment = false;
protected String dstProject;
protected String srcHdfsWorkDir;
protected String dstHdfsWorkDir;
+ private boolean realExecute;
+ private boolean purgeAndDisable;
+ private OptionsHelper optHelper;
private static final String ACL_PREFIX = "/acl/";
private static final String GLOBAL_DICT_PREFIX = "/dict/global_dict/";
- public static void main(String[] args) throws IOException, InterruptedException {
+ private static final Option OPTION_SRC_CONFIG = OptionBuilder.isRequired(true).hasArg().withDescription("The KylinConfig of the cube’s source").create("srcConfig");
+ private static final Option OPTION_DST_CONFIG = OptionBuilder.isRequired(true).hasArg().withDescription("The KylinConfig of the cube’s new home").create("dstConfig");
+ private static final Option OPTION_ALL_CUBES = OptionBuilder.isRequired(false).withDescription("migrate all cubes meta from source cluster").create("allCubes");
+ private static final Option OPTION_CUBE = OptionBuilder.isRequired(false).hasArg().withDescription("Cube name to migrate").create("cube");
+ private static final Option OPTION_DST_PROJECT = OptionBuilder.isRequired(false).hasArg().withDescription("cube's new project home, if not set, keep the same as source cluster").create("dstProject");
+ private static final Option OPTION_SRC_PROJECT = OptionBuilder.isRequired(false).hasArg().withDescription("source project to migrate").create("srcProject");
+ private static final Option OPTION_COPY_ACL = OptionBuilder.isRequired(false).hasArg().withDescription("copy ACL").create("copyAcl");
+ private static final Option OPTION_PURGE_AND_DISABLE = OptionBuilder.isRequired(false).withDescription("purge source cluster data").create("purgeAndDisable");
+ private static final Option OPTION_OVERWRITE = OptionBuilder.isRequired(false).withDescription("overwrite target cluster's meta if exists").create("overwriteIfExists");
+ private static final Option OPTION_EXECUTE = OptionBuilder.isRequired(false).hasArg().withDescription("execute migration").create("realMigrate");
+ private static final Option OPTION_MIGRATE_SEGMENTS = OptionBuilder.isRequired(false).withDescription("migrate segment data").create("migrateSegment");
+
+ public static void main(String[] args) throws Exception {
+ CubeMigrationCLI cli = new CubeMigrationCLI();
+ cli.init(args);
+ cli.moveCube();
+ }
+ public void init(String[] args) {
+ optHelper = new OptionsHelper();
CubeMigrationCLI cli = new CubeMigrationCLI();
- if (args.length != 8 && args.length != 9) {
- cli.usage();
+ try {
+ optHelper.parseOptions(cli.getOptions(), args);
+ } catch (Exception e) {
+ logger.error("failed to parse arguments", e);
+ optHelper.printUsage("CubeMigrationCLI", cli.getOptions());
System.exit(1);
}
- if (args.length == 8) {
- cli.moveCube(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]);
- } else if (args.length == 9) {
- cli.moveCube(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]);
- }
+ doAclCopy = optHelper.hasOption(OPTION_COPY_ACL);
+ doOverwrite = optHelper.hasOption(OPTION_OVERWRITE);
+ doMigrateSegment = optHelper.hasOption(OPTION_MIGRATE_SEGMENTS);
+ purgeAndDisable = optHelper.hasOption(OPTION_PURGE_AND_DISABLE);
+ srcConfig = KylinConfig.createInstanceFromUri(optHelper.getOptionValue(OPTION_SRC_CONFIG));
+ srcStore = ResourceStore.getStore(srcConfig);
+ dstConfig = KylinConfig.createInstanceFromUri(optHelper.getOptionValue(OPTION_DST_CONFIG));
+ dstStore = ResourceStore.getStore(dstConfig);
+ realExecute = optHelper.hasOption(OPTION_EXECUTE) ? Boolean.valueOf(optHelper.getOptionValue(OPTION_EXECUTE)) : true;
+ dstProject = optHelper.getOptionValue(OPTION_DST_PROJECT);
+ conf = HadoopUtil.getCurrentConfiguration();
}
- protected void usage() {
- System.out.println(
- "Usage: CubeMigrationCLI srcKylinConfigUri dstKylinConfigUri cubeName projectName copyAclOrNot purgeOrNot overwriteIfExists realExecute migrateSegmentOrNot");
- System.out.println("srcKylinConfigUri: The KylinConfig of the cube’s source \n"
- + "dstKylinConfigUri: The KylinConfig of the cube’s new home \n"
- + "cubeName: the name of cube to be migrated. \n"
- + "projectName: The target project in the target environment.(Make sure it exist) \n"
- + "copyAclOrNot: true or false: whether copy cube ACL to target environment. \n"
- + "purgeOrNot: true or false: whether purge the cube from src server after the migration. \n"
- + "overwriteIfExists: overwrite cube if it already exists in the target environment. \n"
- + "realExecute: if false, just print the operations to take, if true, do the real migration. \n"
- + "migrateSegmentOrNot:(optional) true or false: whether copy segment data to target environment. \n");
-
- }
+ public void moveCube() throws Exception {
+ conf = HadoopUtil.getCurrentConfiguration();
- public void moveCube(String srcCfgUri, String dstCfgUri, String cubeName, String projectName, String copyAcl,
- String purgeAndDisable, String overwriteIfExists, String realExecute)
- throws IOException, InterruptedException {
+ if (optHelper.hasOption(OPTION_CUBE)) {
+ CubeManager cubeManager = CubeManager.getInstance(srcConfig);
+ moveSingleCube(optHelper.getOptionValue(OPTION_CUBE), dstProject, cubeManager);
+ } else if (optHelper.hasOption(OPTION_SRC_PROJECT)) {
+ moveAllCubesUnderProject(optHelper.getOptionValue(OPTION_SRC_PROJECT), ProjectManager.getInstance(srcConfig), ProjectManager.getInstance(dstConfig));
+ } else if (optHelper.hasOption(OPTION_ALL_CUBES)) {
+ moveAllProjectAndCubes();
+ }
- moveCube(KylinConfig.createInstanceFromUri(srcCfgUri), KylinConfig.createInstanceFromUri(dstCfgUri), cubeName,
- projectName, copyAcl, purgeAndDisable, overwriteIfExists, realExecute);
}
- public void moveCube(KylinConfig srcCfg, KylinConfig dstCfg, String cubeName, String projectName, String copyAcl,
- String purgeAndDisable, String overwriteIfExists, String realExecute)
- throws IOException, InterruptedException {
+ private void moveAllCubesUnderProject(String srcProject, ProjectManager srcProjectManager, ProjectManager dstProjectManager) throws Exception {
+ ProjectInstance srcProjectInstance = srcProjectManager.getProject(srcProject);
- moveCube(srcCfg, dstCfg, cubeName, projectName, Boolean.parseBoolean(copyAcl),
- Boolean.parseBoolean(purgeAndDisable), Boolean.parseBoolean(overwriteIfExists),
- Boolean.parseBoolean(realExecute), true);
- }
+ if (StringUtils.isEmpty(dstProject)) {
+ if (null == dstProjectManager.getProject(srcProject)) {
+ dstProjectManager.createProject(srcProjectInstance.getName(),
+ srcProjectInstance.getOwner(), srcProjectInstance.getDescription(), srcProjectInstance.getOverrideKylinProps());
+ }
+ }
- public void moveCube(String srcCfgUri, String dstCfgUri, String cubeName, String projectName, String copyAcl,
- String purgeAndDisable, String overwriteIfExists, String realExecute, String migrateSegment)
- throws IOException, InterruptedException {
+ CubeManager cubeManager = CubeManager.getInstance(srcConfig);
+
+ srcProjectInstance.getRealizationEntries(RealizationType.CUBE).forEach(cube -> {
+ try {
+ if (StringUtils.isEmpty(dstProject)) {
+ moveSingleCube(cube.getRealization(), srcProject, cubeManager);
+ } else {
+ moveSingleCube(cube.getRealization(), dstProject, cubeManager);
+ }
+ } catch (Exception e) {
+ logger.error("failed to move cube: {}", cube.getRealization(), e);
+ }
+ });
- moveCube(KylinConfig.createInstanceFromUri(srcCfgUri), KylinConfig.createInstanceFromUri(dstCfgUri), cubeName,
- projectName, Boolean.parseBoolean(copyAcl), Boolean.parseBoolean(purgeAndDisable),
- Boolean.parseBoolean(overwriteIfExists), Boolean.parseBoolean(realExecute),
- Boolean.parseBoolean(migrateSegment));
}
- public void moveCube(KylinConfig srcCfg, KylinConfig dstCfg, String cubeName, String projectName, boolean copyAcl,
- boolean purgeAndDisable, boolean overwriteIfExists, boolean realExecute, boolean migrateSegment)
- throws IOException, InterruptedException {
- doAclCopy = copyAcl;
- doOverwrite = overwriteIfExists;
- doMigrateSegment = migrateSegment;
- srcConfig = srcCfg;
- srcStore = ResourceStore.getStore(srcConfig);
- dstConfig = dstCfg;
- dstStore = ResourceStore.getStore(dstConfig);
- dstProject = projectName;
- conf = HadoopUtil.getCurrentConfiguration();
+ private void moveAllProjectAndCubes() throws Exception {
+ ProjectManager srcProjectManager = ProjectManager.getInstance(srcConfig);
+ List<ProjectInstance> projects = srcProjectManager.listAllProjects();
+ for (ProjectInstance project : projects) {
+ moveAllCubesUnderProject(project.getName(), srcProjectManager, ProjectManager.getInstance(dstConfig));
+ }
+ }
- CubeManager cubeManager = CubeManager.getInstance(srcConfig);
+ private void moveSingleCube(String cubeName, String dstProject, CubeManager cubeManager) throws IOException, InterruptedException {
CubeInstance cube = cubeManager.getCube(cubeName);
- srcHdfsWorkDir = srcConfig.getHdfsWorkingDirectory(cube.getProject());
+
+ //if -dstProject option is not set, copy cube to its origin project name
+ if (StringUtils.isEmpty(dstProject)) {
+ dstProject = cube.getProject();
+ }
+
+ ProjectManager dstProjectManager = ProjectManager.getInstance(dstConfig);
+ ProjectInstance instance = dstProjectManager.getProject(dstProject);
+
+ if (null == instance) {
+ ProjectManager scrProjectManager = ProjectManager.getInstance(srcConfig);
+ ProjectInstance originProject = scrProjectManager.getProject(cube.getProject());
+ //create the same dstProject from cube's original project information
+ dstProjectManager.createProject(dstProject, originProject.getOwner(),
+ originProject.getDescription(), originProject.getOverrideKylinProps());
+ }
+
+ if (null == cube) {
+ logger.warn("source cube: {} not exists", cubeName);
+ return;
+ }
+
+ srcHdfsWorkDir = srcConfig.getHdfsWorkingDirectory(dstProject);
dstHdfsWorkDir = dstConfig.getHdfsWorkingDirectory(dstProject);
logger.info("cube to be moved is : " + cubeName);
- if (migrateSegment) {
+ if (doMigrateSegment) {
checkCubeState(cube);
+ KylinVersion srcVersion = new KylinVersion(cube.getVersion());
+ if (srcVersion.major != KylinVersion.getCurrentVersion().major) {
+ throw new IllegalArgumentException(String.format(Locale.ROOT,
+ "can not migrate segment data from version: %s to version: %s",
+ srcVersion.toString(), KylinVersion.getCurrentVersion().toString()));
+ }
}
checkAndGetMetadataUrl();
hdfsFs = HadoopUtil.getWorkingFileSystem();
operations = new ArrayList<Opt>();
- copyFilesInMetaStore(cube);
- if (!migrateSegment) {
+ copyFilesInMetaStore(cube, dstProject);
+ if (!doMigrateSegment) {
clearSegments(cubeName); // this should be after copyFilesInMetaStore
}
- addCubeAndModelIntoProject(cube, cubeName);
+ addCubeAndModelIntoProject(cube, cubeName, dstProject);
- if (migrateSegment && purgeAndDisable) {
+ if (doMigrateSegment && purgeAndDisable) {
purgeAndDisable(cubeName); // this should be the last action
}
if (realExecute) {
doOpts();
- updateMeta(dstConfig, projectName, cubeName, cube.getModel());
+ updateMeta(dstConfig, dstProject, cubeName, cube.getModel());
} else {
showOpts();
}
@@ -211,10 +277,10 @@ public class CubeMigrationCLI extends AbstractApplication {
}
protected void clearSegments(String cubeName) throws IOException {
- operations.add(new Opt(OptType.CLEAR_SEGMENTS, new Object[]{cubeName}));
+ operations.add(new Opt(OptType.CLEAR_SEGMENTS, new Object[]{cubeName}, null));
}
- protected void copyFilesInMetaStore(CubeInstance cube) throws IOException {
+ protected void copyFilesInMetaStore(CubeInstance cube, String dstProject) throws IOException {
if (dstStore.exists(cube.getResourcePath()) && !doOverwrite)
throw new IllegalStateException("The cube named " + cube.getName()
@@ -227,30 +293,30 @@ public class CubeMigrationCLI extends AbstractApplication {
listCubeRelatedResources(cube, metaItems, dictAndSnapshot, srcParquetFiles, dstParquetFiles);
for (String item : metaItems) {
- operations.add(new Opt(OptType.COPY_FILE_IN_META, new Object[]{item}));
+ operations.add(new Opt(OptType.COPY_FILE_IN_META, new Object[]{item}, dstProject));
}
if (doMigrateSegment) {
for (String item : dictAndSnapshot) {
- operations.add(new Opt(OptType.COPY_DICT_OR_SNAPSHOT, new Object[]{item, cube.getName()}));
+ operations.add(new Opt(OptType.COPY_DICT_OR_SNAPSHOT, new Object[]{item, cube.getName()}, dstProject));
}
for (int i = 0; i < srcParquetFiles.size(); i++) {
- operations.add(new Opt(OptType.COPY_PARQUET_FILE, new Object[]{srcParquetFiles.get(i), dstParquetFiles.get(i)}));
+ operations.add(new Opt(OptType.COPY_PARQUET_FILE, new Object[]{srcParquetFiles.get(i), dstParquetFiles.get(i)}, dstProject));
}
}
}
- protected void addCubeAndModelIntoProject(CubeInstance srcCube, String cubeName) throws IOException {
+ protected void addCubeAndModelIntoProject(CubeInstance srcCube, String cubeName, String dstProject) throws IOException {
String projectResPath = ProjectInstance.concatResourcePath(dstProject);
if (!dstStore.exists(projectResPath))
throw new IllegalStateException("The target project " + dstProject + " does not exist");
- operations.add(new Opt(OptType.ADD_INTO_PROJECT, new Object[]{srcCube, cubeName, dstProject}));
+ operations.add(new Opt(OptType.ADD_INTO_PROJECT, new Object[]{srcCube, cubeName}, dstProject));
}
private void purgeAndDisable(String cubeName) throws IOException {
- operations.add(new Opt(OptType.PURGE_AND_DISABLE, new Object[]{cubeName}));
+ operations.add(new Opt(OptType.PURGE_AND_DISABLE, new Object[]{cubeName}, null));
}
private List<String> getCompatibleTablePath(Set<TableRef> tableRefs, String project, String rootPath)
@@ -324,6 +390,22 @@ public class CubeMigrationCLI extends AbstractApplication {
@Override
protected Options getOptions() {
Options options = new Options();
+ options.addOption(OPTION_SRC_CONFIG);
+ options.addOption(OPTION_DST_CONFIG);
+
+ OptionGroup srcGroup = new OptionGroup();
+ srcGroup.addOption(OPTION_ALL_CUBES);
+ srcGroup.addOption(OPTION_CUBE);
+ srcGroup.addOption(OPTION_SRC_PROJECT);
+ srcGroup.setRequired(true);
+ options.addOptionGroup(srcGroup);
+
+ options.addOption(OPTION_DST_PROJECT);
+ options.addOption(OPTION_OVERWRITE);
+ options.addOption(OPTION_COPY_ACL);
+ options.addOption(OPTION_PURGE_AND_DISABLE);
+ options.addOption(OPTION_EXECUTE);
+ options.addOption(OPTION_MIGRATE_SEGMENTS);
return options;
}
@@ -335,17 +417,19 @@ public class CubeMigrationCLI extends AbstractApplication {
COPY_FILE_IN_META, COPY_DICT_OR_SNAPSHOT, COPY_PARQUET_FILE, ADD_INTO_PROJECT, PURGE_AND_DISABLE, CLEAR_SEGMENTS
}
- protected void addOpt(OptType type, Object[] params) {
- operations.add(new Opt(type, params));
+ protected void addOpt(OptType type, Object[] params, String dstProject) {
+ operations.add(new Opt(type, params, dstProject));
}
private class Opt {
private OptType type;
private Object[] params;
+ private String dstProject;
- private Opt(OptType type, Object[] params) {
+ private Opt(OptType type, Object[] params, String dstProject) {
this.type = type;
this.params = params;
+ this.dstProject = dstProject;
}
public String toString() {
@@ -353,6 +437,7 @@ public class CubeMigrationCLI extends AbstractApplication {
sb.append(type).append(":");
for (Object s : params)
sb.append(s).append(", ");
+ sb.append(dstProject);
return sb.toString();
}
@@ -407,15 +492,50 @@ public class CubeMigrationCLI extends AbstractApplication {
// dataModel's project maybe be different with new project.
if (item.startsWith(ResourceStore.DATA_MODEL_DESC_RESOURCE_ROOT)) {
DataModelDesc dataModelDesc = srcStore.getResource(item, DataModelManager.getInstance(srcConfig).getDataModelSerializer());
- if (dataModelDesc != null && dataModelDesc.getProjectName() != null && !dataModelDesc.getProjectName().equals(dstProject)) {
- dataModelDesc.setProjectName(dstProject);
+ //before copy a dataModel, check its uniqueness in new cluster. Because
+ //a model belonging to several projects is not allowed to exist, it will cause unexpected problem.
+ List<ProjectInstance> projectContainsModel = ProjectManager.getInstance(dstConfig).findProjectsByModel(dataModelDesc.getName());
+ if (projectContainsModel.size() > 1) {
+ throw new RuntimeException(String.format(Locale.ROOT, "model: %s belongs to several projects: %s",
+ dataModelDesc.getName(), Arrays.toString(projectContainsModel.toArray())));
+ }
+ if (projectContainsModel.size() == 1 && !opt.dstProject.equals(projectContainsModel.get(0).getName())) {
+ throw new IllegalArgumentException(String.format(Locale.ROOT,
+ "there already exists model: %s in project: %s, can't create model with the same name in dest project: %s",
+ dataModelDesc.getName(), projectContainsModel.get(0).getName(), opt.dstProject));
+ }
+
+ if (dataModelDesc != null && dataModelDesc.getProjectName() != null && !dataModelDesc.getProjectName().equals(opt.dstProject)) {
+ dataModelDesc.setProjectName(opt.dstProject);
dstStore.putResource(item, dataModelDesc, res.lastModified(), DataModelManager.getInstance(srcConfig).getDataModelSerializer());
logger.info("Item " + item + " is copied.");
+ res.close();
break;
}
}
+ if (item.startsWith(ResourceStore.CUBE_DESC_RESOURCE_ROOT)) {
+ JsonSerializer serializer = new JsonSerializer(CubeDesc.class, false);
+ ContentReader<CubeDesc> reader = new ContentReader<>(serializer);
+ CubeDesc cubeDesc = reader.readContent(res);
+
+ //set storage type to parquet and job engine to spark_ii
+ cubeDesc.setStorageType(IStorageAware.ID_PARQUET);
+ cubeDesc.setEngineType(IEngineAware.ID_SPARK_II);
+ cubeDesc.setVersion(KylinVersion.getCurrentVersion().toString());
+ //once storage type have changed, signature will change too
+ cubeDesc.setSignature(cubeDesc.calculateSignature());
+
+ ByteArrayOutputStream buf = new ByteArrayOutputStream();
+ DataOutputStream dout = new DataOutputStream(buf);
+ serializer.serialize(cubeDesc, dout);
+ dstStore.putResource(item, new ByteArrayInputStream(buf.toByteArray()), res.lastModified());
+ dout.close();
+ buf.close();
+ res.close();
+ break;
+ }
dstStore.putResource(renameTableWithinProject(item), res.content(), res.lastModified());
- res.content().close();
+ res.close();
logger.info("Item " + item + " is copied");
break;
}
@@ -446,7 +566,7 @@ public class CubeMigrationCLI extends AbstractApplication {
case ADD_INTO_PROJECT: {
CubeInstance srcCube = (CubeInstance) opt.params[0];
String cubeName = (String) opt.params[1];
- String projectName = (String) opt.params[2];
+ String projectName = opt.dstProject;
String modelName = srcCube.getDescriptor().getModelName();
String projectResPath = ProjectInstance.concatResourcePath(projectName);