diff --git a/submarine-commons/commons-utils/src/main/java/org/apache/submarine/commons/utils/SubmarineConfVars.java b/submarine-commons/commons-utils/src/main/java/org/apache/submarine/commons/utils/SubmarineConfVars.java
index 6dbe18e43c..075c2dd16b 100644
--- a/submarine-commons/commons-utils/src/main/java/org/apache/submarine/commons/utils/SubmarineConfVars.java
+++ b/submarine-commons/commons-utils/src/main/java/org/apache/submarine/commons/utils/SubmarineConfVars.java
@@ -51,6 +51,11 @@ public enum ConfVars {
CLUSTER_HEARTBEAT_INTERVAL("cluster.heartbeat.interval", 3000),
CLUSTER_HEARTBEAT_TIMEOUT("cluster.heartbeat.timeout", 9000),
+ SUBMARINE_METADATA_INIT("submarine.metadata.init", false),
+ SUBMARINE_METADATA_VALIDATE("submarine.metadata.validate", true),
+ SUBMARINE_METADATA_VERSION("submarine.metadata.version", "0.7.0"),
+ SUBMARINE_METADATA_LOCATION("submarine.metadata.location", "classpath:db/migration"),
+
JDBC_DRIVERCLASSNAME("jdbc.driverClassName", "com.mysql.jdbc.Driver"),
JDBC_URL("jdbc.url", "jdbc:mysql://127.0.0.1:3306/submarine" +
"?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&allowMultiQueries=true&" +
diff --git a/submarine-server/server-core/pom.xml b/submarine-server/server-core/pom.xml
index 998e5a7af4..da40942d8f 100644
--- a/submarine-server/server-core/pom.xml
+++ b/submarine-server/server-core/pom.xml
@@ -520,6 +520,19 @@
test
+
+ org.flywaydb
+ flyway-core
+ 7.15.0
+
+
+
+ com.h2database
+ h2
+ 1.4.194
+ test
+
+
diff --git a/submarine-server/server-core/src/main/java/org/apache/submarine/server/SubmarineServer.java b/submarine-server/server-core/src/main/java/org/apache/submarine/server/SubmarineServer.java
index 5a3f9b8b93..7325a39737 100644
--- a/submarine-server/server-core/src/main/java/org/apache/submarine/server/SubmarineServer.java
+++ b/submarine-server/server-core/src/main/java/org/apache/submarine/server/SubmarineServer.java
@@ -20,6 +20,7 @@
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.PropertyConfigurator;
+import org.apache.submarine.server.database.initialization.DatabaseMetadataService;
import org.apache.submarine.server.database.utils.MyBatisUtil;
import org.apache.submarine.server.rest.provider.YamlEntityProvider;
import org.apache.submarine.server.security.SecurityFactory;
@@ -136,8 +137,11 @@ protected void configure() {
// setupClusterServer();
setupWebSocketServer(webApp, conf, sharedServiceLocator);
- startServer();
+ // init database metadata
+ new DatabaseMetadataService().initDatabaseMetadata();
+
+ startServer();
}
@Inject
diff --git a/submarine-server/server-core/src/main/java/org/apache/submarine/server/database/initialization/DatabaseMetadataService.java b/submarine-server/server-core/src/main/java/org/apache/submarine/server/database/initialization/DatabaseMetadataService.java
new file mode 100644
index 0000000000..76a5fada97
--- /dev/null
+++ b/submarine-server/server-core/src/main/java/org/apache/submarine/server/database/initialization/DatabaseMetadataService.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.submarine.server.database.initialization;
+
+import org.apache.submarine.commons.utils.SubmarineConfVars;
+import org.apache.submarine.commons.utils.SubmarineConfiguration;
+import org.flywaydb.core.Flyway;
+import org.flywaydb.core.api.configuration.FluentConfiguration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DatabaseMetadataService {
+
+ private static final Logger LOG = LoggerFactory.getLogger(DatabaseMetadataService.class);
+
+ /**
+ * init database metadata by flyway
+ */
+ public void initDatabaseMetadata() {
+ SubmarineConfiguration conf = SubmarineConfiguration.getInstance();
+ if (!conf.getBoolean(SubmarineConfVars.ConfVars.SUBMARINE_METADATA_INIT)) {
+ LOG.info("Skip submarine metadata initialization. If you want to init database metadata, " +
+ "you can set `submarine.metadata.init` or SUBMARINE_METADATA_INIT env to true.");
+ return;
+ }
+
+ // get database connection conf
+ String jdbcUrl = conf.getJdbcUrl();
+ String jdbcUserName = conf.getJdbcUserName();
+ String jdbcPassword = conf.getJdbcPassword();
+
+ // flyway config
+ FluentConfiguration fluentConfiguration = new FluentConfiguration()
+ .dataSource(jdbcUrl, jdbcUserName, jdbcPassword);
+
+ // sql files location
+ fluentConfiguration.locations(conf.getString(SubmarineConfVars.ConfVars.SUBMARINE_METADATA_LOCATION));
+ // schema metadata history table, control schema version. version id is default release version
+ fluentConfiguration.table("submarine_schema_history");
+ // if schema metadata history table is missed,try to create it
+ fluentConfiguration.baselineOnMigrate(true);
+ // Whether to automatically call validate or not when running migrate.
+ // If encounter script tuning, we can set this value to false
+ fluentConfiguration.validateOnMigrate(
+ conf.getBoolean(SubmarineConfVars.ConfVars.SUBMARINE_METADATA_VALIDATE));
+ // basic version, we may start it from 0.7.0
+ // We can replace this value if we want to update from an intermediate version in some cases
+ fluentConfiguration.baselineVersion(
+ conf.getString(SubmarineConfVars.ConfVars.SUBMARINE_METADATA_VERSION));
+
+ Flyway flyway = fluentConfiguration.load();
+ try {
+ flyway.migrate();
+ } catch (Exception e) {
+ LOG.warn("Error during database initialization. You may need to manually initialize " +
+ "the actual metadata and data.", e);
+ }
+ }
+
+}
diff --git a/submarine-server/server-core/src/main/resources/db/migration/V0.7.0__0.7.0.Release.sql b/submarine-server/server-core/src/main/resources/db/migration/V0.7.0__0.7.0.Release.sql
new file mode 100644
index 0000000000..d0cf98b0a6
--- /dev/null
+++ b/submarine-server/server-core/src/main/resources/db/migration/V0.7.0__0.7.0.Release.sql
@@ -0,0 +1,414 @@
+-- Licensed to the Apache Software Foundation (ASF) under one or more
+-- contributor license agreements. See the NOTICE file distributed with
+-- this work for additional information regarding copyright ownership.
+-- The ASF licenses this file to You under the Apache License, Version 2.0
+-- (the "License"); you may not use this file except in compliance with
+-- the License. You may obtain a copy of the License at
+-- http://www.apache.org/licenses/LICENSE-2.0
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+
+-- ----------------------------
+-- Table structure for sys_dict
+-- ----------------------------
+CREATE TABLE IF NOT EXISTS `sys_dict` (
+ `id` varchar(32) NOT NULL,
+ `dict_code` varchar(32) NOT NULL COMMENT 'dict code',
+ `dict_name` varchar(32) NOT NULL COMMENT 'dict name',
+ `description` varchar(255) default NULL COMMENT 'dict description',
+ `deleted` int(1) default 0 COMMENT 'delete status(0:normal, 1:already deleted)',
+ `type` int(1) default 0 COMMENT 'dict type (0:string,1:number)',
+ `create_by` varchar(32) default NULL COMMENT 'create user',
+ `create_time` datetime default NULL COMMENT 'create time',
+ `update_by` varchar(32) default NULL COMMENT 'last update user',
+ `update_time` datetime default NULL COMMENT 'last update time',
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `UK_SYS_DICT_DICT_CODE` (`dict_code`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+-- ----------------------------
+-- Table structure for sys_dict_item
+-- ----------------------------
+CREATE TABLE IF NOT EXISTS `sys_dict_item` (
+ `id` varchar(32) NOT NULL,
+ `item_code` varchar(32) NOT NULL COMMENT 'dict item code',
+ `item_name` varchar(32) NOT NULL COMMENT 'dict item name',
+ `dict_code` varchar(32) NOT NULL COMMENT 'dict code',
+ `description` varchar(255) default NULL COMMENT 'description',
+ `sort_order` int(3) default 0 COMMENT 'sort order',
+ `deleted` int(1) default 0 COMMENT 'delete status(0:normal,1:already deleted)',
+ `create_by` varchar(32) default NULL,
+ `create_time` datetime default NULL,
+ `update_by` varchar(32) default NULL,
+ `update_time` datetime default NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `UK_SYS_DICT_ITEM_CODE` (`item_code`)/*,
+ CONSTRAINT `FK_SYS_DICT_ITEM_DICT_CODE` FOREIGN KEY (`dict_code`) REFERENCES `sys_dict` (`dict_code`)*/
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+-- ----------------------------
+-- Table structure for system department
+-- ----------------------------
+CREATE TABLE IF NOT EXISTS `sys_department` (
+ `id` varchar(32) NOT NULL COMMENT 'ID',
+ `dept_code` varchar(32) NOT NULL COMMENT 'department code',
+ `dept_name` varchar(64) NOT NULL COMMENT 'department name',
+ `parent_code` varchar(32) default NULL COMMENT 'parent dept code',
+ `sort_order` int(3) default 0 COMMENT 'sort order',
+ `description` varchar(255) COMMENT 'description',
+ `deleted` varchar(1) default 0 COMMENT 'delete status(0:normal,1:already deleted)',
+ `create_by` varchar(32) default NULL COMMENT 'create user',
+ `create_time` datetime default NULL COMMENT 'create time',
+ `update_by` varchar(32) default NULL COMMENT 'last update user',
+ `update_time` datetime default NULL COMMENT 'last update time',
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `UK_DEPT_CODE` (`dept_code`)/*,
+ CONSTRAINT `FK_SYS_DEPT_PARENT_CODE` FOREIGN KEY (`parent_code`) REFERENCES `sys_department` (`dept_code`)*/
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+-- ----------------------------
+-- Table structure for sys_user
+-- ----------------------------
+CREATE TABLE IF NOT EXISTS `sys_user` (
+ `id` varchar(32) NOT NULL COMMENT 'id',
+ `user_name` varchar(32) NOT NULL COMMENT 'login name',
+ `real_name` varchar(64) NOT NULL COMMENT 'real name',
+ `password` varchar(255) NOT NULL COMMENT 'password',
+ `avatar` varchar(255) default NULL COMMENT 'avatar',
+ `birthday` datetime default NULL COMMENT 'birthday',
+ `sex` varchar(32) default NULL COMMENT 'sex',
+ `email` varchar(32) default NULL COMMENT 'email',
+ `phone` varchar(32) default NULL COMMENT 'telphone',
+ `dept_code` varchar(32) default NULL COMMENT 'department code',
+ `role_code` varchar(32) default NULL COMMENT 'role code',
+ `status` varchar(32) default NULL COMMENT 'status',
+ `deleted` int(1) default 0 COMMENT 'deleted status(0:normal, 1:already deleted)',
+ `create_by` varchar(32) default NULL COMMENT 'create user',
+ `create_time` datetime default NULL COMMENT 'create time',
+ `update_by` varchar(32) default NULL COMMENT 'last update user',
+ `update_time` datetime default NULL COMMENT 'last update time',
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `sys_user_name` (`user_name`)/*,
+ CONSTRAINT `FK_SYS_USER_DEPT_CODE` FOREIGN KEY (`dept_code`) REFERENCES `sys_department` (`dept_code`),
+ CONSTRAINT `FK_SYS_USER_SEX` FOREIGN KEY (`sex`) REFERENCES `sys_dict_item` (`item_code`),
+ CONSTRAINT `FK_SYS_USER_STATUS` FOREIGN KEY (`status`) REFERENCES `sys_dict_item` (`item_code`)*/
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+-- ----------------------------
+-- Table structure for sys_message
+-- ----------------------------
+CREATE TABLE IF NOT EXISTS `sys_message` (
+ `id` varchar(32) NOT NULL COMMENT 'id',
+ `sender` varchar(32) default NULL COMMENT 'sender user',
+ `receiver` varchar(32) default NULL COMMENT 'receiver user',
+ `type` varchar(32) default NULL COMMENT 'dict_code:MESSAGE_TYPE',
+ `context` text COMMENT 'message context',
+ `status` int(1) default 0 COMMENT '0:unread, 1:read',
+ `create_by` varchar(32) default NULL COMMENT 'create user',
+ `create_time` datetime default NULL COMMENT 'create time',
+ `update_by` varchar(32) default NULL COMMENT 'last update user',
+ `update_time` datetime default NULL COMMENT 'last update time',
+ PRIMARY KEY (`id`)/*,
+ CONSTRAINT `FK_SYS_MSG_SENDER` FOREIGN KEY (`sender`) REFERENCES `sys_user` (`user_name`),
+ CONSTRAINT `FK_SYS_MSG_RECEIVER` FOREIGN KEY (`receiver`) REFERENCES `sys_user` (`user_name`),
+ CONSTRAINT `FK_SYS_MSG_TYPE` FOREIGN KEY (`type`) REFERENCES `sys_dict_item` (`item_code`)*/
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+-- ----------------------------
+-- Table structure for team
+-- ----------------------------
+CREATE TABLE IF NOT EXISTS `team` (
+ `id` varchar(32) NOT NULL,
+ `owner` varchar(100) NOT NULL COMMENT 'owner name',
+ `team_name` varchar(64) NOT NULL COMMENT 'team name',
+ `create_by` varchar(32) default NULL COMMENT 'create user',
+ `create_time` datetime default NULL COMMENT 'create time',
+ `update_by` varchar(32) default NULL COMMENT 'last update user',
+ `update_time` datetime default NULL COMMENT 'last update time',
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `UK_TEAM_NAME` (`team_name`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+-- ----------------------------
+-- Table structure for team_member
+-- ----------------------------
+CREATE TABLE IF NOT EXISTS `team_member` (
+ `id` varchar(32) NOT NULL,
+ `team_id` varchar(32) NOT NULL COMMENT 'team id',
+ `team_name` varchar(64) NOT NULL COMMENT 'team name',
+ `member` varchar(100) NOT NULL COMMENT 'member name',
+ `inviter` int(1) default 0 COMMENT '0:inviter, 1:accept',
+ `create_by` varchar(32) default NULL,
+ `create_time` datetime default NULL,
+ `update_by` varchar(32) default NULL,
+ `update_time` datetime default NULL,
+ PRIMARY KEY (`id`)/*,
+ CONSTRAINT `FK_TEAM_MEMBER_USER` FOREIGN KEY (`member`) REFERENCES `sys_user` (`user_name`)*/
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+-- ----------------------------
+-- Table structure for project
+-- ----------------------------
+CREATE TABLE IF NOT EXISTS `project` (
+ `id` varchar(32) NOT NULL,
+ `name` varchar(100) NOT NULL COMMENT 'project name',
+ `visibility` varchar(32) default NULL COMMENT 'dict_code:PROJECT_VISIBILITY',
+ `permission` varchar(32) default NULL COMMENT 'dict_code:PROJECT_PERMISSION',
+ `type` varchar(32) default NULL COMMENT 'dict_code:PROJECT_TYPE',
+ `description` varchar(255) COMMENT 'description',
+ `user_name` varchar(32) NOT NULL COMMENT 'owner user id',
+ `team_name` varchar(32) default NULL COMMENT 'team name',
+ `tags` varchar(128) default NULL COMMENT 'Comma separated tag',
+ `star_num` int(8) default 0 COMMENT 'star number',
+ `like_num` int(8) default 0 COMMENT 'like number',
+ `message_num` int(8) default 0 COMMENT 'message number',
+ `create_by` varchar(32) default NULL COMMENT 'create user',
+ `create_time` datetime default NULL COMMENT 'create time',
+ `update_by` varchar(32) default NULL COMMENT 'last update user',
+ `update_time` datetime default NULL COMMENT 'last update time',
+ PRIMARY KEY (`id`)/*,
+ CONSTRAINT `FK_PROJECT_TYPE` FOREIGN KEY (`type`) REFERENCES `sys_dict_item` (`item_code`),
+ CONSTRAINT `FK_PROJECT_TEAM_NAME` FOREIGN KEY (`team_name`) REFERENCES `team` (`team_name`),
+ CONSTRAINT `FK_PROJECT_USER_NAME` FOREIGN KEY (`user_name`) REFERENCES `sys_user` (`user_name`)*/
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+-- ----------------------------
+-- Table structure for project_files
+-- ----------------------------
+CREATE TABLE IF NOT EXISTS `project_files` (
+ `id` varchar(32) NOT NULL,
+ `project_id` varchar(32) NOT NULL COMMENT 'project id',
+ `file_name` varchar(128) NOT NULL COMMENT '/path/.../file.suffix',
+ `file_content` text default NULL COMMENT 'file content',
+ `create_by` varchar(32) default NULL COMMENT 'create user',
+ `create_time` datetime default NULL COMMENT 'create time',
+ `update_by` varchar(32) default NULL COMMENT 'last update user',
+ `update_time` datetime default NULL COMMENT 'last update time',
+ PRIMARY KEY (`id`)/*,
+ CONSTRAINT `FK_PROJECT_FILES_PRJ_ID` FOREIGN KEY (`project_id`) REFERENCES `project` (`id`)*/
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+-- ----------------------------
+-- Table structure for jobs
+-- ----------------------------
+CREATE TABLE IF NOT EXISTS `job` (
+ `id` int NOT NULL AUTO_INCREMENT,
+ `job_id` varchar(64) default NULL COMMENT 'job id',
+ `job_name` varchar(64) NOT NULL COMMENT 'job name',
+ `job_type` varchar(64) NOT NULL COMMENT 'job type',
+ `job_namespace` varchar(32) default NULL COMMENT 'job namespace',
+ `job_status` varchar(32) default NULL COMMENT 'job status',
+ `job_final_status` varchar(32) default NULL COMMENT 'job final status',
+ `user_name` varchar(32) default NULL COMMENT 'user name',
+ `create_by` varchar(32) default NULL COMMENT 'create user',
+ `create_time` datetime default NULL COMMENT 'create time',
+ `update_by` varchar(32) default NULL COMMENT 'last update user',
+ `update_time` datetime default NULL COMMENT 'last update time',
+ PRIMARY KEY (`id`)
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+-- ----------------------------
+-- Table structure for environment
+-- ----------------------------
+CREATE TABLE IF NOT EXISTS `environment` (
+ `id` varchar(64) NOT NULL COMMENT 'Id of the Environment',
+ `environment_name` varchar(255) NOT NULL COMMENT 'Name of the Environment',
+ `environment_spec` text NOT NULL COMMENT 'Spec of the Environment',
+ `create_by` varchar(32) DEFAULT NULL COMMENT 'create user',
+ `create_time` datetime DEFAULT NULL COMMENT 'create time',
+ `update_by` varchar(32) DEFAULT NULL COMMENT 'last update user',
+ `update_time` datetime DEFAULT NULL COMMENT 'last update time',
+ PRIMARY KEY `id` (`id`),
+ UNIQUE KEY `environment_name` (`environment_name`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+-- ----------------------------
+-- Table structure for experiment
+-- ----------------------------
+CREATE TABLE IF NOT EXISTS `experiment` (
+ `id` varchar(64) NOT NULL COMMENT 'Id of the Experiment',
+ `experiment_spec` text NOT NULL COMMENT 'Spec of the experiment',
+ `create_by` varchar(32) DEFAULT NULL COMMENT 'create user',
+ `create_time` datetime DEFAULT NULL COMMENT 'create time',
+ `update_by` varchar(32) DEFAULT NULL COMMENT 'last update user',
+ `update_time` datetime DEFAULT NULL COMMENT 'last update time',
+ `experiment_status` varchar(20) DEFAULT NULL COMMENT 'experiment status',
+ PRIMARY KEY `id` (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+-- ----------------------------
+-- Table structure for notebook
+-- ----------------------------
+CREATE TABLE IF NOT EXISTS `notebook` (
+ `id` varchar(64) NOT NULL COMMENT 'Id of the notebook',
+ `notebook_spec` text NOT NULL COMMENT 'Spec of the notebook',
+ `create_by` varchar(32) DEFAULT NULL COMMENT 'create user',
+ `create_time` datetime DEFAULT NULL COMMENT 'create time',
+ `update_by` varchar(32) DEFAULT NULL COMMENT 'last update user',
+ `update_time` datetime DEFAULT NULL COMMENT 'last update time',
+ `notebook_status` varchar(20) DEFAULT NULL COMMENT 'notebook status',
+ PRIMARY KEY `id` (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+-- ----------------------------
+-- Table structure for experiment_templates
+-- ----------------------------
+CREATE TABLE IF NOT EXISTS `experiment_template` (
+ `id` varchar(64) NOT NULL,
+ `experimentTemplate_name` varchar(32) NOT NULL,
+ `experimentTemplate_spec` json DEFAULT NULL,
+ `create_by` varchar(32) DEFAULT NULL,
+ `create_time` datetime NOT NULL,
+ `update_by` varchar(32) DEFAULT NULL,
+ `update_time` datetime NOT NULL,
+ PRIMARY KEY `id` (`id`),
+ UNIQUE KEY `experimentTemplate_name` (`experimentTemplate_name`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+-- ----------------------------
+-- Table structure for registered_model
+-- ----------------------------
+CREATE TABLE IF NOT EXISTS `registered_model` (
+ `name` VARCHAR(256) NOT NULL,
+ `creation_time` DATETIME(3) COMMENT 'Millisecond precision',
+ `last_updated_time` DATETIME(3) COMMENT 'Millisecond precision',
+ `description` VARCHAR(5000),
+ CONSTRAINT `registered_model_pk` PRIMARY KEY (`name`),
+ UNIQUE (`name`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+-- ----------------------------
+-- Table structure for registered_model
+-- ----------------------------
+CREATE TABLE IF NOT EXISTS `registered_model_tag` (
+ `name` VARCHAR(256) NOT NULL,
+ `tag` VARCHAR(256) NOT NULL,
+ CONSTRAINT `registered_model_tag_pk` PRIMARY KEY (`name`, `tag`),
+ FOREIGN KEY(`name`) REFERENCES `registered_model` (`name`) ON UPDATE CASCADE ON DELETE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+-- ----------------------------
+-- Table structure for model_version
+-- ----------------------------
+CREATE TABLE IF NOT EXISTS `model_version` (
+ `name` VARCHAR(256) NOT NULL COMMENT 'Name of model',
+ `version` INTEGER NOT NULL,
+ `source` VARCHAR(512) NOT NULL COMMENT 'Model saved link',
+ `user_id` VARCHAR(64) NOT NULL COMMENT 'Id of the created user',
+ `experiment_id` VARCHAR(64) NOT NULL,
+ `model_type` VARCHAR(64) NOT NULL COMMENT 'Type of model',
+ `current_stage` VARCHAR(64) COMMENT 'Model stage ex: None, production...',
+ `creation_time` DATETIME(3) COMMENT 'Millisecond precision',
+ `last_updated_time` DATETIME(3) COMMENT 'Millisecond precision',
+ `dataset` VARCHAR(256) COMMENT 'Which dataset is used',
+ `description` VARCHAR(5000),
+ CONSTRAINT `model_version_pk` PRIMARY KEY (`name`, `version`),
+ FOREIGN KEY(`name`) REFERENCES `registered_model` (`name`) ON UPDATE CASCADE ON DELETE CASCADE,
+ UNIQUE(`source`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+-- ----------------------------
+-- Table structure for model_version_tag
+-- ----------------------------
+CREATE TABLE IF NOT EXISTS `model_version_tag` (
+ `name` VARCHAR(256) NOT NULL COMMENT 'Name of model',
+ `version` INTEGER NOT NULL,
+ `tag` VARCHAR(256) NOT NULL,
+ CONSTRAINT `model_version_tag_pk` PRIMARY KEY (`name`, `version`, `tag`),
+ FOREIGN KEY(`name`, `version`) REFERENCES `model_version` (`name`, `version`) ON UPDATE CASCADE ON DELETE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+-- ----------------------------
+-- Table structure for metric
+-- ----------------------------
+CREATE TABLE IF NOT EXISTS `metric` (
+ `id` VARCHAR(64) NOT NULL COMMENT 'Id of the Experiment',
+ `key` VARCHAR(190) NOT NULL COMMENT 'Metric key: `String` (limit 190 characters). Part of *Primary Key* for ``metric`` table.',
+ `value` FLOAT NOT NULL COMMENT 'Metric value: `Float`. Defined as *Non-null* in schema.',
+ `worker_index` VARCHAR(32) NOT NULL COMMENT 'Metric worker_index: `String` (limit 32 characters). Part of *Primary Key* for\r\n ``metrics`` table.',
+ `timestamp` DATETIME(3) NOT NULL COMMENT 'Timestamp recorded for this metric entry: `DATETIME` (millisecond precision).
+ Part of *Primary Key* for ``metrics`` table.',
+ `step` INTEGER NOT NULL COMMENT 'Step recorded for this metric entry: `INTEGER`.',
+ `is_nan` BOOLEAN NOT NULL COMMENT 'True if the value is in fact NaN.',
+ CONSTRAINT `metric_pk` PRIMARY KEY (`id`, `key`, `timestamp`, `worker_index`),
+ FOREIGN KEY(`id`) REFERENCES `experiment` (`id`) ON UPDATE CASCADE ON DELETE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+-- ----------------------------
+-- Table structure for param
+-- ----------------------------
+CREATE TABLE IF NOT EXISTS `param` (
+ `id` VARCHAR(64) NOT NULL COMMENT 'Id of the Experiment',
+ `key` VARCHAR(190) NOT NULL COMMENT '`String` (limit 190 characters). Part of *Primary Key* for ``param`` table.',
+ `value` VARCHAR(190) NOT NULL COMMENT '`String` (limit 190 characters). Defined as *Non-null* in schema.',
+ `worker_index` VARCHAR(32) NOT NULL COMMENT '`String` (limit 32 characters). Part of *Primary Key* for\r\n ``metric`` table.',
+ CONSTRAINT `param_pk` PRIMARY KEY (`id`, `key`, `worker_index`),
+ FOREIGN KEY(`id`) REFERENCES `experiment` (`id`) ON UPDATE CASCADE ON DELETE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+-- ----------------------------
+-- Records of sys_dict
+-- ----------------------------
+INSERT INTO `sys_dict` VALUES ('ca2dd544ca4c11e9a71e0242ac110002','SYS_USER_SEX','Sys user sex','submarine system dict, Do not modify.',0,0,NULL,'2019-08-29 11:04:36',NULL,'2019-09-01 01:08:12');
+INSERT INTO `sys_dict` VALUES ('f405a7b1cc5411e9af810242ac110002','SYS_USER_STATUS','Sys user status','submarine system dict, Do not modify.',0,0,NULL,'2019-09-01 01:08:05',NULL,'2019-09-01 01:08:05');
+INSERT INTO `sys_dict` VALUES ('3a1ed33ae83611e9ab840242ac110002','PROJECT_TYPE','Project machine learning type','submarine system dict, Do not modify.',0,0,NULL,'2019-09-01 01:08:05',NULL,'2019-09-01 01:08:05');
+INSERT INTO `sys_dict` VALUES ('8a101495e84011e9ab840242ac110002','PROJECT_VISIBILITY','Project visibility type','submarine system dict, Do not modify.',0,0,NULL,'2019-09-01 01:08:05',NULL,'2019-09-01 01:08:05');
+INSERT INTO `sys_dict` VALUES ('8f0439c9e84011e9ab840242ac110002','PROJECT_PERMISSION','Project permission type','submarine system dict, Do not modify.',0,0,NULL,'2019-09-01 01:08:05',NULL,'2019-09-01 01:08:05');
+
+-- ----------------------------
+-- Records of sys_dict_item
+-- ----------------------------
+INSERT INTO `sys_dict_item` VALUES ('27ef1080cc5511e9af810242ac110002','SYS_USER_STATUS_AVAILABLE','Available','SYS_USER_STATUS','submarine system dict, Do not modify.',1,0,NULL,'2019-09-01 01:09:32',NULL,'2019-09-01 01:13:19');
+INSERT INTO `sys_dict_item` VALUES ('4c5d736acc5511e9af810242ac110002','SYS_USER_STATUS_LOCKED','Locked','SYS_USER_STATUS','submarine system dict, Do not modify.',2,0,NULL,'2019-09-01 01:10:33',NULL,'2019-09-01 01:12:53');
+INSERT INTO `sys_dict_item` VALUES ('6d5ae3b2cc5511e9af810242ac110002','SYS_USER_STATUS_REGISTERED','New Registered','SYS_USER_STATUS','submarine system dict, Do not modify.',3,0,NULL,'2019-09-01 01:11:29',NULL,'2019-09-01 01:12:47');
+INSERT INTO `sys_dict_item` VALUES ('d018e2b0ca4c11e9a71e0242ac110002','SYS_USER_SEX_MALE','Male','SYS_USER_SEX','submarine system dict, Do not modify.',1,0,NULL,'2019-08-29 11:04:46',NULL,'2019-09-01 00:53:54');
+INSERT INTO `sys_dict_item` VALUES ('d94410adca4c11e9a71e0242ac110002','SYS_USER_SEX_FEMALE','Female','SYS_USER_SEX','submarine system dict, Do not modify.',2,0,NULL,'2019-08-29 11:05:02',NULL,'2019-09-01 00:54:00');
+INSERT INTO `sys_dict_item` VALUES ('7b9aafa0e83611e9ab840242ac110002','PROJECT_TYPE_NOTEBOOK','notebook','PROJECT_TYPE','submarine system dict, Do not modify.',1,0,NULL,'2019-08-29 11:05:02',NULL,'2019-09-01 00:54:00');
+INSERT INTO `sys_dict_item` VALUES ('8229a76be83611e9ab840242ac110002','PROJECT_TYPE_PYTHON','python','PROJECT_TYPE','submarine system dict, Do not modify.',2,0,NULL,'2019-08-29 11:05:02',NULL,'2019-09-01 00:54:00');
+INSERT INTO `sys_dict_item` VALUES ('ac80ab12e83611e9ab840242ac110002','PROJECT_TYPE_R','R','PROJECT_TYPE','submarine system dict, Do not modify.',3,0,NULL,'2019-08-29 11:05:02',NULL,'2019-09-01 00:54:00');
+INSERT INTO `sys_dict_item` VALUES ('b1070158e83611e9ab840242ac110002','PROJECT_TYPE_SCALA','scala','PROJECT_TYPE','submarine system dict, Do not modify.',4,0,NULL,'2019-08-29 11:05:02',NULL,'2019-09-01 00:54:00');
+INSERT INTO `sys_dict_item` VALUES ('8c53870be83611e9ab840242ac110002','PROJECT_TYPE_TENSORFLOW','tensorflow','PROJECT_TYPE','submarine system dict, Do not modify.',5,0,NULL,'2019-08-29 11:05:02',NULL,'2019-09-01 00:54:00');
+INSERT INTO `sys_dict_item` VALUES ('90ca63dfe83611e9ab840242ac110002','PROJECT_TYPE_PYTORCH','pytorch','PROJECT_TYPE','submarine system dict, Do not modify.',6,0,NULL,'2019-08-29 11:05:02',NULL,'2019-09-01 00:54:00');
+INSERT INTO `sys_dict_item` VALUES ('2ed844fae84111e9ab840242ac110002','PROJECT_VISIBILITY_PRIVATE','private','PROJECT_VISIBILITY','submarine system dict, Do not modify.',1,0,NULL,'2019-09-01 01:09:32',NULL,'2019-09-01 01:13:19');
+INSERT INTO `sys_dict_item` VALUES ('341d5a35e84111e9ab840242ac110002','PROJECT_VISIBILITY_TEAM','team','PROJECT_VISIBILITY','submarine system dict, Do not modify.',2,0,NULL,'2019-09-01 01:10:33',NULL,'2019-09-01 01:12:53');
+INSERT INTO `sys_dict_item` VALUES ('3866b369e84111e9ab840242ac110002','PROJECT_VISIBILITY_PUBLIC','public','PROJECT_VISIBILITY','submarine system dict, Do not modify.',3,0,NULL,'2019-09-01 01:11:29',NULL,'2019-09-01 01:12:47');
+INSERT INTO `sys_dict_item` VALUES ('3cc1a373e84111e9ab840242ac110002','PROJECT_PERMISSION_VIEW','can view','PROJECT_PERMISSION','submarine system dict, Do not modify.',1,0,NULL,'2019-09-01 01:09:32',NULL,'2019-09-01 01:13:19');
+INSERT INTO `sys_dict_item` VALUES ('44e90f6ce84111e9ab840242ac110002','PROJECT_PERMISSION_EDIT','can edit','PROJECT_PERMISSION','submarine system dict, Do not modify.',2,0,NULL,'2019-09-01 01:11:29',NULL,'2019-09-01 01:12:47');
+INSERT INTO `sys_dict_item` VALUES ('40dbb5ece84111e9ab840242ac110002','PROJECT_PERMISSION_EXECUTE','can execute','PROJECT_PERMISSION','submarine system dict, Do not modify.',3,0,NULL,'2019-09-01 01:10:33',NULL,'2019-09-01 01:12:53');
+
+-- ----------------------------
+-- Records of sys_department
+-- ----------------------------
+INSERT INTO `sys_department` VALUES ('e3d69d19c8d211e98edc0242ac110002','A','Company',NULL,0,'','0',NULL,'2019-08-27 13:59:30',NULL,'2019-08-27 14:02:05');
+INSERT INTO `sys_department` VALUES ('eec10fe9c8d211e98edc0242ac110002','AA','DepartmentA','A',0,'','0',NULL,'2019-08-27 13:59:48',NULL,'2019-08-27 14:04:11');
+INSERT INTO `sys_department` VALUES ('f8b42e19c8d211e98edc0242ac110002','AB','DepartmentB','A',0,'','0',NULL,'2019-08-27 14:00:05',NULL,'2019-08-27 14:07:19');
+INSERT INTO `sys_department` VALUES ('13a1916dc8d311e98edc0242ac110002','ABA','GroupA','AB',0,'','0',NULL,'2019-08-27 14:00:50',NULL,'2019-08-27 14:09:21');
+INSERT INTO `sys_department` VALUES ('1bc0cd98c8d311e98edc0242ac110002','AAA','GroupB','AA',0,'','0',NULL,'2019-08-27 14:01:04',NULL,'2019-08-29 16:48:56');
+
+-- ----------------------------
+-- Records of sys_user
+-- ----------------------------
+INSERT INTO `sys_user` VALUES ('e9ca23d68d884d4ebb19d07889727dae', 'admin', 'administrator', '21232f297a57a5a743894a0e4a801fc3', 'avatar.png', '2018-12-05 00:00:00', NULL, 'dev@submarine.org', '18566666661', NULL, NULL, NULL, 0, 'admin', '2019-07-05 14:47:22', 'admin', '2019-07-05 14:47:22');
+
+-- ----------------------------
+-- Records of team
+-- ----------------------------
+INSERT INTO `team` VALUES ('e9ca23d68d884d4ebb19d07889721234', 'admin', 'Submarine', 'admin', '2020-05-06 14:00:05', 'Jack', '2020-05-06 14:00:14');
+
+-- ----------------------------
+-- Records of environment
+-- ----------------------------
+INSERT INTO `environment` VALUES
+('environment_1600862964725_0001', 'notebook-env', '{"name":"notebook-env","dockerImage":"apache/submarine:jupyter-notebook-0.7.0-SNAPSHOT","kernelSpec":{"name":"submarine_jupyter_py3","channels":["defaults"],"condaDependencies":[],"pipDependencies":[]}}', 'admin', '2020-09-21 14:00:05', 'admin', '2020-09-21 14:00:14'),
+('environment_1600862964725_0002', 'notebook-gpu-env', '{"name":"notebook-gpu-env","dockerImage":"apache/submarine:jupyter-notebook-gpu-0.7.0-SNAPSHOT","kernelSpec":{"name":"submarine_jupyter_py3","channels":["defaults"],"condaDependencies":[],"pipDependencies":[]}}', 'admin', '2021-03-28 17:00:00', 'admin', '2021-03-28 17:00:00');
+
+-- ----------------------------
+-- Records of experiment_templates
+-- ----------------------------
+INSERT INTO `experiment_template` (`id`, `experimentTemplate_name`, `experimentTemplate_spec`, `create_by`, `create_time`, `update_by`, `update_time`) VALUES
+('experimentTemplate_1599498007985_0013', 'tf-mnist', '{\"name\": \"tf-mnist\", \"author\": \"author\", \"parameters\": [{\"name\": \"learning_rate\", \"value\": \"0.2\", \"required\": \"false\", \"description\": \"The parameter of train mnist.\"}, {\"name\": \"batch_size\", \"value\": \"150\", \"required\": \"false\", \"description\": \"The parameter of train mnist.\"}, {\"name\": \"experiment_name\", \"required\": \"true\", \"description\": \"experiment name, you should change it to avoid duplication with other experiment names.\"}, {\"name\": \"spec.Ps.replicas\", \"value\": \"1\", \"required\": \"false\", \"description\": \"\"}, {\"name\": \"spec.Ps.resourceMap.cpu\", \"value\": \"1\", \"required\": \"false\", \"description\": \"\"}, {\"name\": \"spec.Ps.resourceMap.memory\", \"value\": \"2G\", \"required\": \"false\", \"description\": \"\"}, {\"name\": \"spec.Worker.replicas\", \"value\": \"1\", \"required\": \"false\", \"description\": \"\"}, {\"name\": \"spec.Worker.resourceMap.cpu\", \"value\": \"1\", \"required\": \"false\", \"description\": \"\"}, {\"name\": \"spec.Worker.resourceMap.memory\", \"value\": \"2G\", \"required\": \"false\", \"description\": \"\"}], \"description\": \"This is a template to run tf-mnist.\", \"experimentSpec\": {\"meta\": {\"cmd\": \"python /var/tf_mnist/mnist_with_summaries.py --log_dir=/train/log --learning_rate={{learning_rate}} --batch_size={{batch_size}}\", \"name\": \"{{experiment_name}}\", \"envVars\": {\"ENV1\": \"ENV1\"}, \"framework\": \"TensorFlow\", \"namespace\": \"default\"}, \"spec\": {\"Ps\": {\"replicas\": 1, \"resources\": \"cpu=1,memory=2G\", \"resourceMap\": {\"cpu\": \"1\", \"memory\": \"1000M\"}}, \"Worker\": {\"replicas\": 1, \"resources\": \"cpu=1,memory=2G\", \"resourceMap\": {\"cpu\": \"1\", \"memory\": \"2G\"}}}, \"environment\": {\"image\": \"apache/submarine:tf-mnist-with-summaries-1.0\"}}}', NULL, '2020-09-10 16:31:32', NULL, '2020-10-19 17:05:21');
+
+INSERT INTO `experiment_template` (`id`, `experimentTemplate_name`, `experimentTemplate_spec`, `create_by`, `create_time`, `update_by`, `update_time`) VALUES('experimentTemplate_1606489231336_0014', 'pytorch-mnist', '{\"name\": \"pytorch-mnist\", \"author\": \"author\", \"parameters\": [{\"name\": \"experiment_name\", \"required\": \"true\", \"description\": \"experiment name\"}, {\"name\": \"spec.Master.replicas\", \"value\": \"1\", \"required\": \"false\", \"description\": \"\"}, {\"name\": \"spec.Master.resourceMap.cpu\", \"value\": \"1\", \"required\": \"false\", \"description\": \"\"}, {\"name\": \"spec.Master.resourceMap.memory\", \"value\": \"1024M\", \"required\": \"false\", \"description\": \"\"}, {\"name\": \"spec.Worker.replicas\", \"value\": \"1\", \"required\": \"false\", \"description\": \"\"}, {\"name\": \"spec.Worker.resourceMap.cpu\", \"value\": \"1\", \"required\": \"false\", \"description\": \"\"}, {\"name\": \"spec.Worker.resourceMap.memory\", \"value\": \"1024M\", \"required\": \"false\", \"description\": \"\"}], \"description\": \"This is a template to run pytorch-mnist\\n\", \"experimentSpec\": {\"meta\": {\"cmd\": \"python /var/mnist.py --backend gloo\", \"name\": \"{{experiment_name}}\", \"envVars\": {\"ENV_1\": \"ENV1\"}, \"framework\": \"PyTorch\", \"namespace\": \"default\"}, \"spec\": {\"Master\": {\"replicas\": 1, \"resources\": \"cpu=1,memory=1024M\", \"resourceMap\": {\"cpu\": \"1\", \"memory\": \"1024M\"}}, \"Worker\": {\"replicas\": 1, \"resources\": \"cpu=1,memory=1024M\", \"resourceMap\": {\"cpu\": \"1\", \"memory\": \"1024M\"}}}, \"environment\": {\"image\": \"apache/submarine:pytorch-dist-mnist-1.0\"}}}', NULL, '2020-11-29 17:56:10', NULL, '2020-11-29 17:56:10');
diff --git a/submarine-server/server-core/src/test/java/org/apache/submarine/server/database/TestInitDatabaseMetadata.java b/submarine-server/server-core/src/test/java/org/apache/submarine/server/database/TestInitDatabaseMetadata.java
new file mode 100644
index 0000000000..d8b35311eb
--- /dev/null
+++ b/submarine-server/server-core/src/test/java/org/apache/submarine/server/database/TestInitDatabaseMetadata.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.submarine.server.database;
+
+import org.apache.submarine.commons.utils.SubmarineConfiguration;
+import org.apache.submarine.server.database.initialization.DatabaseMetadataService;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+import static org.junit.Assert.assertTrue;
+
+public class TestInitDatabaseMetadata {
+
+ @Before
+ public void setDefaultVars() {
+ SubmarineConfiguration conf = SubmarineConfiguration.getInstance();
+ conf.updateConfiguration("submarine.metadata.init", "true");
+ conf.updateConfiguration("submarine.metadata.location", "classpath:test_db/migration");
+ conf.updateConfiguration("jdbc.driverClassName", "org.h2.Driver");
+ conf.updateConfiguration("jdbc.url", "jdbc:h2:mem:testdb;MODE=MYSQL;DB_CLOSE_DELAY=-1");
+ conf.updateConfiguration("jdbc.username", "root");
+ conf.updateConfiguration("jdbc.password", "");
+ }
+
+ @Test
+ public void testInit() throws SQLException {
+ // init database
+ new DatabaseMetadataService().initDatabaseMetadata();
+ // test table exists
+ try (Connection conn = DriverManager.getConnection("jdbc:h2:mem:testdb;MODE=MYSQL;DB_CLOSE_DELAY=-1",
+ "root", "");
+ Statement stmt = conn.createStatement();
+ ResultSet rs = stmt.executeQuery("select * from sys_user")) {
+ assertTrue(rs.next());
+ }
+ }
+}
diff --git a/submarine-server/server-core/src/test/resources/test_db/migration/V0.7.0__0.7.0.TES-TCASE.sql b/submarine-server/server-core/src/test/resources/test_db/migration/V0.7.0__0.7.0.TES-TCASE.sql
new file mode 100644
index 0000000000..79b47d489a
--- /dev/null
+++ b/submarine-server/server-core/src/test/resources/test_db/migration/V0.7.0__0.7.0.TES-TCASE.sql
@@ -0,0 +1,41 @@
+-- Licensed to the Apache Software Foundation (ASF) under one or more
+-- contributor license agreements. See the NOTICE file distributed with
+-- this work for additional information regarding copyright ownership.
+-- The ASF licenses this file to You under the Apache License, Version 2.0
+-- (the "License"); you may not use this file except in compliance with
+-- the License. You may obtain a copy of the License at
+-- http://www.apache.org/licenses/LICENSE-2.0
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+
+-- ----------------------------
+-- Test table structure for sys_dict
+-- ----------------------------
+CREATE TABLE IF NOT EXISTS sys_user
+(
+ id varchar(32) NOT NULL COMMENT 'id' primary key ,
+ user_name varchar(32) NOT NULL COMMENT 'login name',
+ real_name varchar(64) NOT NULL COMMENT 'real name',
+ password varchar(255) NOT NULL COMMENT 'password',
+ avatar varchar(255) default NULL COMMENT 'avatar',
+ birthday datetime default NULL COMMENT 'birthday',
+ sex varchar(32) default NULL COMMENT 'sex',
+ email varchar(32) default NULL COMMENT 'email',
+ phone varchar(32) default NULL COMMENT 'telphone',
+ dept_code varchar(32) default NULL COMMENT 'department code',
+ role_code varchar(32) default NULL COMMENT 'role code',
+ status varchar(32) default NULL COMMENT 'status',
+ deleted int(1) default 0 COMMENT 'deleted status(0:normal, 1:already deleted)',
+ create_by varchar(32) default NULL COMMENT 'create user',
+ create_time datetime default NULL COMMENT 'create time',
+ update_by varchar(32) default NULL COMMENT 'last update user',
+ update_time datetime default NULL COMMENT 'last update time'
+);
+
+-- ----------------------------
+-- Test records of sys_user
+-- ----------------------------
+INSERT INTO sys_user VALUES ('e9ca23d68d884d4ebb19d07889727dae', 'admin', 'administrator', '21232f297a57a5a743894a0e4a801fc3', 'avatar.png', '2018-12-05 00:00:00', NULL, 'dev@submarine.org', '18566666661', NULL, NULL, NULL, 0, 'admin', '2019-07-05 14:47:22', 'admin', '2019-07-05 14:47:22');