diff --git a/_environ.py b/_environ.py
new file mode 100644
index 0000000000000000000000000000000000000000..a544ac8f4f0a125d6a65acfd573f65b0c338b838
--- /dev/null
+++ b/_environ.py
@@ -0,0 +1,33 @@
+# coding: utf-8
+# OceanBase Deploy.
+# Copyright (C) 2021 OceanBase
+#
+# This file is part of OceanBase Deploy.
+#
+# OceanBase Deploy is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# OceanBase Deploy is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with OceanBase Deploy. If not, see .
+
+
+from __future__ import absolute_import, division, print_function
+
+# obd dev mode. {0/1}
+ENV_DEV_MODE = "OBD_DEV_MODE"
+
+# base path which will be used by runtime dependencies sync and include config. {absolute path style}
+ENV_BASE_DIR = "OBD_DEPLOY_BASE_DIR"
+
+# the installation mode of remote repository. {cp/ln}
+ENV_REPO_INSTALL_MODE = "OBD_REPO_INSTALL_MODE"
+
+# disable rsync mode even if the rsync exists. {0/1}
+ENV_DISABLE_RSYNC = "OBD_DISABLE_RSYNC"
diff --git a/_optimize.py b/_optimize.py
new file mode 100644
index 0000000000000000000000000000000000000000..3df8c4eb956f26957ce6488649efa4d5989214e4
--- /dev/null
+++ b/_optimize.py
@@ -0,0 +1,142 @@
+# coding: utf-8
+# OceanBase Deploy.
+# Copyright (C) 2021 OceanBase
+#
+# This file is part of OceanBase Deploy.
+#
+# OceanBase Deploy is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# OceanBase Deploy is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with OceanBase Deploy. If not, see .
+
+
+from __future__ import absolute_import, division, print_function
+
+import enum
+import os
+
+from _manager import Manager
+from _rpm import Version
+from tool import YamlLoader, FileUtil, DynamicLoading
+
+yaml_loader = YamlLoader()
+
+
+class OptimizeManager(Manager):
+
+ RELATIVE_PATH = "optimize/"
+
+ def __init__(self, home_path, loader=yaml_loader, stdio=None):
+ self.loader = loader
+ self.components = {}
+ self._parser = None
+ self._optimize_config = None
+ super(OptimizeManager, self).__init__(home_path, stdio=stdio)
+
+ @property
+ def optimize_config(self):
+ if not self._parser:
+ raise Exception("Optimize parser not load")
+ return self._parser.optimize_config
+
+ def load_config(self, path, stdio=None):
+ self._optimize_config = None
+ with FileUtil.open(path, 'rb') as f:
+ config = self.loader.load(f)
+ parser_version = config.get("optimize_version", None)
+ parser = self._get_parser(version=parser_version)
+ self._parser = parser
+ self._load_default_optimizers(parser, stdio=stdio)
+ self._optimize_config = parser.load(config)
+
+ def _search_yaml_file(self, component, version, yaml_name, stdio=None):
+ component_dir = os.path.join(self.path, component)
+ if not os.path.exists(component_dir):
+ stdio.verbose("no optimize config for component {}".format(component))
+ return None
+ yaml_file = os.path.join(component_dir, version, yaml_name)
+ if not os.path.exists(yaml_file):
+ stdio.verbose(
+ 'yaml file {} not found, try to get earlier version.'.format(yaml_file))
+ final_version = Version('')
+ versions = sorted([Version(v) for v in os.listdir(component_dir)], reverse=True)
+ for v in versions:
+ yaml_file = os.path.join(component_dir, v, yaml_name)
+ if os.path.exists(yaml_file) and v <= version:
+ self.stdio.verbose('find earlier version yaml file: {}'.format(yaml_file))
+ break
+ else:
+ yaml_file = os.path.join(component_dir, final_version, yaml_name)
+ stdio.verbose('try to use top yaml file: {}'.format(yaml_file))
+ if not os.path.exists(yaml_file):
+ stdio.verbose('No such yaml file: {}'.format(yaml_file))
+ return None
+ return yaml_file
+
+ def load_default_config(self, test_name, stdio=None):
+ self._optimize_config = None
+ parser = self._get_parser()
+ self._load_default_optimizers(parser, stdio=stdio)
+ yaml_name = '{}.yaml'.format(test_name)
+ for component, version in self.components.items():
+ config_path = self._search_yaml_file(component, version, yaml_name, stdio=stdio)
+ if config_path:
+ with FileUtil.open(config_path, 'rb', stdio=stdio) as f:
+ config = self.loader.load(f)
+ parser.load_config_by_component(component, config, stdio=stdio)
+ self._parser = parser
+
+ def _load_default_optimizers(self, parser, stdio=None):
+ yaml_name = 'optimizer.yaml'
+ for component, version in self.components.items():
+ optimizer_path = self._search_yaml_file(component, version, yaml_name, stdio=stdio)
+ if optimizer_path:
+ with FileUtil.open(optimizer_path, 'rb') as f:
+ config = self.loader.load(f)
+ parser.load_optimizer_by_component(component, config, stdio=stdio)
+
+ @staticmethod
+ def _get_latest_version(path):
+ latest_version = Version('')
+ for name in os.listdir(path):
+ latest_version = max(latest_version, Version(name))
+ return latest_version
+
+ def _get_parser(self, version=None):
+ if self._parser:
+ return self._parser
+ module_name = 'optimize_parser'
+ class_name = 'OptimizeParser'
+ file_name = '{}.py'.format(module_name)
+ parser_base = os.path.join(self.path, module_name)
+ if version is None:
+ version = self._get_latest_version(parser_base)
+ lib_path = os.path.join(parser_base, version)
+ path = os.path.join(lib_path, file_name)
+ if os.path.isfile(path):
+ DynamicLoading.add_lib_path(lib_path)
+ self.stdio.verbose('load optimize parser: {}'.format(path))
+ module = DynamicLoading.import_module(module_name, self.stdio)
+ try:
+ self._parser = getattr(module, class_name)()
+ return self._parser
+ except:
+ self.stdio.exception("")
+ return None
+ finally:
+ DynamicLoading.remove_lib_path(lib_path)
+ else:
+ self.stdio.verbose('No such optimize parser: {}'.format(path))
+ return None
+
+ def register_component(self, name, version):
+ self.stdio.verbose('register component {}-{} to optimize manager'.format(name, version))
+ self.components[name] = Version(version)
diff --git a/docs/.menu_map.yml b/docs/.menu_map.yml
new file mode 100644
index 0000000000000000000000000000000000000000..71cca576339f3b294620825bfccc0d7d6bca7d64
--- /dev/null
+++ b/docs/.menu_map.yml
@@ -0,0 +1,3 @@
+3.user-guide=使用指南
+3.obd-command=OBD 命令
+5.faq=常见问题
diff --git a/docs/.menu_map_en.yml b/docs/.menu_map_en.yml
new file mode 100644
index 0000000000000000000000000000000000000000..264ff28d874a34132ce8e94fe273b8dce098806a
--- /dev/null
+++ b/docs/.menu_map_en.yml
@@ -0,0 +1,2 @@
+3.user-guide=User Guide
+3.obd-command=OBD command
\ No newline at end of file
diff --git a/docs/en-US/3.user-guide/2.start-the-oceanbase-cluster-by-using-obd.md b/docs/en-US/3.user-guide/2.start-the-oceanbase-cluster-by-using-obd.md
index bf1979887fc189bf016b9bb2d230849a6913032a..674fb086748010e68b9fb6a309908f0a5f87a22d 100644
--- a/docs/en-US/3.user-guide/2.start-the-oceanbase-cluster-by-using-obd.md
+++ b/docs/en-US/3.user-guide/2.start-the-oceanbase-cluster-by-using-obd.md
@@ -4,30 +4,39 @@ To start an OceanBase cluster, follow these steps:
## Step 1: Select a configuration file
-Select a configuration file based on your resource configurations:
+OBD provides different configuration files for different deployment scenarios. These configuration file examples are placed in the directory `/usr/OBD/example/`. Select a configuration file based on your resource configurations:
### Small-scale deployment mode
This deployment mode applies to personal devices with at least 8 GB of memory.
-- [Sample configuration file for local single-node deployment](https://github.com/oceanbase/obdeploy/blob/master/example/mini-local-example.yaml)
-- [Sample configuration file for single-node deployment](https://github.com/oceanbase/obdeploy/blob/master/example/mini-single-example.yaml)
-- [Sample configuration file for three-node deployment](https://github.com/oceanbase/obdeploy/blob/master/example/mini-distributed-example.yaml)
-- [Sample configuration file for single-node deployment with ODP](https://github.com/oceanbase/obdeploy/blob/master/example/mini-single-with-obproxy-example.yaml)
-- [Sample configuration file for three-node deployment with ODP](https://github.com/oceanbase/obdeploy/blob/master/example/mini-distributed-with-obproxy-example.yaml)
+- Sample configuration file for local single-node deployment: /usr/obd/example/mini-local-example.yaml
+
+- Sample configuration file for single-node deployment: /usr/obd/example/mini-single-example.yaml
+
+- Sample configuration file for three-node deployment: /usr/obd/example/mini-distributed-example.yaml
+
+- Sample configuration file for single-node deployment with ODP: /usr/obd/example/mini-single-with-obproxy-example.yaml
+
+- Sample configuration file for three-node deployment with ODP: /usr/obd/example/mini-distributed-with-obproxy-example.yaml
### Professional deployment mode
This deployment mode applies to advanced Elastic Compute Service (ECS) instances or physical servers with at least 16 CPU cores and 64 GB of memory.
-- [Sample configuration file for local single-node deployment](https://github.com/oceanbase/obdeploy/blob/master/example/local-example.yaml)
-- [Sample configuration file for single-node deployment](https://github.com/oceanbase/obdeploy/blob/master/example/single-example.yaml)
-- [Sample configuration file for three-node deployment](https://github.com/oceanbase/obdeploy/blob/master/example/distributed-example.yaml)
-- [Sample configuration file for single-node deployment with ODP](https://github.com/oceanbase/obdeploy/blob/master/example/single-with-obproxy-example.yaml)
-- [Sample configuration file for three-node deployment with ODP](https://github.com/oceanbase/obdeploy/blob/master/example/distributed-with-obproxy-example.yaml)
-- [Sample configuration file for three-node deployment with ODP and obagent](https://github.com/oceanbase/obdeploy/blob/master/example/obagent/distributed-with-obproxy-and-obagent-example.yaml)
+- Sample configuration file for local single-node deployment: /usr/obd/example/local-example.yaml
+
+- Sample configuration file for single-node deployment: /usr/obd/example/single-example.yaml
-This section describes how to start a local single-node OceanBase cluster by using the [sample configuration file for local single-node deployment in the small-scale deployment mode](https://github.com/oceanbase/obdeploy/blob/master/example/mini-local-example.yaml).
+- Sample configuration file for three-node deployment: /usr/obd/example/distributed-example.yaml
+
+- Sample configuration file for single-node deployment with ODP: /usr/obd/example/single-with-obproxy-example.yaml
+
+- Sample configuration file for three-node deployment with ODP: /usr/obd/example/distributed-with-obproxy-example.yaml
+
+- Sample configuration file for three-node deployment with ODP and obagent: /usr/obd/example/obagent/distributed-with-obproxy-and-obagent-example.yaml
+
+This section describes how to start a local single-node OceanBase cluster by using the sample configuration file for local single-node deployment in the small-scale deployment mode: /usr/obd/example/mini-local-example.yaml.
```shell
# Modify the working directory of the OceanBase cluster: home_path.
@@ -47,7 +56,10 @@ user:
```
`username` specifies the username used to log on to the target server. Make sure that your username has the write permission on the `home_path` directory. `password` and `key_file` are used to authenticate the user. Generally, only one of them is required.
-> **NOTE:** After you specify the path of the key, add an annotation to the `password` field or delete it if your key does not require a password. Otherwise, `password` will be deemed as the password of the key and used for login, leading to a logon verification failure.
+
+> **NOTE:**
+>
+> After you specify the path of the key, add an annotation to the `password` field or delete it if your key does not require a password. Otherwise, `password` will be deemed as the password of the key and used for login, leading to a logon verification failure.
## Step 2: Deploy and start a cluster
diff --git a/docs/en-US/3.user-guide/3.obd-command/1.cluster-command-groups.md b/docs/en-US/3.user-guide/3.obd-command/1.cluster-command-groups.md
index 64aa0d3399bd1f962b0cc6d6f9b2b9790bbbd37c..a174ef0f969664c4f43664c3bc74338c14d1d29a 100644
--- a/docs/en-US/3.user-guide/3.obd-command/1.cluster-command-groups.md
+++ b/docs/en-US/3.user-guide/3.obd-command/1.cluster-command-groups.md
@@ -181,12 +181,28 @@ obd cluster upgrade -c -V [tags]
| Option | Required | Data type | Default value | Description |
--- | --- | --- |--- |---
-c/--component | Yes | string | empty | The component name you want to upgrade.
--V/--version | Yes | string | The target upgrade version number.
+-V/--version | Yes | string | empty | The target upgrade version number.
--skip-check | No | bool | false | Skip check.
--usable | No | string | empty | The hash list for the mirrors that you use during upgrade. Separated with `,`.
--disable | No | string | empty | The hash list for the mirrors that you disable during upgrade. Separated with `,`.
-e/--executer-path | No | string | /usr/obd/lib/executer | The executer path for the upgrade script.
+## obd cluster reinstall
+
+You can run this command to reinstall the repository of a deployed component. The new repository must have the same version number as the previous repository. If this command is used to replace the repository when the deployment status is 'running', the component is restarted after the replacement without loading parameters.
+
+```bash
+obd cluster reinstall -c --hash [-f/--force]
+```
+
+The `deploy name` parameter indicates the name of the deployed cluster, which is also the alias of the configuration file.
+
+| Option name | Required | Data type | Default value | Description |
+|---------|----------|-------------|-------------|--------------|
+| -c/--component | Yes | string | Null | The name of the component whose repository is to be replaced. |
+|--hash | Yes | string | Null | The target repository. It must be of the same version as the current repository. |
+| -f/--force | No | Bool | false | Specifies whether to enable forced replacement even if the restart fails. |
+
## `obd cluster tenant create`
Creates a tenant. This command applies only to an OceanBase cluster. This command automatically creates resource units and resource pools.
@@ -232,3 +248,41 @@ obd cluster tenant drop [-n ]
`deploy name` specifies the name of the deployment configuration file.
`-n` is `--tenant-name`. This option specifies the name of the tenant to be deleted. This option is required.
+
+## obd cluster chst
+
+You can run this command to change the configuration style.
+
+```shell
+obd cluster chst --style