This is an automated email from the ASF dual-hosted git repository.

wuzhiguo pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/bigtop-manager.git


The following commit(s) were added to refs/heads/main by this push:
     new c58eb4d2 BIGTOP-4323: Add component init/prepare commands for internal 
use (#145)
c58eb4d2 is described below

commit c58eb4d23b2465ed38e6144d577b5404f1f0f55b
Author: Zhiguo Wu <[email protected]>
AuthorDate: Wed Jan 8 20:25:51 2025 +0800

    BIGTOP-4323: Add component init/prepare commands for internal use (#145)
---
 .../bigtop/manager/common/enums/Command.java       |   6 +-
 .../command/helper/ComponentStageHelper.java       | 193 +++++++++++++++++++++
 .../manager/server/command/job/AbstractJob.java    |   7 +
 .../command/job/cluster/AbstractClusterJob.java    |  98 ++---------
 .../command/job/cluster/ClusterRestartJob.java     |  13 +-
 .../command/job/cluster/ClusterStartJob.java       |  10 +-
 .../server/command/job/cluster/ClusterStopJob.java |  10 +-
 .../job/component/AbstractComponentJob.java        | 119 +------------
 .../command/job/component/ComponentAddJob.java     |  17 +-
 .../command/job/component/ComponentRestartJob.java |  13 +-
 .../command/job/component/ComponentStartJob.java   |  10 +-
 .../command/job/component/ComponentStopJob.java    |  10 +-
 .../server/command/job/host/AbstractHostJob.java   |  91 ++--------
 .../server/command/job/host/HostRestartJob.java    |  13 +-
 .../server/command/job/host/HostStartJob.java      |  10 +-
 .../server/command/job/host/HostStopJob.java       |  10 +-
 .../command/job/service/AbstractServiceJob.java    | 155 +----------------
 .../server/command/job/service/ServiceAddJob.java  |  68 ++++----
 .../command/job/service/ServiceCheckJob.java       |   7 +-
 .../command/job/service/ServiceConfigureJob.java   |  16 +-
 .../command/job/service/ServiceRestartJob.java     |  10 +-
 .../command/job/service/ServiceStartJob.java       |   7 +-
 .../server/command/job/service/ServiceStopJob.java |   7 +-
 .../ComponentInitStage.java}                       |  19 +-
 .../ComponentPrepareStage.java}                    |  19 +-
 .../ComponentInitTask.java}                        |  18 +-
 .../ComponentPrepareTask.java}                     |  18 +-
 .../bigtop/manager/server/utils/StackDAGUtils.java |  65 -------
 .../stacks/bigtop/3.3.0/services/hive/order.json   |   4 +-
 .../stacks/bigtop/3.3.0/services/kafka/order.json  |   3 -
 .../bigtop/v3_3_0/hive/HiveMetastoreScript.java    |  64 ++++---
 .../stack/core/spi/script/AbstractScript.java      |  11 ++
 .../manager/stack/core/spi/script/Script.java      |  29 +++-
 .../infra/v1_0_0/mysql/MySQLServerScript.java      |  64 +++----
 34 files changed, 560 insertions(+), 654 deletions(-)

diff --git 
a/bigtop-manager-common/src/main/java/org/apache/bigtop/manager/common/enums/Command.java
 
b/bigtop-manager-common/src/main/java/org/apache/bigtop/manager/common/enums/Command.java
index 6eed8637..3ca6f2b9 100644
--- 
a/bigtop-manager-common/src/main/java/org/apache/bigtop/manager/common/enums/Command.java
+++ 
b/bigtop-manager-common/src/main/java/org/apache/bigtop/manager/common/enums/Command.java
@@ -29,7 +29,7 @@ import lombok.Getter;
 @Getter
 public enum Command {
     // Available for: Cluster, Host, Service, Component
-    // Remove is not a command because it won't create job, please refer to 
the related controller for remove action.
+    // Remove is not a command because it won't create job, please refer to 
the related API for remove action.
     ADD("add", "Add"),
     START("start", "Start"),
     STOP("stop", "Stop"),
@@ -40,7 +40,9 @@ public enum Command {
     CONFIGURE("configure", "Configure"),
     CUSTOM("custom", "Custom"),
 
-    // Internal use only, not available for job creation
+    // Internal use only, not available for API call
+    INIT("init", "Init"),
+    PREPARE("prepare", "Prepare"),
     STATUS("status", "Status"),
     ;
 
diff --git 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/helper/ComponentStageHelper.java
 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/helper/ComponentStageHelper.java
new file mode 100644
index 00000000..05ab40d2
--- /dev/null
+++ 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/helper/ComponentStageHelper.java
@@ -0,0 +1,193 @@
+/*
+ * 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
+ *
+ *    https://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.bigtop.manager.server.command.helper;
+
+import org.apache.bigtop.manager.common.enums.Command;
+import org.apache.bigtop.manager.server.command.stage.ComponentAddStage;
+import org.apache.bigtop.manager.server.command.stage.ComponentCheckStage;
+import org.apache.bigtop.manager.server.command.stage.ComponentConfigureStage;
+import org.apache.bigtop.manager.server.command.stage.ComponentInitStage;
+import org.apache.bigtop.manager.server.command.stage.ComponentPrepareStage;
+import org.apache.bigtop.manager.server.command.stage.ComponentStartStage;
+import org.apache.bigtop.manager.server.command.stage.ComponentStopStage;
+import org.apache.bigtop.manager.server.command.stage.Stage;
+import org.apache.bigtop.manager.server.command.stage.StageContext;
+import org.apache.bigtop.manager.server.command.task.Task;
+import org.apache.bigtop.manager.server.exception.ServerException;
+import org.apache.bigtop.manager.server.model.dto.CommandDTO;
+import org.apache.bigtop.manager.server.model.dto.ComponentDTO;
+import org.apache.bigtop.manager.server.model.dto.ServiceDTO;
+import org.apache.bigtop.manager.server.utils.StackUtils;
+
+import org.apache.commons.collections4.CollectionUtils;
+
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+@Slf4j
+public class ComponentStageHelper {
+
+    public static List<Stage> createComponentStages(Map<String, List<String>> 
componentHosts, CommandDTO commandDTO) {
+        return createComponentStages(componentHosts, commandDTO.getCommand(), 
commandDTO);
+    }
+
+    public static List<Stage> createComponentStages(
+            Map<String, List<String>> componentHosts, Command command, 
CommandDTO commandDTO) {
+        return createComponentStages(componentHosts, List.of(command), 
commandDTO);
+    }
+
+    public static List<Stage> createComponentStages(
+            Map<String, List<String>> componentHosts, List<Command> commands, 
CommandDTO commandDTO) {
+        List<Stage> stages = new ArrayList<>();
+        List<String> componentNames = new ArrayList<>(componentHosts.keySet());
+        List<String> todoList = getTodoList(componentNames, commands);
+
+        for (String componentCommand : todoList) {
+            String[] split = componentCommand.split("-");
+            String componentName = split[0].toLowerCase();
+            Command command = Command.valueOf(split[1].toUpperCase());
+
+            List<String> hostnames = componentHosts.get(componentName);
+            if (CollectionUtils.isEmpty(hostnames)) {
+                continue;
+            }
+
+            StageContext stageContext;
+            switch (command) {
+                case ADD:
+                    stageContext = createStageContext(componentName, 
hostnames, commandDTO);
+                    stages.add(new ComponentAddStage(stageContext));
+                    break;
+                case START:
+                    if (!StackUtils.isClientComponent(componentName)) {
+                        stageContext = createStageContext(componentName, 
hostnames, commandDTO);
+                        stages.add(new ComponentStartStage(stageContext));
+                    }
+                    break;
+                case STOP:
+                    if (!StackUtils.isClientComponent(componentName)) {
+                        stageContext = createStageContext(componentName, 
hostnames, commandDTO);
+                        stages.add(new ComponentStopStage(stageContext));
+                    }
+                    break;
+                case CHECK:
+                    if (!StackUtils.isClientComponent(componentName)) {
+                        stageContext = createStageContext(componentName, 
List.of(hostnames.get(0)), commandDTO);
+                        stages.add(new ComponentCheckStage(stageContext));
+                    }
+                    break;
+                case CONFIGURE:
+                    stageContext = createStageContext(componentName, 
hostnames, commandDTO);
+                    stages.add(new ComponentConfigureStage(stageContext));
+                    break;
+                case INIT:
+                    stageContext = createStageContext(componentName, 
hostnames, commandDTO);
+                    stages.add(new ComponentInitStage(stageContext));
+                    break;
+                case PREPARE:
+                    // Prepare phase runs after component started, client 
component shouldn't create this.
+                    if (!StackUtils.isClientComponent(componentName)) {
+                        stageContext = createStageContext(componentName, 
hostnames, commandDTO);
+                        stages.add(new ComponentPrepareStage(stageContext));
+                    }
+                    break;
+            }
+        }
+
+        return stages;
+    }
+
+    private static StageContext createStageContext(
+            String componentName, List<String> hostnames, CommandDTO 
commandDTO) {
+        StageContext stageContext = StageContext.fromCommandDTO(commandDTO);
+
+        ServiceDTO serviceDTO = 
StackUtils.getServiceDTOByComponentName(componentName);
+        ComponentDTO componentDTO = StackUtils.getComponentDTO(componentName);
+
+        stageContext.setHostnames(hostnames);
+        stageContext.setServiceDTO(serviceDTO);
+        stageContext.setComponentDTO(componentDTO);
+
+        return stageContext;
+    }
+
+    private static List<String> getTodoList(List<String> componentNames, 
Command command) {
+        return getTodoList(componentNames, List.of(command));
+    }
+
+    private static List<String> getTodoList(List<String> componentNames, 
List<Command> commands) {
+        try {
+            List<String> orderedList =
+                    StackUtils.DAG.getAllNodesList().isEmpty() ? new 
ArrayList<>() : StackUtils.DAG.topologicalSort();
+            orderedList.replaceAll(String::toUpperCase);
+            List<String> componentCommandNames = new ArrayList<>();
+            for (String componentName : componentNames) {
+                for (Command command : commands) {
+                    String name =
+                            componentName.toUpperCase() + "-" + 
command.name().toUpperCase();
+                    componentCommandNames.add(name);
+                }
+            }
+
+            // Re-order the commands, since order.json does not contain all 
commands,
+            // only contains which has dependencies, we need to add the rest 
to the end.
+            if (commands.size() == 1) {
+                orderedList.retainAll(componentCommandNames);
+                componentCommandNames.removeAll(orderedList);
+                orderedList.addAll(componentCommandNames);
+                return orderedList;
+            } else {
+                // TODO, order.json currently only contains start/stop 
dependencies of major components, the situation
+                // of commands size greater than 1 is only with 
init/start/prepare commands, we see this as a special
+                // situation and use special logic for it, should use a better 
solution in the future.
+                orderedList.retainAll(componentCommandNames);
+                componentCommandNames.removeAll(orderedList);
+
+                List<String> res = new ArrayList<>();
+                List<String> commandOrder = List.of("ADD", "CONFIGURE", 
"INIT", "START", "PREPARE", "CHECK");
+                for (String command : commandOrder) {
+                    List<String> filtered = componentCommandNames.stream()
+                            .filter(s -> s.endsWith(command))
+                            .toList();
+                    res.addAll(filtered);
+                    if (command.equals("START")) {
+                        res.addAll(orderedList);
+                    }
+                }
+
+                return res;
+            }
+
+        } catch (Exception e) {
+            throw new ServerException(e);
+        }
+    }
+
+    public static void printStageDump(List<Stage> stages) {
+        log.info("Dumping stages...");
+        for (Stage stage : stages) {
+            List<String> taskNames =
+                    stage.getTasks().stream().map(Task::getName).toList();
+            log.info("[{}] : [{}]", stage.getName(), String.join(",", 
taskNames));
+        }
+    }
+}
diff --git 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/AbstractJob.java
 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/AbstractJob.java
index 635d5590..1f72ba5d 100644
--- 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/AbstractJob.java
+++ 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/AbstractJob.java
@@ -28,7 +28,9 @@ import org.apache.bigtop.manager.dao.repository.ClusterDao;
 import org.apache.bigtop.manager.dao.repository.JobDao;
 import org.apache.bigtop.manager.dao.repository.StageDao;
 import org.apache.bigtop.manager.dao.repository.TaskDao;
+import org.apache.bigtop.manager.server.command.stage.CacheFileUpdateStage;
 import org.apache.bigtop.manager.server.command.stage.Stage;
+import org.apache.bigtop.manager.server.command.stage.StageContext;
 import org.apache.bigtop.manager.server.command.task.Task;
 import org.apache.bigtop.manager.server.holder.SpringContextHolder;
 
@@ -82,6 +84,11 @@ public abstract class AbstractJob implements Job {
 
     protected abstract void createStages();
 
+    protected void createCacheStage() {
+        StageContext stageContext = 
StageContext.fromCommandDTO(jobContext.getCommandDTO());
+        stages.add(new CacheFileUpdateStage(stageContext));
+    }
+
     @Override
     public void beforeRun() {
         jobPO.setState(JobState.PROCESSING.getName());
diff --git 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/cluster/AbstractClusterJob.java
 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/cluster/AbstractClusterJob.java
index 211788e7..d6bfbd71 100644
--- 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/cluster/AbstractClusterJob.java
+++ 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/cluster/AbstractClusterJob.java
@@ -18,25 +18,17 @@
  */
 package org.apache.bigtop.manager.server.command.job.cluster;
 
-import org.apache.bigtop.manager.common.enums.Command;
 import org.apache.bigtop.manager.dao.po.ComponentPO;
 import org.apache.bigtop.manager.dao.query.ComponentQuery;
 import org.apache.bigtop.manager.dao.repository.ComponentDao;
 import org.apache.bigtop.manager.server.command.job.AbstractJob;
 import org.apache.bigtop.manager.server.command.job.JobContext;
-import org.apache.bigtop.manager.server.command.stage.ComponentStartStage;
-import org.apache.bigtop.manager.server.command.stage.ComponentStopStage;
-import org.apache.bigtop.manager.server.command.stage.StageContext;
 import org.apache.bigtop.manager.server.holder.SpringContextHolder;
-import org.apache.bigtop.manager.server.model.dto.ComponentDTO;
-import org.apache.bigtop.manager.server.model.dto.ServiceDTO;
-import org.apache.bigtop.manager.server.utils.StackDAGUtils;
-import org.apache.bigtop.manager.server.utils.StackUtils;
-
-import org.apache.commons.collections4.CollectionUtils;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 public abstract class AbstractClusterJob extends AbstractJob {
 
@@ -58,84 +50,16 @@ public abstract class AbstractClusterJob extends 
AbstractJob {
         super.beforeCreateStages();
     }
 
-    protected StageContext createStageContext(String componentName, 
List<String> hostnames) {
-        StageContext stageContext = 
StageContext.fromCommandDTO(jobContext.getCommandDTO());
-
-        ServiceDTO serviceDTO = 
StackUtils.getServiceDTOByComponentName(componentName);
-        ComponentDTO componentDTO = StackUtils.getComponentDTO(componentName);
-
-        stageContext.setHostnames(hostnames);
-        stageContext.setServiceDTO(serviceDTO);
-        stageContext.setComponentDTO(componentDTO);
-
-        return stageContext;
-    }
-
-    protected void createStartStages() {
-        List<ComponentPO> componentPOList = getComponentPOList();
-        List<String> todoList = 
StackDAGUtils.getTodoList(getComponentNames(componentPOList), Command.START);
-
-        for (String componentCommand : todoList) {
-            String[] split = componentCommand.split("-");
-            String componentName = split[0];
-
-            if (StackUtils.isClientComponent(componentName)) {
-                continue;
-            }
-
-            List<String> hostnames = 
findHostnamesByComponentName(componentPOList, componentName);
-            if (CollectionUtils.isEmpty(hostnames)) {
-                continue;
-            }
-
-            StageContext stageContext = createStageContext(componentName, 
hostnames);
-            stages.add(new ComponentStartStage(stageContext));
-        }
-    }
-
-    protected void createStopStages() {
-        List<ComponentPO> componentPOList = getComponentPOList();
-        List<String> todoList = 
StackDAGUtils.getTodoList(getComponentNames(componentPOList), Command.STOP);
-
-        for (String componentCommand : todoList) {
-            String[] split = componentCommand.split("-");
-            String componentName = split[0];
-
-            if (StackUtils.isClientComponent(componentName)) {
-                continue;
-            }
-
-            List<String> hostnames = 
findHostnamesByComponentName(componentPOList, componentName);
-            if (CollectionUtils.isEmpty(hostnames)) {
-                continue;
-            }
-
-            StageContext stageContext = createStageContext(componentName, 
hostnames);
-            stages.add(new ComponentStopStage(stageContext));
-        }
-    }
-
-    private List<ComponentPO> getComponentPOList() {
-        return componentDao.findByQuery(
-                ComponentQuery.builder().clusterId(clusterPO.getId()).build());
-    }
-
-    private List<String> getComponentNames(List<ComponentPO> componentPOList) {
-        if (componentPOList == null) {
-            return new ArrayList<>();
-        } else {
-            return 
componentPOList.stream().map(ComponentPO::getName).distinct().toList();
+    protected Map<String, List<String>> getComponentHostsMap() {
+        ComponentQuery componentQuery =
+                ComponentQuery.builder().clusterId(clusterPO.getId()).build();
+        List<ComponentPO> componentPOList = 
componentDao.findByQuery(componentQuery);
+        Map<String, List<String>> componentHostsMap = new HashMap<>();
+        for (ComponentPO componentPO : componentPOList) {
+            List<String> hosts = 
componentHostsMap.computeIfAbsent(componentPO.getName(), k -> new 
ArrayList<>());
+            hosts.add(componentPO.getHostname());
         }
-    }
 
-    private List<String> findHostnamesByComponentName(List<ComponentPO> 
componentPOList, String componentName) {
-        if (componentPOList == null) {
-            return new ArrayList<>();
-        } else {
-            return componentPOList.stream()
-                    .filter(componentPO -> 
componentPO.getName().equals(componentName))
-                    .map(ComponentPO::getHostname)
-                    .toList();
-        }
+        return componentHostsMap;
     }
 }
diff --git 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/cluster/ClusterRestartJob.java
 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/cluster/ClusterRestartJob.java
index 6ac4c5d1..7813693f 100644
--- 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/cluster/ClusterRestartJob.java
+++ 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/cluster/ClusterRestartJob.java
@@ -18,7 +18,13 @@
  */
 package org.apache.bigtop.manager.server.command.job.cluster;
 
+import org.apache.bigtop.manager.common.enums.Command;
+import org.apache.bigtop.manager.server.command.helper.ComponentStageHelper;
 import org.apache.bigtop.manager.server.command.job.JobContext;
+import org.apache.bigtop.manager.server.model.dto.CommandDTO;
+
+import java.util.List;
+import java.util.Map;
 
 public class ClusterRestartJob extends AbstractClusterJob {
 
@@ -28,9 +34,12 @@ public class ClusterRestartJob extends AbstractClusterJob {
 
     @Override
     protected void createStages() {
-        super.createStopStages();
+        CommandDTO commandDTO = jobContext.getCommandDTO();
+        Map<String, List<String>> componentHostsMap = getComponentHostsMap();
 
-        super.createStartStages();
+        // Restart services
+        
stages.addAll(ComponentStageHelper.createComponentStages(componentHostsMap, 
Command.STOP, commandDTO));
+        
stages.addAll(ComponentStageHelper.createComponentStages(componentHostsMap, 
Command.START, commandDTO));
     }
 
     @Override
diff --git 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/cluster/ClusterStartJob.java
 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/cluster/ClusterStartJob.java
index 9f8ff7a8..d1f6dba1 100644
--- 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/cluster/ClusterStartJob.java
+++ 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/cluster/ClusterStartJob.java
@@ -18,7 +18,12 @@
  */
 package org.apache.bigtop.manager.server.command.job.cluster;
 
+import org.apache.bigtop.manager.server.command.helper.ComponentStageHelper;
 import org.apache.bigtop.manager.server.command.job.JobContext;
+import org.apache.bigtop.manager.server.model.dto.CommandDTO;
+
+import java.util.List;
+import java.util.Map;
 
 public class ClusterStartJob extends AbstractClusterJob {
 
@@ -28,7 +33,10 @@ public class ClusterStartJob extends AbstractClusterJob {
 
     @Override
     protected void createStages() {
-        super.createStartStages();
+        CommandDTO commandDTO = jobContext.getCommandDTO();
+        Map<String, List<String>> componentHostsMap = getComponentHostsMap();
+
+        
stages.addAll(ComponentStageHelper.createComponentStages(componentHostsMap, 
commandDTO));
     }
 
     @Override
diff --git 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/cluster/ClusterStopJob.java
 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/cluster/ClusterStopJob.java
index ee4cc770..ff509d4c 100644
--- 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/cluster/ClusterStopJob.java
+++ 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/cluster/ClusterStopJob.java
@@ -18,7 +18,12 @@
  */
 package org.apache.bigtop.manager.server.command.job.cluster;
 
+import org.apache.bigtop.manager.server.command.helper.ComponentStageHelper;
 import org.apache.bigtop.manager.server.command.job.JobContext;
+import org.apache.bigtop.manager.server.model.dto.CommandDTO;
+
+import java.util.List;
+import java.util.Map;
 
 public class ClusterStopJob extends AbstractClusterJob {
 
@@ -28,7 +33,10 @@ public class ClusterStopJob extends AbstractClusterJob {
 
     @Override
     protected void createStages() {
-        super.createStopStages();
+        CommandDTO commandDTO = jobContext.getCommandDTO();
+        Map<String, List<String>> componentHostsMap = getComponentHostsMap();
+
+        
stages.addAll(ComponentStageHelper.createComponentStages(componentHostsMap, 
commandDTO));
     }
 
     @Override
diff --git 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/component/AbstractComponentJob.java
 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/component/AbstractComponentJob.java
index 7fa057f5..3374cf22 100644
--- 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/component/AbstractComponentJob.java
+++ 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/component/AbstractComponentJob.java
@@ -18,29 +18,16 @@
  */
 package org.apache.bigtop.manager.server.command.job.component;
 
-import org.apache.bigtop.manager.common.enums.Command;
 import org.apache.bigtop.manager.dao.repository.ComponentDao;
 import org.apache.bigtop.manager.dao.repository.HostDao;
 import org.apache.bigtop.manager.dao.repository.ServiceDao;
 import org.apache.bigtop.manager.server.command.job.AbstractJob;
 import org.apache.bigtop.manager.server.command.job.JobContext;
-import org.apache.bigtop.manager.server.command.stage.CacheFileUpdateStage;
-import org.apache.bigtop.manager.server.command.stage.ComponentAddStage;
-import org.apache.bigtop.manager.server.command.stage.ComponentConfigureStage;
-import org.apache.bigtop.manager.server.command.stage.ComponentStartStage;
-import org.apache.bigtop.manager.server.command.stage.ComponentStopStage;
-import org.apache.bigtop.manager.server.command.stage.StageContext;
 import org.apache.bigtop.manager.server.holder.SpringContextHolder;
-import org.apache.bigtop.manager.server.model.dto.ComponentDTO;
-import org.apache.bigtop.manager.server.model.dto.ServiceDTO;
-import org.apache.bigtop.manager.server.model.dto.command.ComponentCommandDTO;
-import org.apache.bigtop.manager.server.utils.StackDAGUtils;
-import org.apache.bigtop.manager.server.utils.StackUtils;
 
-import org.apache.commons.collections4.CollectionUtils;
-
-import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 public abstract class AbstractComponentJob extends AbstractJob {
 
@@ -66,105 +53,15 @@ public abstract class AbstractComponentJob extends 
AbstractJob {
         super.beforeCreateStages();
     }
 
-    protected StageContext createStageContext(String componentName, 
List<String> hostnames) {
-        StageContext stageContext = 
StageContext.fromCommandDTO(jobContext.getCommandDTO());
-
-        ServiceDTO serviceDTO = 
StackUtils.getServiceDTOByComponentName(componentName);
-        ComponentDTO componentDTO = StackUtils.getComponentDTO(componentName);
-
-        stageContext.setHostnames(hostnames);
-        stageContext.setServiceDTO(serviceDTO);
-        stageContext.setComponentDTO(componentDTO);
-
-        return stageContext;
-    }
-
-    protected void createCacheStage() {
-        StageContext stageContext = 
StageContext.fromCommandDTO(jobContext.getCommandDTO());
-        stages.add(new CacheFileUpdateStage(stageContext));
-    }
-
-    protected void createAddStages() {
-        List<String> todoList = StackDAGUtils.getTodoList(getComponentNames(), 
Command.ADD);
-
-        for (String componentCommand : todoList) {
-            String[] split = componentCommand.split("-");
-            String componentName = split[0];
-            List<String> hostnames = getHostnames(componentName);
-            if (CollectionUtils.isEmpty(hostnames)) {
-                continue;
-            }
-
-            StageContext stageContext = createStageContext(componentName, 
hostnames);
-            stages.add(new ComponentAddStage(stageContext));
-        }
-    }
+    protected Map<String, List<String>> getComponentHostsMap() {
+        Map<String, List<String>> componentHostsMap = new HashMap<>();
 
-    protected void createConfigureStages() {
-        for (ComponentCommandDTO componentCommand : 
jobContext.getCommandDTO().getComponentCommands()) {
+        
jobContext.getCommandDTO().getComponentCommands().forEach(componentCommand -> {
             String componentName = componentCommand.getComponentName();
             List<String> hostnames = componentCommand.getHostnames();
+            componentHostsMap.put(componentName, hostnames);
+        });
 
-            StageContext stageContext = createStageContext(componentName, 
hostnames);
-            stages.add(new ComponentConfigureStage(stageContext));
-        }
-    }
-
-    protected void createStartStages() {
-        List<String> todoList = StackDAGUtils.getTodoList(getComponentNames(), 
Command.START);
-
-        for (String componentCommand : todoList) {
-            String[] split = componentCommand.split("-");
-            String componentName = split[0];
-
-            if (StackUtils.isClientComponent(componentName)) {
-                continue;
-            }
-
-            List<String> hostnames = getHostnames(componentName);
-            if (CollectionUtils.isEmpty(hostnames)) {
-                continue;
-            }
-
-            StageContext stageContext = createStageContext(componentName, 
hostnames);
-            stages.add(new ComponentStartStage(stageContext));
-        }
-    }
-
-    protected void createStopStages() {
-        List<String> todoList = StackDAGUtils.getTodoList(getComponentNames(), 
Command.STOP);
-
-        for (String componentCommand : todoList) {
-            String[] split = componentCommand.split("-");
-            String componentName = split[0];
-
-            if (StackUtils.isClientComponent(componentName)) {
-                continue;
-            }
-
-            List<String> hostnames = getHostnames(componentName);
-            if (CollectionUtils.isEmpty(hostnames)) {
-                continue;
-            }
-
-            StageContext stageContext = createStageContext(componentName, 
hostnames);
-            stages.add(new ComponentStopStage(stageContext));
-        }
-    }
-
-    private List<String> getComponentNames() {
-        return jobContext.getCommandDTO().getComponentCommands().stream()
-                .map(ComponentCommandDTO::getComponentName)
-                .toList();
-    }
-
-    private List<String> getHostnames(String componentName) {
-        for (ComponentCommandDTO componentCommand : 
jobContext.getCommandDTO().getComponentCommands()) {
-            if (componentCommand.getComponentName().equals(componentName)) {
-                return componentCommand.getHostnames();
-            }
-        }
-
-        return new ArrayList<>();
+        return componentHostsMap;
     }
 }
diff --git 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/component/ComponentAddJob.java
 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/component/ComponentAddJob.java
index 762b7b08..c95fd60b 100644
--- 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/component/ComponentAddJob.java
+++ 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/component/ComponentAddJob.java
@@ -18,9 +18,11 @@
  */
 package org.apache.bigtop.manager.server.command.job.component;
 
+import org.apache.bigtop.manager.common.enums.Command;
 import org.apache.bigtop.manager.dao.po.ComponentPO;
 import org.apache.bigtop.manager.dao.po.HostPO;
 import org.apache.bigtop.manager.dao.po.ServicePO;
+import org.apache.bigtop.manager.server.command.helper.ComponentStageHelper;
 import org.apache.bigtop.manager.server.command.job.JobContext;
 import org.apache.bigtop.manager.server.enums.HealthyStatusEnum;
 import org.apache.bigtop.manager.server.model.converter.ComponentConverter;
@@ -32,6 +34,7 @@ import org.apache.bigtop.manager.server.utils.StackUtils;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
 
 public class ComponentAddJob extends AbstractComponentJob {
 
@@ -49,14 +52,18 @@ public class ComponentAddJob extends AbstractComponentJob {
         // Update cache files
         super.createCacheStage();
 
+        CommandDTO commandDTO = jobContext.getCommandDTO();
+        Map<String, List<String>> componentHostsMap = getComponentHostsMap();
+
         // Install components
-        super.createAddStages();
+        
stages.addAll(ComponentStageHelper.createComponentStages(componentHostsMap, 
Command.ADD, commandDTO));
 
-        // Configure services
-        super.createConfigureStages();
+        // Configure components
+        
stages.addAll(ComponentStageHelper.createComponentStages(componentHostsMap, 
Command.CONFIGURE, commandDTO));
 
-        // Start all master components
-        super.createStartStages();
+        // Init/Start/Prepare components
+        List<Command> commands = List.of(Command.INIT, Command.START, 
Command.PREPARE);
+        
stages.addAll(ComponentStageHelper.createComponentStages(componentHostsMap, 
commands, commandDTO));
     }
 
     @Override
diff --git 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/component/ComponentRestartJob.java
 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/component/ComponentRestartJob.java
index 820ff6fb..769f7b48 100644
--- 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/component/ComponentRestartJob.java
+++ 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/component/ComponentRestartJob.java
@@ -18,7 +18,13 @@
  */
 package org.apache.bigtop.manager.server.command.job.component;
 
+import org.apache.bigtop.manager.common.enums.Command;
+import org.apache.bigtop.manager.server.command.helper.ComponentStageHelper;
 import org.apache.bigtop.manager.server.command.job.JobContext;
+import org.apache.bigtop.manager.server.model.dto.CommandDTO;
+
+import java.util.List;
+import java.util.Map;
 
 public class ComponentRestartJob extends AbstractComponentJob {
 
@@ -28,9 +34,12 @@ public class ComponentRestartJob extends 
AbstractComponentJob {
 
     @Override
     protected void createStages() {
-        super.createStopStages();
+        CommandDTO commandDTO = jobContext.getCommandDTO();
+        Map<String, List<String>> componentHostsMap = getComponentHostsMap();
 
-        super.createStartStages();
+        // Restart services
+        
stages.addAll(ComponentStageHelper.createComponentStages(componentHostsMap, 
Command.STOP, commandDTO));
+        
stages.addAll(ComponentStageHelper.createComponentStages(componentHostsMap, 
Command.START, commandDTO));
     }
 
     @Override
diff --git 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/component/ComponentStartJob.java
 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/component/ComponentStartJob.java
index 94d2c6c3..13212034 100644
--- 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/component/ComponentStartJob.java
+++ 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/component/ComponentStartJob.java
@@ -18,7 +18,12 @@
  */
 package org.apache.bigtop.manager.server.command.job.component;
 
+import org.apache.bigtop.manager.server.command.helper.ComponentStageHelper;
 import org.apache.bigtop.manager.server.command.job.JobContext;
+import org.apache.bigtop.manager.server.model.dto.CommandDTO;
+
+import java.util.List;
+import java.util.Map;
 
 public class ComponentStartJob extends AbstractComponentJob {
 
@@ -28,7 +33,10 @@ public class ComponentStartJob extends AbstractComponentJob {
 
     @Override
     protected void createStages() {
-        super.createStartStages();
+        CommandDTO commandDTO = jobContext.getCommandDTO();
+        Map<String, List<String>> componentHostsMap = getComponentHostsMap();
+
+        
stages.addAll(ComponentStageHelper.createComponentStages(componentHostsMap, 
commandDTO));
     }
 
     @Override
diff --git 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/component/ComponentStopJob.java
 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/component/ComponentStopJob.java
index cef74f65..20c66b9b 100644
--- 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/component/ComponentStopJob.java
+++ 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/component/ComponentStopJob.java
@@ -18,7 +18,12 @@
  */
 package org.apache.bigtop.manager.server.command.job.component;
 
+import org.apache.bigtop.manager.server.command.helper.ComponentStageHelper;
 import org.apache.bigtop.manager.server.command.job.JobContext;
+import org.apache.bigtop.manager.server.model.dto.CommandDTO;
+
+import java.util.List;
+import java.util.Map;
 
 public class ComponentStopJob extends AbstractComponentJob {
 
@@ -28,7 +33,10 @@ public class ComponentStopJob extends AbstractComponentJob {
 
     @Override
     protected void createStages() {
-        super.createStopStages();
+        CommandDTO commandDTO = jobContext.getCommandDTO();
+        Map<String, List<String>> componentHostsMap = getComponentHostsMap();
+
+        
stages.addAll(ComponentStageHelper.createComponentStages(componentHostsMap, 
commandDTO));
     }
 
     @Override
diff --git 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/host/AbstractHostJob.java
 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/host/AbstractHostJob.java
index d1af00f0..7135efc0 100644
--- 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/host/AbstractHostJob.java
+++ 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/host/AbstractHostJob.java
@@ -18,25 +18,17 @@
  */
 package org.apache.bigtop.manager.server.command.job.host;
 
-import org.apache.bigtop.manager.common.enums.Command;
 import org.apache.bigtop.manager.dao.po.ComponentPO;
 import org.apache.bigtop.manager.dao.query.ComponentQuery;
 import org.apache.bigtop.manager.dao.repository.ComponentDao;
 import org.apache.bigtop.manager.server.command.job.AbstractJob;
 import org.apache.bigtop.manager.server.command.job.JobContext;
-import org.apache.bigtop.manager.server.command.stage.ComponentStartStage;
-import org.apache.bigtop.manager.server.command.stage.ComponentStopStage;
-import org.apache.bigtop.manager.server.command.stage.StageContext;
 import org.apache.bigtop.manager.server.holder.SpringContextHolder;
-import org.apache.bigtop.manager.server.model.dto.ComponentDTO;
-import org.apache.bigtop.manager.server.model.dto.ServiceDTO;
-import org.apache.bigtop.manager.server.utils.StackDAGUtils;
-import org.apache.bigtop.manager.server.utils.StackUtils;
-
-import org.apache.commons.collections4.CollectionUtils;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 public abstract class AbstractHostJob extends AbstractJob {
 
@@ -58,77 +50,20 @@ public abstract class AbstractHostJob extends AbstractJob {
         super.beforeCreateStages();
     }
 
-    protected StageContext createStageContext(String componentName, 
List<String> hostnames) {
-        StageContext stageContext = 
StageContext.fromCommandDTO(jobContext.getCommandDTO());
-
-        ServiceDTO serviceDTO = 
StackUtils.getServiceDTOByComponentName(componentName);
-        ComponentDTO componentDTO = StackUtils.getComponentDTO(componentName);
-
-        stageContext.setHostnames(hostnames);
-        stageContext.setServiceDTO(serviceDTO);
-        stageContext.setComponentDTO(componentDTO);
-
-        return stageContext;
-    }
-
-    protected void createStartStages() {
-        List<ComponentPO> componentPOList = getComponentPOList();
-        List<String> todoList = 
StackDAGUtils.getTodoList(getComponentNames(componentPOList), Command.START);
-
-        for (String componentCommand : todoList) {
-            String[] split = componentCommand.split("-");
-            String componentName = split[0];
-
-            if (StackUtils.isClientComponent(componentName)) {
-                continue;
-            }
-
-            List<String> hostnames = getHostnames();
-            if (CollectionUtils.isEmpty(hostnames)) {
-                continue;
-            }
-
-            StageContext stageContext = createStageContext(componentName, 
hostnames);
-            stages.add(new ComponentStartStage(stageContext));
-        }
-    }
-
-    protected void createStopStages() {
-        List<ComponentPO> componentPOList = getComponentPOList();
-        List<String> todoList = 
StackDAGUtils.getTodoList(getComponentNames(componentPOList), Command.STOP);
-
-        for (String componentCommand : todoList) {
-            String[] split = componentCommand.split("-");
-            String componentName = split[0];
-
-            if (StackUtils.isClientComponent(componentName)) {
-                continue;
-            }
-
-            List<String> hostnames = getHostnames();
-            if (CollectionUtils.isEmpty(hostnames)) {
-                continue;
-            }
-
-            StageContext stageContext = createStageContext(componentName, 
hostnames);
-            stages.add(new ComponentStopStage(stageContext));
-        }
-    }
-
-    private List<ComponentPO> getComponentPOList() {
-        ComponentQuery query = ComponentQuery.builder()
+    protected Map<String, List<String>> getComponentHostsMap() {
+        List<String> hostnames = getHostnames();
+        ComponentQuery componentQuery = ComponentQuery.builder()
                 .clusterId(clusterPO.getId())
-                .hostnames(getHostnames())
+                .hostnames(hostnames)
                 .build();
-        return componentDao.findByQuery(query);
-    }
-
-    private List<String> getComponentNames(List<ComponentPO> componentPOList) {
-        if (componentPOList == null) {
-            return new ArrayList<>();
-        } else {
-            return 
componentPOList.stream().map(ComponentPO::getName).distinct().toList();
+        List<ComponentPO> componentPOList = 
componentDao.findByQuery(componentQuery);
+        Map<String, List<String>> componentHostsMap = new HashMap<>();
+        for (ComponentPO componentPO : componentPOList) {
+            List<String> hosts = 
componentHostsMap.computeIfAbsent(componentPO.getName(), k -> new 
ArrayList<>());
+            hosts.add(componentPO.getHostname());
         }
+
+        return componentHostsMap;
     }
 
     private List<String> getHostnames() {
diff --git 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/host/HostRestartJob.java
 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/host/HostRestartJob.java
index 9bc0b337..c8453748 100644
--- 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/host/HostRestartJob.java
+++ 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/host/HostRestartJob.java
@@ -18,7 +18,13 @@
  */
 package org.apache.bigtop.manager.server.command.job.host;
 
+import org.apache.bigtop.manager.common.enums.Command;
+import org.apache.bigtop.manager.server.command.helper.ComponentStageHelper;
 import org.apache.bigtop.manager.server.command.job.JobContext;
+import org.apache.bigtop.manager.server.model.dto.CommandDTO;
+
+import java.util.List;
+import java.util.Map;
 
 public class HostRestartJob extends AbstractHostJob {
 
@@ -28,9 +34,12 @@ public class HostRestartJob extends AbstractHostJob {
 
     @Override
     protected void createStages() {
-        super.createStopStages();
+        CommandDTO commandDTO = jobContext.getCommandDTO();
+        Map<String, List<String>> componentHostsMap = getComponentHostsMap();
 
-        super.createStartStages();
+        // Restart services
+        
stages.addAll(ComponentStageHelper.createComponentStages(componentHostsMap, 
Command.STOP, commandDTO));
+        
stages.addAll(ComponentStageHelper.createComponentStages(componentHostsMap, 
Command.START, commandDTO));
     }
 
     @Override
diff --git 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/host/HostStartJob.java
 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/host/HostStartJob.java
index 80c2c85a..8a4563e7 100644
--- 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/host/HostStartJob.java
+++ 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/host/HostStartJob.java
@@ -18,7 +18,12 @@
  */
 package org.apache.bigtop.manager.server.command.job.host;
 
+import org.apache.bigtop.manager.server.command.helper.ComponentStageHelper;
 import org.apache.bigtop.manager.server.command.job.JobContext;
+import org.apache.bigtop.manager.server.model.dto.CommandDTO;
+
+import java.util.List;
+import java.util.Map;
 
 public class HostStartJob extends AbstractHostJob {
 
@@ -28,7 +33,10 @@ public class HostStartJob extends AbstractHostJob {
 
     @Override
     protected void createStages() {
-        super.createStartStages();
+        CommandDTO commandDTO = jobContext.getCommandDTO();
+        Map<String, List<String>> componentHostsMap = getComponentHostsMap();
+
+        
stages.addAll(ComponentStageHelper.createComponentStages(componentHostsMap, 
commandDTO));
     }
 
     @Override
diff --git 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/host/HostStopJob.java
 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/host/HostStopJob.java
index 2ab781ba..198a8e52 100644
--- 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/host/HostStopJob.java
+++ 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/host/HostStopJob.java
@@ -18,7 +18,12 @@
  */
 package org.apache.bigtop.manager.server.command.job.host;
 
+import org.apache.bigtop.manager.server.command.helper.ComponentStageHelper;
 import org.apache.bigtop.manager.server.command.job.JobContext;
+import org.apache.bigtop.manager.server.model.dto.CommandDTO;
+
+import java.util.List;
+import java.util.Map;
 
 public class HostStopJob extends AbstractHostJob {
 
@@ -28,7 +33,10 @@ public class HostStopJob extends AbstractHostJob {
 
     @Override
     protected void createStages() {
-        super.createStopStages();
+        CommandDTO commandDTO = jobContext.getCommandDTO();
+        Map<String, List<String>> componentHostsMap = getComponentHostsMap();
+
+        
stages.addAll(ComponentStageHelper.createComponentStages(componentHostsMap, 
commandDTO));
     }
 
     @Override
diff --git 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/service/AbstractServiceJob.java
 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/service/AbstractServiceJob.java
index b47292ac..d32400b9 100644
--- 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/service/AbstractServiceJob.java
+++ 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/service/AbstractServiceJob.java
@@ -18,7 +18,6 @@
  */
 package org.apache.bigtop.manager.server.command.job.service;
 
-import org.apache.bigtop.manager.common.enums.Command;
 import org.apache.bigtop.manager.dao.po.ComponentPO;
 import org.apache.bigtop.manager.dao.query.ComponentQuery;
 import org.apache.bigtop.manager.dao.repository.ComponentDao;
@@ -28,25 +27,13 @@ import 
org.apache.bigtop.manager.dao.repository.ServiceConfigSnapshotDao;
 import org.apache.bigtop.manager.dao.repository.ServiceDao;
 import org.apache.bigtop.manager.server.command.job.AbstractJob;
 import org.apache.bigtop.manager.server.command.job.JobContext;
-import org.apache.bigtop.manager.server.command.stage.CacheFileUpdateStage;
-import org.apache.bigtop.manager.server.command.stage.ComponentAddStage;
-import org.apache.bigtop.manager.server.command.stage.ComponentCheckStage;
-import org.apache.bigtop.manager.server.command.stage.ComponentConfigureStage;
-import org.apache.bigtop.manager.server.command.stage.ComponentStartStage;
-import org.apache.bigtop.manager.server.command.stage.ComponentStopStage;
-import org.apache.bigtop.manager.server.command.stage.StageContext;
 import org.apache.bigtop.manager.server.holder.SpringContextHolder;
-import org.apache.bigtop.manager.server.model.dto.ComponentDTO;
-import org.apache.bigtop.manager.server.model.dto.ComponentHostDTO;
-import org.apache.bigtop.manager.server.model.dto.ServiceDTO;
 import org.apache.bigtop.manager.server.model.dto.command.ServiceCommandDTO;
-import org.apache.bigtop.manager.server.utils.StackDAGUtils;
-import org.apache.bigtop.manager.server.utils.StackUtils;
-
-import org.apache.commons.collections4.CollectionUtils;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 public abstract class AbstractServiceJob extends AbstractJob {
 
@@ -76,146 +63,20 @@ public abstract class AbstractServiceJob extends 
AbstractJob {
         super.beforeCreateStages();
     }
 
-    protected StageContext createStageContext(String serviceName, String 
componentName, List<String> hostnames) {
-        StageContext stageContext = 
StageContext.fromCommandDTO(jobContext.getCommandDTO());
-
-        ServiceDTO serviceDTO = StackUtils.getServiceDTO(serviceName);
-        ComponentDTO componentDTO = StackUtils.getComponentDTO(componentName);
-
-        stageContext.setHostnames(hostnames);
-        stageContext.setServiceDTO(serviceDTO);
-        stageContext.setComponentDTO(componentDTO);
-
-        return stageContext;
-    }
-
-    protected List<String> getComponentNames() {
+    protected Map<String, List<String>> getComponentHostsMap() {
         List<String> serviceNames = getServiceNames();
         ComponentQuery componentQuery = ComponentQuery.builder()
                 .clusterId(clusterPO.getId())
                 .serviceNames(serviceNames)
                 .build();
         List<ComponentPO> componentPOList = 
componentDao.findByQuery(componentQuery);
-
-        return 
componentPOList.stream().map(ComponentPO::getName).distinct().toList();
-    }
-
-    protected String findServiceNameByComponentName(String componentName) {
-        return 
StackUtils.getServiceDTOByComponentName(componentName).getName();
-    }
-
-    protected List<String> findHostnamesByComponentName(String componentName) {
-        ComponentQuery componentQuery = ComponentQuery.builder()
-                .clusterId(clusterPO.getId())
-                .name(componentName)
-                .build();
-        List<ComponentPO> componentPOList = 
componentDao.findByQuery(componentQuery);
-        if (componentPOList == null) {
-            return new ArrayList<>();
-        } else {
-            return 
componentPOList.stream().map(ComponentPO::getHostname).toList();
-        }
-    }
-
-    protected void createCacheStage() {
-        StageContext stageContext = 
StageContext.fromCommandDTO(jobContext.getCommandDTO());
-        stages.add(new CacheFileUpdateStage(stageContext));
-    }
-
-    protected void createAddStages() {
-        List<String> todoList = StackDAGUtils.getTodoList(getComponentNames(), 
Command.ADD);
-
-        for (String componentCommand : todoList) {
-            String[] split = componentCommand.split("-");
-            String componentName = split[0];
-            String serviceName = findServiceNameByComponentName(componentName);
-            List<String> hostnames = 
findHostnamesByComponentName(componentName);
-            if (CollectionUtils.isEmpty(hostnames)) {
-                continue;
-            }
-
-            StageContext stageContext = createStageContext(serviceName, 
componentName, hostnames);
-            stages.add(new ComponentAddStage(stageContext));
-        }
-    }
-
-    protected void createConfigureStages() {
-        for (ServiceCommandDTO serviceCommand : 
jobContext.getCommandDTO().getServiceCommands()) {
-            for (ComponentHostDTO componentHost : 
serviceCommand.getComponentHosts()) {
-                String serviceName = serviceCommand.getServiceName();
-                String componentName = componentHost.getComponentName();
-                List<String> hostnames = componentHost.getHostnames();
-
-                StageContext stageContext = createStageContext(serviceName, 
componentName, hostnames);
-                stages.add(new ComponentConfigureStage(stageContext));
-            }
-        }
-    }
-
-    protected void createStartStages() {
-        List<String> todoList = StackDAGUtils.getTodoList(getComponentNames(), 
Command.START);
-
-        for (String componentCommand : todoList) {
-            String[] split = componentCommand.split("-");
-            String componentName = split[0];
-            String serviceName = findServiceNameByComponentName(componentName);
-
-            if (StackUtils.isClientComponent(componentName)) {
-                continue;
-            }
-
-            List<String> hostnames = 
findHostnamesByComponentName(componentName);
-            if (CollectionUtils.isEmpty(hostnames)) {
-                continue;
-            }
-
-            StageContext stageContext = createStageContext(serviceName, 
componentName, hostnames);
-            stages.add(new ComponentStartStage(stageContext));
+        Map<String, List<String>> componentHostsMap = new HashMap<>();
+        for (ComponentPO componentPO : componentPOList) {
+            List<String> hosts = 
componentHostsMap.computeIfAbsent(componentPO.getName(), k -> new 
ArrayList<>());
+            hosts.add(componentPO.getHostname());
         }
-    }
-
-    protected void createStopStages() {
-        List<String> todoList = StackDAGUtils.getTodoList(getComponentNames(), 
Command.STOP);
 
-        for (String componentCommand : todoList) {
-            String[] split = componentCommand.split("-");
-            String componentName = split[0];
-            String serviceName = findServiceNameByComponentName(componentName);
-
-            if (StackUtils.isClientComponent(componentName)) {
-                continue;
-            }
-
-            List<String> hostnames = 
findHostnamesByComponentName(componentName);
-            if (CollectionUtils.isEmpty(hostnames)) {
-                continue;
-            }
-
-            StageContext stageContext = createStageContext(serviceName, 
componentName, hostnames);
-            stages.add(new ComponentStopStage(stageContext));
-        }
-    }
-
-    protected void createCheckStages() {
-        List<String> todoList = StackDAGUtils.getTodoList(getComponentNames(), 
Command.CHECK);
-
-        for (String componentCommand : todoList) {
-            String[] split = componentCommand.split("-");
-            String componentName = split[0];
-            String serviceName = findServiceNameByComponentName(componentName);
-
-            if (StackUtils.isClientComponent(componentName)) {
-                continue;
-            }
-
-            List<String> hostnames = 
findHostnamesByComponentName(componentName);
-            if (CollectionUtils.isEmpty(hostnames)) {
-                continue;
-            }
-
-            StageContext stageContext = createStageContext(serviceName, 
componentName, List.of(hostnames.get(0)));
-            stages.add(new ComponentCheckStage(stageContext));
-        }
+        return componentHostsMap;
     }
 
     private List<String> getServiceNames() {
diff --git 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/service/ServiceAddJob.java
 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/service/ServiceAddJob.java
index 35553ebd..690f3542 100644
--- 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/service/ServiceAddJob.java
+++ 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/service/ServiceAddJob.java
@@ -18,12 +18,14 @@
  */
 package org.apache.bigtop.manager.server.command.job.service;
 
+import org.apache.bigtop.manager.common.enums.Command;
 import org.apache.bigtop.manager.common.utils.JsonUtils;
 import org.apache.bigtop.manager.dao.po.ComponentPO;
 import org.apache.bigtop.manager.dao.po.HostPO;
 import org.apache.bigtop.manager.dao.po.ServiceConfigPO;
 import org.apache.bigtop.manager.dao.po.ServiceConfigSnapshotPO;
 import org.apache.bigtop.manager.dao.po.ServicePO;
+import org.apache.bigtop.manager.server.command.helper.ComponentStageHelper;
 import org.apache.bigtop.manager.server.command.job.JobContext;
 import org.apache.bigtop.manager.server.enums.HealthyStatusEnum;
 import org.apache.bigtop.manager.server.model.converter.ComponentConverter;
@@ -59,45 +61,41 @@ public class ServiceAddJob extends AbstractServiceJob {
         // Update cache files
         super.createCacheStage();
 
+        CommandDTO commandDTO = jobContext.getCommandDTO();
+        Map<String, List<String>> componentHostsMap = getComponentHostsMap();
+
         // Install components
-        super.createAddStages();
+        
stages.addAll(ComponentStageHelper.createComponentStages(componentHostsMap, 
Command.ADD, commandDTO));
 
-        // Configure services
-        super.createConfigureStages();
+        // Configure components
+        
stages.addAll(ComponentStageHelper.createComponentStages(componentHostsMap, 
Command.CONFIGURE, commandDTO));
 
-        // Start all master components
-        super.createStartStages();
+        // Init/Start/Prepare components
+        // Since the order of these stages might be mixed up, we need to sort 
and add them together.
+        // For example, the order usually is init -> start -> prepare, but 
Hive Metastore init requires MySQL Server to
+        // be prepared.
+        List<Command> commands = List.of(Command.INIT, Command.START, 
Command.PREPARE);
+        
stages.addAll(ComponentStageHelper.createComponentStages(componentHostsMap, 
commands, commandDTO));
 
         // Check all master components after started
-        super.createCheckStages();
+        
stages.addAll(ComponentStageHelper.createComponentStages(componentHostsMap, 
Command.CHECK, commandDTO));
     }
 
     @Override
-    protected List<String> getComponentNames() {
-        List<String> componentNames = new ArrayList<>();
-        for (ServiceCommandDTO serviceCommand : 
jobContext.getCommandDTO().getServiceCommands()) {
-            List<ComponentHostDTO> componentHosts = 
serviceCommand.getComponentHosts();
-            for (ComponentHostDTO componentHost : componentHosts) {
-                String componentName = componentHost.getComponentName();
-                componentNames.add(componentName);
-            }
-        }
-
-        return componentNames;
-    }
-
-    @Override
-    protected List<String> findHostnamesByComponentName(String componentName) {
-        for (ServiceCommandDTO serviceCommand : 
jobContext.getCommandDTO().getServiceCommands()) {
-            List<ComponentHostDTO> componentHosts = 
serviceCommand.getComponentHosts();
-            for (ComponentHostDTO componentHost : componentHosts) {
-                if (componentHost.getComponentName().equals(componentName)) {
-                    return componentHost.getHostnames();
-                }
-            }
-        }
-
-        return new ArrayList<>();
+    protected Map<String, List<String>> getComponentHostsMap() {
+        Map<String, List<String>> componentHostsMap = new HashMap<>();
+
+        jobContext.getCommandDTO().getServiceCommands().stream()
+                .map(ServiceCommandDTO::getComponentHosts)
+                .forEach(componentHosts -> {
+                    for (ComponentHostDTO componentHost : componentHosts) {
+                        String componentName = 
componentHost.getComponentName();
+                        List<String> hostnames = componentHost.getHostnames();
+                        componentHostsMap.put(componentName, hostnames);
+                    }
+                });
+
+        return componentHostsMap;
     }
 
     @Override
@@ -144,7 +142,7 @@ public class ServiceAddJob extends AbstractServiceJob {
         Long clusterId = commandDTO.getClusterId();
         String serviceName = serviceCommand.getServiceName();
 
-        // 1. Persist service
+        // Persist services
         StackDTO stackDTO = StackUtils.getServiceStack(serviceName);
         ServiceDTO serviceDTO = StackUtils.getServiceDTO(serviceName);
         ServicePO servicePO = ServiceConverter.INSTANCE.fromDTO2PO(serviceDTO);
@@ -153,7 +151,7 @@ public class ServiceAddJob extends AbstractServiceJob {
         servicePO.setStatus(HealthyStatusEnum.UNHEALTHY.getCode());
         serviceDao.save(servicePO);
 
-        // 2. Persist components
+        // Persist components
         List<ComponentPO> componentPOList = new ArrayList<>();
         for (ComponentHostDTO componentHostDTO : 
serviceCommand.getComponentHosts()) {
             String componentName = componentHostDTO.getComponentName();
@@ -172,7 +170,7 @@ public class ServiceAddJob extends AbstractServiceJob {
 
         componentDao.saveAll(componentPOList);
 
-        // 3. Persist current configs
+        // Persist current configs
         Map<String, String> confMap = new HashMap<>();
         List<ServiceConfigDTO> configs = serviceCommand.getConfigs();
         List<ServiceConfigPO> serviceConfigPOList = 
ServiceConfigConverter.INSTANCE.fromDTO2PO(configs);
@@ -184,7 +182,7 @@ public class ServiceAddJob extends AbstractServiceJob {
 
         serviceConfigDao.saveAll(serviceConfigPOList);
 
-        // 4. Create initial config snapshot
+        // Create initial config snapshot
         ServiceConfigSnapshotPO serviceConfigSnapshotPO = new 
ServiceConfigSnapshotPO();
         serviceConfigSnapshotPO.setName("initial");
         serviceConfigSnapshotPO.setDesc("Initial config snapshot");
diff --git 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/service/ServiceCheckJob.java
 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/service/ServiceCheckJob.java
index 7f3bc192..b0bc2885 100644
--- 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/service/ServiceCheckJob.java
+++ 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/service/ServiceCheckJob.java
@@ -19,12 +19,14 @@
 package org.apache.bigtop.manager.server.command.job.service;
 
 import org.apache.bigtop.manager.dao.po.ServicePO;
+import org.apache.bigtop.manager.server.command.helper.ComponentStageHelper;
 import org.apache.bigtop.manager.server.command.job.JobContext;
 import org.apache.bigtop.manager.server.enums.HealthyStatusEnum;
 import org.apache.bigtop.manager.server.model.dto.CommandDTO;
 import org.apache.bigtop.manager.server.model.dto.command.ServiceCommandDTO;
 
 import java.util.List;
+import java.util.Map;
 
 public class ServiceCheckJob extends AbstractServiceJob {
 
@@ -34,7 +36,10 @@ public class ServiceCheckJob extends AbstractServiceJob {
 
     @Override
     protected void createStages() {
-        super.createCheckStages();
+        CommandDTO commandDTO = jobContext.getCommandDTO();
+        Map<String, List<String>> componentHostsMap = getComponentHostsMap();
+
+        
stages.addAll(ComponentStageHelper.createComponentStages(componentHostsMap, 
commandDTO));
     }
 
     @Override
diff --git 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/service/ServiceConfigureJob.java
 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/service/ServiceConfigureJob.java
index 03fed56e..f6325685 100644
--- 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/service/ServiceConfigureJob.java
+++ 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/service/ServiceConfigureJob.java
@@ -18,7 +18,13 @@
  */
 package org.apache.bigtop.manager.server.command.job.service;
 
+import org.apache.bigtop.manager.common.enums.Command;
+import org.apache.bigtop.manager.server.command.helper.ComponentStageHelper;
 import org.apache.bigtop.manager.server.command.job.JobContext;
+import org.apache.bigtop.manager.server.model.dto.CommandDTO;
+
+import java.util.List;
+import java.util.Map;
 
 public class ServiceConfigureJob extends AbstractServiceJob {
 
@@ -31,12 +37,14 @@ public class ServiceConfigureJob extends AbstractServiceJob 
{
         // Update cache files
         super.createCacheStage();
 
-        // Configure services
-        super.createConfigureStages();
+        CommandDTO commandDTO = jobContext.getCommandDTO();
+        Map<String, List<String>> componentHostsMap = getComponentHostsMap();
+
+        
stages.addAll(ComponentStageHelper.createComponentStages(componentHostsMap, 
Command.CONFIGURE, commandDTO));
 
         // Restart services
-        super.createStopStages();
-        super.createStartStages();
+        
stages.addAll(ComponentStageHelper.createComponentStages(componentHostsMap, 
Command.STOP, commandDTO));
+        
stages.addAll(ComponentStageHelper.createComponentStages(componentHostsMap, 
Command.START, commandDTO));
     }
 
     @Override
diff --git 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/service/ServiceRestartJob.java
 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/service/ServiceRestartJob.java
index 1124e865..e32e36d8 100644
--- 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/service/ServiceRestartJob.java
+++ 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/service/ServiceRestartJob.java
@@ -18,13 +18,16 @@
  */
 package org.apache.bigtop.manager.server.command.job.service;
 
+import org.apache.bigtop.manager.common.enums.Command;
 import org.apache.bigtop.manager.dao.po.ServicePO;
+import org.apache.bigtop.manager.server.command.helper.ComponentStageHelper;
 import org.apache.bigtop.manager.server.command.job.JobContext;
 import org.apache.bigtop.manager.server.enums.HealthyStatusEnum;
 import org.apache.bigtop.manager.server.model.dto.CommandDTO;
 import org.apache.bigtop.manager.server.model.dto.command.ServiceCommandDTO;
 
 import java.util.List;
+import java.util.Map;
 
 public class ServiceRestartJob extends AbstractServiceJob {
 
@@ -34,9 +37,12 @@ public class ServiceRestartJob extends AbstractServiceJob {
 
     @Override
     protected void createStages() {
-        super.createStopStages();
+        CommandDTO commandDTO = jobContext.getCommandDTO();
+        Map<String, List<String>> componentHostsMap = getComponentHostsMap();
 
-        super.createStartStages();
+        // Restart services
+        
stages.addAll(ComponentStageHelper.createComponentStages(componentHostsMap, 
Command.STOP, commandDTO));
+        
stages.addAll(ComponentStageHelper.createComponentStages(componentHostsMap, 
Command.START, commandDTO));
     }
 
     @Override
diff --git 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/service/ServiceStartJob.java
 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/service/ServiceStartJob.java
index 06d8f9bc..b4bb236a 100644
--- 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/service/ServiceStartJob.java
+++ 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/service/ServiceStartJob.java
@@ -19,12 +19,14 @@
 package org.apache.bigtop.manager.server.command.job.service;
 
 import org.apache.bigtop.manager.dao.po.ServicePO;
+import org.apache.bigtop.manager.server.command.helper.ComponentStageHelper;
 import org.apache.bigtop.manager.server.command.job.JobContext;
 import org.apache.bigtop.manager.server.enums.HealthyStatusEnum;
 import org.apache.bigtop.manager.server.model.dto.CommandDTO;
 import org.apache.bigtop.manager.server.model.dto.command.ServiceCommandDTO;
 
 import java.util.List;
+import java.util.Map;
 
 public class ServiceStartJob extends AbstractServiceJob {
 
@@ -34,7 +36,10 @@ public class ServiceStartJob extends AbstractServiceJob {
 
     @Override
     protected void createStages() {
-        super.createStartStages();
+        CommandDTO commandDTO = jobContext.getCommandDTO();
+        Map<String, List<String>> componentHostsMap = getComponentHostsMap();
+
+        
stages.addAll(ComponentStageHelper.createComponentStages(componentHostsMap, 
commandDTO));
     }
 
     @Override
diff --git 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/service/ServiceStopJob.java
 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/service/ServiceStopJob.java
index bb1296b9..ff45c5d3 100644
--- 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/service/ServiceStopJob.java
+++ 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/service/ServiceStopJob.java
@@ -19,12 +19,14 @@
 package org.apache.bigtop.manager.server.command.job.service;
 
 import org.apache.bigtop.manager.dao.po.ServicePO;
+import org.apache.bigtop.manager.server.command.helper.ComponentStageHelper;
 import org.apache.bigtop.manager.server.command.job.JobContext;
 import org.apache.bigtop.manager.server.enums.HealthyStatusEnum;
 import org.apache.bigtop.manager.server.model.dto.CommandDTO;
 import org.apache.bigtop.manager.server.model.dto.command.ServiceCommandDTO;
 
 import java.util.List;
+import java.util.Map;
 
 public class ServiceStopJob extends AbstractServiceJob {
 
@@ -34,7 +36,10 @@ public class ServiceStopJob extends AbstractServiceJob {
 
     @Override
     protected void createStages() {
-        super.createStopStages();
+        CommandDTO commandDTO = jobContext.getCommandDTO();
+        Map<String, List<String>> componentHostsMap = getComponentHostsMap();
+
+        
stages.addAll(ComponentStageHelper.createComponentStages(componentHostsMap, 
commandDTO));
     }
 
     @Override
diff --git 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/component/ComponentRestartJob.java
 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/ComponentInitStage.java
similarity index 62%
copy from 
bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/component/ComponentRestartJob.java
copy to 
bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/ComponentInitStage.java
index 820ff6fb..2cc48652 100644
--- 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/component/ComponentRestartJob.java
+++ 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/ComponentInitStage.java
@@ -16,25 +16,24 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.bigtop.manager.server.command.job.component;
+package org.apache.bigtop.manager.server.command.stage;
 
-import org.apache.bigtop.manager.server.command.job.JobContext;
+import org.apache.bigtop.manager.server.command.task.ComponentInitTask;
+import org.apache.bigtop.manager.server.command.task.Task;
 
-public class ComponentRestartJob extends AbstractComponentJob {
+public class ComponentInitStage extends AbstractComponentStage {
 
-    public ComponentRestartJob(JobContext jobContext) {
-        super(jobContext);
+    public ComponentInitStage(StageContext stageContext) {
+        super(stageContext);
     }
 
     @Override
-    protected void createStages() {
-        super.createStopStages();
-
-        super.createStartStages();
+    protected Task createTask(String hostname) {
+        return new ComponentInitTask(createTaskContext(hostname));
     }
 
     @Override
     public String getName() {
-        return "Restart components";
+        return "Init " + stageContext.getComponentDTO().getDisplayName();
     }
 }
diff --git 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/component/ComponentRestartJob.java
 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/ComponentPrepareStage.java
similarity index 62%
copy from 
bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/component/ComponentRestartJob.java
copy to 
bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/ComponentPrepareStage.java
index 820ff6fb..3b91dc8b 100644
--- 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/component/ComponentRestartJob.java
+++ 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/stage/ComponentPrepareStage.java
@@ -16,25 +16,24 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.bigtop.manager.server.command.job.component;
+package org.apache.bigtop.manager.server.command.stage;
 
-import org.apache.bigtop.manager.server.command.job.JobContext;
+import org.apache.bigtop.manager.server.command.task.ComponentPrepareTask;
+import org.apache.bigtop.manager.server.command.task.Task;
 
-public class ComponentRestartJob extends AbstractComponentJob {
+public class ComponentPrepareStage extends AbstractComponentStage {
 
-    public ComponentRestartJob(JobContext jobContext) {
-        super(jobContext);
+    public ComponentPrepareStage(StageContext stageContext) {
+        super(stageContext);
     }
 
     @Override
-    protected void createStages() {
-        super.createStopStages();
-
-        super.createStartStages();
+    protected Task createTask(String hostname) {
+        return new ComponentPrepareTask(createTaskContext(hostname));
     }
 
     @Override
     public String getName() {
-        return "Restart components";
+        return "Prepare " + stageContext.getComponentDTO().getDisplayName();
     }
 }
diff --git 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/component/ComponentRestartJob.java
 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/task/ComponentInitTask.java
similarity index 67%
copy from 
bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/component/ComponentRestartJob.java
copy to 
bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/task/ComponentInitTask.java
index 820ff6fb..72d8c686 100644
--- 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/component/ComponentRestartJob.java
+++ 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/task/ComponentInitTask.java
@@ -16,25 +16,23 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.bigtop.manager.server.command.job.component;
+package org.apache.bigtop.manager.server.command.task;
 
-import org.apache.bigtop.manager.server.command.job.JobContext;
+import org.apache.bigtop.manager.common.enums.Command;
 
-public class ComponentRestartJob extends AbstractComponentJob {
+public class ComponentInitTask extends AbstractComponentTask {
 
-    public ComponentRestartJob(JobContext jobContext) {
-        super(jobContext);
+    public ComponentInitTask(TaskContext taskContext) {
+        super(taskContext);
     }
 
     @Override
-    protected void createStages() {
-        super.createStopStages();
-
-        super.createStartStages();
+    protected Command getCommand() {
+        return Command.INIT;
     }
 
     @Override
     public String getName() {
-        return "Restart components";
+        return "Init " + taskContext.getComponentDisplayName() + " on " + 
taskContext.getHostname();
     }
 }
diff --git 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/component/ComponentRestartJob.java
 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/task/ComponentPrepareTask.java
similarity index 67%
copy from 
bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/component/ComponentRestartJob.java
copy to 
bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/task/ComponentPrepareTask.java
index 820ff6fb..418da2c1 100644
--- 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/component/ComponentRestartJob.java
+++ 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/task/ComponentPrepareTask.java
@@ -16,25 +16,23 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.bigtop.manager.server.command.job.component;
+package org.apache.bigtop.manager.server.command.task;
 
-import org.apache.bigtop.manager.server.command.job.JobContext;
+import org.apache.bigtop.manager.common.enums.Command;
 
-public class ComponentRestartJob extends AbstractComponentJob {
+public class ComponentPrepareTask extends AbstractComponentTask {
 
-    public ComponentRestartJob(JobContext jobContext) {
-        super(jobContext);
+    public ComponentPrepareTask(TaskContext taskContext) {
+        super(taskContext);
     }
 
     @Override
-    protected void createStages() {
-        super.createStopStages();
-
-        super.createStartStages();
+    protected Command getCommand() {
+        return Command.PREPARE;
     }
 
     @Override
     public String getName() {
-        return "Restart components";
+        return "Prepare " + taskContext.getComponentDisplayName() + " on " + 
taskContext.getHostname();
     }
 }
diff --git 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/utils/StackDAGUtils.java
 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/utils/StackDAGUtils.java
deleted file mode 100644
index 994170f2..00000000
--- 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/utils/StackDAGUtils.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * 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
- *
- *    https://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.bigtop.manager.server.utils;
-
-import org.apache.bigtop.manager.common.enums.Command;
-import org.apache.bigtop.manager.server.exception.ServerException;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class StackDAGUtils {
-
-    public static List<String> orderTodoList(List<String> 
componentCommandNames) {
-        try {
-            List<String> orderedList =
-                    StackUtils.DAG.getAllNodesList().isEmpty() ? new 
ArrayList<>() : StackUtils.DAG.topologicalSort();
-
-            // Re-order the commands, since order.json does not contain all 
commands,
-            // only contains which has dependencies, we need to add the rest 
to the end.
-            orderedList.retainAll(componentCommandNames);
-            componentCommandNames.removeAll(orderedList);
-            orderedList.addAll(componentCommandNames);
-
-            return orderedList;
-        } catch (Exception e) {
-            throw new ServerException(e);
-        }
-    }
-
-    public static List<String> getTodoList(List<String> componentNames, 
Command command) {
-        try {
-            List<String> orderedList =
-                    StackUtils.DAG.getAllNodesList().isEmpty() ? new 
ArrayList<>() : StackUtils.DAG.topologicalSort();
-            List<String> componentCommandNames = new 
ArrayList<>(componentNames.stream()
-                    .map(x -> x + "-" + command.name().toUpperCase())
-                    .toList());
-
-            // Re-order the commands, since order.json does not contain all 
commands,
-            // only contains which has dependencies, we need to add the rest 
to the end.
-            orderedList.retainAll(componentCommandNames);
-            componentCommandNames.removeAll(orderedList);
-            orderedList.addAll(componentCommandNames);
-
-            return orderedList;
-        } catch (Exception e) {
-            throw new ServerException(e);
-        }
-    }
-}
diff --git 
a/bigtop-manager-server/src/main/resources/stacks/bigtop/3.3.0/services/hive/order.json
 
b/bigtop-manager-server/src/main/resources/stacks/bigtop/3.3.0/services/hive/order.json
index e5b220ce..e15e27e8 100644
--- 
a/bigtop-manager-server/src/main/resources/stacks/bigtop/3.3.0/services/hive/order.json
+++ 
b/bigtop-manager-server/src/main/resources/stacks/bigtop/3.3.0/services/hive/order.json
@@ -1,6 +1,8 @@
 {
+  "HIVE_METASTORE-INIT": [
+    "MYSQL_SERVER-PREPARE"
+  ],
   "HIVE_METASTORE-START": [
-    "MYSQL_SERVER-START",
     "NAMENODE-START",
     "NODEMANAGER-START"
   ],
diff --git 
a/bigtop-manager-server/src/main/resources/stacks/bigtop/3.3.0/services/kafka/order.json
 
b/bigtop-manager-server/src/main/resources/stacks/bigtop/3.3.0/services/kafka/order.json
index 6591b238..2f55e86d 100644
--- 
a/bigtop-manager-server/src/main/resources/stacks/bigtop/3.3.0/services/kafka/order.json
+++ 
b/bigtop-manager-server/src/main/resources/stacks/bigtop/3.3.0/services/kafka/order.json
@@ -1,7 +1,4 @@
 {
-  "KAFKA_BROKER-ADD": [
-    "ZOOKEEPER_SERVER-ADD"
-  ],
   "KAFKA_BROKER-START": [
     "ZOOKEEPER_SERVER-START"
   ],
diff --git 
a/bigtop-manager-stack/bigtop-manager-stack-bigtop/src/main/java/org/apache/bigtop/manager/stack/bigtop/v3_3_0/hive/HiveMetastoreScript.java
 
b/bigtop-manager-stack/bigtop-manager-stack-bigtop/src/main/java/org/apache/bigtop/manager/stack/bigtop/v3_3_0/hive/HiveMetastoreScript.java
index 181ab29a..7b19663a 100644
--- 
a/bigtop-manager-stack/bigtop-manager-stack-bigtop/src/main/java/org/apache/bigtop/manager/stack/bigtop/v3_3_0/hive/HiveMetastoreScript.java
+++ 
b/bigtop-manager-stack/bigtop-manager-stack-bigtop/src/main/java/org/apache/bigtop/manager/stack/bigtop/v3_3_0/hive/HiveMetastoreScript.java
@@ -48,21 +48,7 @@ public class HiveMetastoreScript extends 
AbstractServerScript {
         Properties properties = new Properties();
         properties.setProperty(PROPERTY_KEY_SKIP_LEVELS, "1");
 
-        ShellResult shellResult = super.add(params, properties);
-
-        // Download mysql jdbc driver
-        RepoInfo repoInfo = LocalSettings.repos().stream()
-                .filter(r -> OSDetection.getArch().equals(r.getArch()) && 
r.getType() == 2)
-                .findFirst()
-                .orElseThrow(() -> new RuntimeException("Cannot find repo for 
os: [" + OSDetection.getOS()
-                        + "] and arch: [" + OSDetection.getArch() + "]"));
-        String mysqlDriver = repoInfo.getBaseUrl() + 
"/mysql-connector-j-8.0.33.jar";
-        TarballDownloader.download(mysqlDriver, params.stackHome());
-        LinuxFileUtils.moveFile(params.stackHome() + 
"/mysql-connector-j-8.0.33.jar", params.serviceHome() + "/lib/");
-        LinuxFileUtils.updateOwner(params.serviceHome() + "/lib", 
params.user(), params.group(), true);
-        LinuxFileUtils.updatePermissions(params.serviceHome() + "/lib", 
Constants.PERMISSION_755, true);
-
-        return shellResult;
+        return super.add(params, properties);
     }
 
     @Override
@@ -70,6 +56,13 @@ public class HiveMetastoreScript extends 
AbstractServerScript {
         return HiveSetup.configure(params);
     }
 
+    @Override
+    public ShellResult init(Params params) {
+        downloadMySQLJdbcDriver(params);
+        initSchema(params);
+        return ShellResult.success();
+    }
+
     @Override
     public ShellResult start(Params params) {
         configure(params);
@@ -119,19 +112,36 @@ public class HiveMetastoreScript extends 
AbstractServerScript {
         return LinuxOSUtils.checkProcess(hiveParams.getHiveMetastorePidFile());
     }
 
-    private void initSchema(Params params) throws Exception {
-        HiveParams hiveParams = (HiveParams) params;
-        String cmd = hiveParams.serviceHome() + "/bin/schematool -validate 
-dbType mysql";
-        ShellResult shellResult = LinuxOSUtils.sudoExecCmd(cmd, 
hiveParams.user());
-        String clusterName = LocalSettings.cluster().getName();
-        if (shellResult.getExitCode() != MessageConstants.SUCCESS_CODE
-                && shellResult.getErrMsg().contains("Table '" + clusterName + 
"_hive.VERSION' doesn't exist")) {
-            // init schema
-            cmd = hiveParams.serviceHome() + "/bin/schematool -initSchema 
-dbType mysql";
-            shellResult = LinuxOSUtils.sudoExecCmd(cmd, hiveParams.user());
-            if (shellResult.getExitCode() != MessageConstants.SUCCESS_CODE) {
-                throw new StackException(shellResult.getErrMsg());
+    private void downloadMySQLJdbcDriver(Params params) {
+        RepoInfo repoInfo = LocalSettings.repos().stream()
+                .filter(r -> OSDetection.getArch().equals(r.getArch()) && 
r.getType() == 2)
+                .findFirst()
+                .orElseThrow(() -> new RuntimeException("Cannot find repo for 
os: [" + OSDetection.getOS()
+                        + "] and arch: [" + OSDetection.getArch() + "]"));
+        String mysqlDriver = repoInfo.getBaseUrl() + 
"/mysql-connector-j-8.0.33.jar";
+        TarballDownloader.download(mysqlDriver, params.stackHome());
+        LinuxFileUtils.moveFile(params.stackHome() + 
"/mysql-connector-j-8.0.33.jar", params.serviceHome() + "/lib/");
+        LinuxFileUtils.updateOwner(params.serviceHome() + "/lib", 
params.user(), params.group(), true);
+        LinuxFileUtils.updatePermissions(params.serviceHome() + "/lib", 
Constants.PERMISSION_755, true);
+    }
+
+    private void initSchema(Params params) {
+        try {
+            HiveParams hiveParams = (HiveParams) params;
+            String cmd = hiveParams.serviceHome() + "/bin/schematool -validate 
-dbType mysql";
+            ShellResult shellResult = LinuxOSUtils.sudoExecCmd(cmd, 
hiveParams.user());
+            String clusterName = LocalSettings.cluster().getName();
+            if (shellResult.getExitCode() != MessageConstants.SUCCESS_CODE
+                    && shellResult.getErrMsg().contains("Table '" + 
clusterName + "_hive.VERSION' doesn't exist")) {
+                // init schema
+                cmd = hiveParams.serviceHome() + "/bin/schematool -initSchema 
-dbType mysql";
+                shellResult = LinuxOSUtils.sudoExecCmd(cmd, hiveParams.user());
+                if (shellResult.getExitCode() != 
MessageConstants.SUCCESS_CODE) {
+                    throw new StackException(shellResult.getErrMsg());
+                }
             }
+        } catch (IOException e) {
+            throw new StackException(e);
         }
     }
 
diff --git 
a/bigtop-manager-stack/bigtop-manager-stack-core/src/main/java/org/apache/bigtop/manager/stack/core/spi/script/AbstractScript.java
 
b/bigtop-manager-stack/bigtop-manager-stack-core/src/main/java/org/apache/bigtop/manager/stack/core/spi/script/AbstractScript.java
index 2bd67de1..8131fa00 100644
--- 
a/bigtop-manager-stack/bigtop-manager-stack-core/src/main/java/org/apache/bigtop/manager/stack/core/spi/script/AbstractScript.java
+++ 
b/bigtop-manager-stack/bigtop-manager-stack-core/src/main/java/org/apache/bigtop/manager/stack/core/spi/script/AbstractScript.java
@@ -68,6 +68,17 @@ public abstract class AbstractScript implements Script {
         return ShellResult.success();
     }
 
+    @Override
+    public ShellResult init(Params params) {
+        return ShellResult.success();
+    }
+
+    @Override
+    public ShellResult prepare(Params params) {
+        return ShellResult.success();
+    }
+
+    @Override
     public ShellResult restart(Params params) {
         ShellResult shellResult = stop(params);
         if (shellResult.getExitCode() != 0) {
diff --git 
a/bigtop-manager-stack/bigtop-manager-stack-core/src/main/java/org/apache/bigtop/manager/stack/core/spi/script/Script.java
 
b/bigtop-manager-stack/bigtop-manager-stack-core/src/main/java/org/apache/bigtop/manager/stack/core/spi/script/Script.java
index 3c95dc82..337814aa 100644
--- 
a/bigtop-manager-stack/bigtop-manager-stack-core/src/main/java/org/apache/bigtop/manager/stack/core/spi/script/Script.java
+++ 
b/bigtop-manager-stack/bigtop-manager-stack-core/src/main/java/org/apache/bigtop/manager/stack/core/spi/script/Script.java
@@ -28,7 +28,7 @@ import org.apache.bigtop.manager.stack.core.spi.param.Params;
 public interface Script extends PrioritySPI {
 
     /**
-     * Install the component.
+     * Install the component, download and extract tarball files.
      *
      * @param params the parameters required for installation
      * @return a ShellResult object containing the result of the installation 
process
@@ -36,13 +36,25 @@ public interface Script extends PrioritySPI {
     ShellResult add(Params params);
 
     /**
-     * Configure the component.
+     * Configure the component, usually only for config files creation.
      *
      * @param params the parameters required for configuration
      * @return a ShellResult object containing the result of the configuration 
process
      */
     ShellResult configure(Params params);
 
+    /**
+     * Initialize the component, run necessary tasks which are required by the 
component <b>before</b> it can be started.
+     * Except for create config files, which is done in {@link 
#configure(Params)}.
+     * This method is used to run tasks like initializing databases, setting 
up initial data, etc.
+     * Like Hive Metastore database initialization.
+     * Should only be run in service/component add job.
+     *
+     * @param params the parameters required for initialize
+     * @return a ShellResult object containing the result of the initialize 
process
+     */
+    ShellResult init(Params params);
+
     /**
      * Start the component.
      *
@@ -51,6 +63,17 @@ public interface Script extends PrioritySPI {
      */
     ShellResult start(Params params);
 
+    /**
+     * Prepare the component, Unlike {@link #configure(Params)} and {@link 
#init(Params)}.
+     * This method is to prepare the environment which are required by cluster 
<b>after</b> component starts.
+     * Like change default root password for MySQL or upload files to HDFS.
+     * Should only be run in service/component add job.
+     *
+     * @param params the parameters required for prepare
+     * @return a ShellResult object containing the result of the prepare 
process
+     */
+    ShellResult prepare(Params params);
+
     /**
      * Stop the component.
      *
@@ -69,7 +92,7 @@ public interface Script extends PrioritySPI {
 
     /**
      * Check the healthy status of the component.
-     * A simple status check which will only check if the process is running
+     * A simple status check which will only check if the process is running.
      * use {@link #check(Params)} to check the real healthy status of the 
component with smoke tests.
      *
      * @param params the parameters required to check the status
diff --git 
a/bigtop-manager-stack/bigtop-manager-stack-infra/src/main/java/org/apache/bigtop/manager/stack/infra/v1_0_0/mysql/MySQLServerScript.java
 
b/bigtop-manager-stack/bigtop-manager-stack-infra/src/main/java/org/apache/bigtop/manager/stack/infra/v1_0_0/mysql/MySQLServerScript.java
index 7cfcdbd7..bff5e436 100644
--- 
a/bigtop-manager-stack/bigtop-manager-stack-infra/src/main/java/org/apache/bigtop/manager/stack/infra/v1_0_0/mysql/MySQLServerScript.java
+++ 
b/bigtop-manager-stack/bigtop-manager-stack-infra/src/main/java/org/apache/bigtop/manager/stack/infra/v1_0_0/mysql/MySQLServerScript.java
@@ -42,35 +42,7 @@ public class MySQLServerScript extends AbstractServerScript {
         Properties properties = new Properties();
         properties.setProperty(PROPERTY_KEY_SKIP_LEVELS, "1");
 
-        super.add(params, properties);
-
-        // Initialize server after added
-        log.info("Initializing MySQL root user");
-        MySQLParams mysqlParams = (MySQLParams) params;
-        String user = params.user();
-        String binDir = params.serviceHome() + "/bin";
-        String password = mysqlParams.getRootPassword();
-        configure(params);
-        runCommand(binDir + "/mysqld --initialize-insecure", user);
-        start(params);
-        runCommand(
-                MessageFormat.format(
-                        "{0}/mysql -u root -e \"ALTER USER 'root'@'localhost' 
IDENTIFIED BY ''{1}'';\"",
-                        binDir, password),
-                user);
-        runCommand(
-                MessageFormat.format(
-                        "{0}/mysql -u root -p''{1}'' -e \"CREATE USER 
''root''@''%'' IDENTIFIED BY ''{1}'';\"",
-                        binDir, password),
-                user);
-        runCommand(
-                MessageFormat.format(
-                        "{0}/mysql -u root -p''{1}'' -e \"GRANT ALL PRIVILEGES 
ON *.* TO ''root''@''%'' WITH GRANT OPTION;\"",
-                        binDir, password),
-                user);
-        stop(params);
-
-        return ShellResult.success();
+        return super.add(params, properties);
     }
 
     @Override
@@ -78,6 +50,14 @@ public class MySQLServerScript extends AbstractServerScript {
         return MySQLSetup.configure(params);
     }
 
+    @Override
+    public ShellResult init(Params params) {
+        String user = params.user();
+        String binDir = params.serviceHome() + "/bin";
+        runCommand(binDir + "/mysqld --initialize-insecure", user);
+        return ShellResult.success();
+    }
+
     @Override
     public ShellResult start(Params params) {
         configure(params);
@@ -106,6 +86,32 @@ public class MySQLServerScript extends AbstractServerScript 
{
         }
     }
 
+    @Override
+    public ShellResult prepare(Params params) {
+        MySQLParams mysqlParams = (MySQLParams) params;
+        String user = params.user();
+        String binDir = params.serviceHome() + "/bin";
+        String password = mysqlParams.getRootPassword();
+        runCommand(
+                MessageFormat.format(
+                        "{0}/mysql -u root -e \"ALTER USER 'root'@'localhost' 
IDENTIFIED BY ''{1}'';\"",
+                        binDir, password),
+                user);
+        runCommand(
+                MessageFormat.format(
+                        "{0}/mysql -u root -p''{1}'' -e \"CREATE USER 
''root''@''%'' IDENTIFIED BY ''{1}'';\"",
+                        binDir, password),
+                user);
+        runCommand(
+                MessageFormat.format(
+                        "{0}/mysql -u root -p''{1}'' -e \"GRANT ALL PRIVILEGES 
ON *.* TO ''root''@''%'' WITH GRANT OPTION;\"",
+                        binDir, password),
+                user);
+        runCommand(
+                MessageFormat.format("{0}/mysql -u root -p''{1}'' -e \"FLUSH 
PRIVILEGES;\"", binDir, password), user);
+        return ShellResult.success();
+    }
+
     @Override
     public ShellResult stop(Params params) {
         MySQLParams mysqlParams = (MySQLParams) params;


Reply via email to