在 debug pacemaker/pcs/pcsd 的时候,我们通常需要知道,敲下 `pcs xxxx xxxx` 命令后,发生了什么动作。
在应用 pcs 进行管理的 pacemaker 集群中,每个节点都会启动一个 pcsd 守护进程,监听 2224/tcp 端口。随后,我们可以从任一节点中,通过 pcs 命令管理整个集群。
误解
按照套路,通常这是一种 client/server 架构, pcs 命令行工具向相应节点的 pcsd 发送请求, pcsd 在相应节点完成动作。
然而实际与此有所出入。
实际套路
实际上,真正对 pacemaker 执行操作的,是 pcs 这个命令行工具。pcsd 负责接收来自其他节点的请求,随之调用本地的 pcs 工具,最后由本地的 pcs 执行操作。
本地命令示例
以 `pcs cluster start` 命令为例。在 Node A 中执行 `pcs cluster start`, Node A 本地的 cluster 相关服务将被启动。
在此操作中,不需要经过 pcsd. 即, pcs ---> execute. 具体过程如下。
1. Node A 的 pcs 脚本被调用。
10 from pcs import app
11
12 app.main(sys.argv[1:])
2. Node A 的 pcs 调起 app.py.
14 from pcs import (
15 acl,
16 cluster,
17 config,
18 constraint,
19 node,
20 pcsd,
21 prop,
22 qdevice,
23 quorum,
24 resource,
25 settings,
26 status,
27 stonith,
28 usage,
29 utils,
30 alert,
31 )
### 找到 cluster 子命令对应的入口,cluster.cluster_cmd.
176 cmd_map = {
177 "resource": resource.resource_cmd,
178 "cluster": cluster.cluster_cmd,
179 "stonith": stonith.stonith_cmd,
180 "property": prop.property_cmd,
181 "constraint": constraint.constraint_cmd,
182 "acl": acl.acl_cmd,
183 "status": status.status_cmd,
184 "config": config.config_cmd,
185 "pcsd": pcsd.pcsd_cmd,
186 "node": node.node_cmd,
187 "quorum": lambda argv: quorum.quorum_cmd(
188 utils.get_library_wrapper(),
189 argv,
190 utils.get_modificators()
191 ),
192 "qdevice": lambda argv: qdevice.qdevice_cmd(
193 utils.get_library_wrapper(),
194 argv,
195 utils.get_modificators()
196 ),
197 "alert": lambda args: alert.alert_cmd(
198 utils.get_library_wrapper(),
199 args,
200 utils.get_modificators()
201 ),
202 }
3. 由于`pcs cluster start`后面没有接节点名或`--all`,所以判断为在本地节点进行操作。
可以看到,这个命令实际会在本地启动 corosync 和 pacemaker 服务。
57 def cluster_cmd(argv):
86 elif (sub_cmd == "start"):
87 if "--all" in utils.pcs_options:
88 start_cluster_all()
89 else:
90 start_cluster(argv)
859 def start_cluster(argv):
860 wait = False
861 wait_timeout = None
862 if "--wait" in utils.pcs_options:
863 wait_timeout = utils.validate_wait_get_timeout(False)
864 wait = True
865
866 if len(argv) > 0: ###### <---------------- For remote node only.
867 start_cluster_nodes(argv)
868 if wait:
869 wait_for_nodes_started(argv, wait_timeout)
870 return
871
872 print("Starting Cluster...")
873 if utils.is_rhel6():
874 # Verify that CMAN_QUORUM_TIMEOUT is set, if not, then we set it to 0
875 retval, output = getstatusoutput('source /etc/sysconfig/cman ; [ -z "$CMAN_QUORUM_TIMEOUT" ]')
876 if retval == 0:
877 with open("/etc/sysconfig/cman", "a") as cman_conf_file:
878 cman_conf_file.write("\nCMAN_QUORUM_TIMEOUT=0\n")
879
880 output, retval = utils.run(["service", "cman","start"])
881 if retval != 0:
882 print(output)
883 utils.err("unable to start cman")
884 else:
885 output, retval = utils.run(["service", "corosync","start"]) #####<------ Work Horse 本地执行操作
886 if retval != 0:
887 print(output)
888 utils.err("unable to start corosync")
889 output, retval = utils.run(["service", "pacemaker", "start"])
890 if retval != 0:
891 print(output)
892 utils.err("unable to start pacemaker")
893 if wait:
894 wait_for_nodes_started([], wait_timeout)
远程命令示例
以`pcs cluster start --all`为例。在 Node A 执行该命令,会启动所有节点的的 cluster 相关服务。
这个命令会向每个节点的 pcsd 发送请求,随后每个节点的 pcsd 调用本地的 pcs 命令执行相应操作。
即, pcs ----> remote psdc ----> remote pcs ---> execute. 具体过程如下。
1. Node A 中执行 `pcs cluster start --all` 命令。由于存在`--all`参数,进入start_cluster_all()分支。
86 elif (sub_cmd == "start"):
87 if "--all" in utils.pcs_options:
88 start_cluster_all()
89 else:
90 start_cluster(argv)
91 elif (sub_cmd == "stop"):
92 if "--all" in utils.pcs_options:
93 stop_cluster_all()
94 else:
95 stop_cluster(argv)
896 def start_cluster_all():
897 wait = False
898 wait_timeout = None
899 if "--wait" in utils.pcs_options:
900 wait_timeout = utils.validate_wait_get_timeout(False)
901 wait = True
902
903 all_nodes = utils.getNodesFromCorosyncConf() ######<------获取所有节点名字
904 start_cluster_nodes(all_nodes) ######<------在所有节点启动cluster
905
906 if wait:
907 wait_for_nodes_started(all_nodes, wait_timeout)
909 def start_cluster_nodes(nodes):
910 error_list = parallel_for_nodes(utils.startCluster, nodes, quiet=True)
911 if error_list:
912 utils.err("unable to start all nodes\n" + "\n".join(error_list))
2. Node A 向各节点的 pcsd 发送 http 请求。
246 def startCluster(node, quiet=False):
247 return sendHTTPRequest(node, 'remote/cluster_start', None, False, not quiet)
346 def sendHTTPRequest(host, request, data = None, printResult = True, printSuccess = True):
347 url = 'https://' + host + ':2224/' + request
3. 各节点(包括A)的 pcsd 接收到请求. 随后在本地执行 `pcs cluster start`. 后面的过程与上述本地的过程一致。
17 def remote(params, request, auth_user)
18 remote_cmd_without_pacemaker = {
39 :cluster_start => method(:cluster_start),
193 def cluster_start(params, request, auth_user)
194 if params[:name]
195 code, response = send_request_with_token(
196 auth_user, params[:name], 'cluster_start', true
197 )
198 else
199 if not allowed_for_local_cluster(auth_user, Permissions::WRITE)
200 return 403, 'Permission denied'
201 end
202 $logger.info "Starting Daemons"
203 output, stderr, retval = run_cmd(auth_user, PCS, 'cluster', 'start') ####<<<<------Call local pcs
204 $logger.debug output
205 if retval != 0
206 return [400, (output + stderr).join]
207 else
208 return output
209 end
210 end
211 end