Orchestrator源码解读 - 如何执行钩子脚本

Oc支持的钩子脚本 

orchestrator支持钩子脚本,即在恢复过程调用的外部脚本。这些是通过 shell 调用的命令数组

  • OnFailureDetectionProcesses  // 故障发现阶段
  • PreGracefulTakeoverProcesses // 计划内切换流程之前执行,在master设置read_only 之前执行
  • PreFailoverProcesses // 自动切换流程之前执行
  • PostMasterFailoverProcesses // 主库切换成功之后
  • PostIntermediateMasterFailoverProcesses
  • PostFailoverProcesses // 自动切换流程之后执行
  • PostUnsuccessfulFailoverProcesses // 切换不成功事
  • PostGracefulTakeoverProcesses // 计划内切换流程之后执行

脚本解释

OnFailureDetectionProcesses                []string          // 检测到故障转移场景时要执行的流程 (在决定是否进行故障转移之前).可以并且应该使用以下一些占位符: {failureType}, {instanceType}, {isMaster}, {isCoMaster}, {failureDescription}, {command}, {failedHost}, {failureCluster}, {failureClusterAlias}, {failureClusterDomain}, {failedPort}, {successorHost}, {successorPort}, {successorAlias}, {countReplicas}, {replicaHosts}, {isDowntimed}, {autoMasterRecovery}, {autoIntermediateMasterRecovery}
PreGracefulTakeoverProcesses               []string          // 在执行 failover 之前执行的流程(如果其中任何一个以非零代码退出,则中止操作;执行顺序未定义)。可以并且应该使用以下一些占位符: {failureType}, {instanceType}, {isMaster}, {isCoMaster}, {failureDescription}, {command}, {failedHost}, {failureCluster}, {failureClusterAlias}, {failureClusterDomain}, {failedPort}, {successorHost}, {successorPort}, {countReplicas}, {replicaHosts}, {isDowntimed}
PreFailoverProcesses                       []string          // 在执行 failover 之前要执行的流程(如果其中任何一个以非零代码退出,则中止操作;执行顺序未定义)。 可以并且应该使用以下一些占位符: {failureType}, {instanceType}, {isMaster}, {isCoMaster}, {failureDescription}, {command}, {failedHost}, {failureCluster}, {failureClusterAlias}, {failureClusterDomain}, {failedPort}, {countReplicas}, {replicaHosts}, {isDowntimed}
PostFailoverProcesses                      []string          // 执行故障转移后要执行的流程(执行顺序未定义)。 可以并且应该使用以下一些占位符: {failureType}, {instanceType}, {isMaster}, {isCoMaster}, {failureDescription}, {command}, {failedHost}, {failureCluster}, {failureClusterAlias}, {failureClusterDomain}, {failedPort}, {successorHost}, {successorPort}, {successorBinlogCoordinates}, {successorAlias}, {countReplicas}, {replicaHosts}, {isDowntimed}, {isSuccessful}, {lostReplicas}, {countLostReplicas}
PostUnsuccessfulFailoverProcesses          []string          // 未完全成功的故障转移后执行的流程(执行顺序未定义)。 可以并且应该使用以下一些占位符: {failureType}, {instanceType}, {isMaster}, {isCoMaster}, {failureDescription}, {command}, {failedHost}, {failureCluster}, {failureClusterAlias}, {failureClusterDomain}, {failedPort}, {successorHost}, {successorPort}, {successorBinlogCoordinates}, {successorAlias}, {countReplicas}, {replicaHosts}, {isDowntimed}, {isSuccessful}, {lostReplicas}, {countLostReplicas}
PostMasterFailoverProcesses                []string          // 执行主故障转移后要执行的流程(执行顺序未定义)。 使用与 PostFailoverProcesses 相同的占位符
PostIntermediateMasterFailoverProcesses    []string          // 执行 中间主库(级联复制)故障转移后要执行的进程(执行顺序未定义)。 使用与 PostFailoverProcesses 相同的占位符
PostGracefulTakeoverProcesses              []string          // 运行优雅的主接管后要执行的进程。 使用与 PostFailoverProcesses 相同的占位符

脚本返回状态码

PreFailoverProcesses : 非零代码退出,则终止操作 

PostFailoverProcesses : 非零代码退出,则终止操作 

如果你在该脚本中 调用了修改域名后端的IP,或者修改LVS后端的RS,在修改不成功时 ,则钩子脚本返回一个非零的值即可终止恢复流程。

占位符

可以并且应该使用以下一些占位符:

{failureType}, // 失败类型{instanceType}, // 实例类型{isMaster}, // 是否为master{isCoMaster}, // 是否为CoMaster{failureDescription}, // 失败描述{command},// 命令{failedHost}, // 故障实例主机{failureCluster}, // 故障实例所在集群{failureClusterAlias},  // 故障集群别名{failureClusterDomain}, // 故障集群域名{failedPort}, // 故障实例端口{successorHost}, // 新主库的{successorPort},//  新主库的端口{successorAlias},//  {countReplicas}, // 从副本的个数{replicaHosts},//  从副本的主机名{isDowntimed},// 是否维护状态{autoMasterRecovery},// 是否开启自动恢复{autoIntermediateMasterRecovery}

配置文件中的配置例子

配置了两个脚本,第一个是shell 脚本,第二个是一个go脚本,

  "OnFailureDetectionProcesses": ["echo 'Detected {failureType} on {failureCluster}. Affected replicas: {countSlaves}' >> /tmp/recovery.log","/usr/local/orchestrator/scripts/orcFailureDetection --failureType {failureType} --instanceType {instanceType} --failureDescription '{failureDescription}' --failedHost {failedHost} --failureCluster {failureCluster} --failureClusterAlias {failureClusterAlias} --failureClusterDomain {failureClusterDomain} --failedPort {failedPort} --successorHost {successorHost} --successorPort {successorPort} --successorAlias {successorAlias} --countReplicas {countReplicas}"],

核心函数调用流程:

executeProcesses 

        --> prepareCommand // 组装脚本

        --> applyEnvironmentVariables // 环境变量

        --> executeProcess // 执行脚本

                --> os.CommandRun(command, env)

                        --> generateShellScript // 生成shell 脚本

                        --> cmd.CombinedOutput() // 执行命令 

OC如何调用钩子脚本

1  将脚本中的占位符替换成实际的变量 

// prepareCommand replaces agreed-upon placeholders with analysis data
// prepareCommand 通过分析得到的数据替换脚本的占位符
func prepareCommand(command string, topologyRecovery *TopologyRecovery) (result string, async bool) {analysisEntry := &topologyRecovery.AnalysisEntry// 从 command 字符串中移除前后的空白字符。command = strings.TrimSpace(command)// 检查 command 字符串是否以 "&" 结尾。if strings.HasSuffix(command, "&") {// 如果是,移除末尾的 "&" 并将 async 设置为 true。command = strings.TrimRight(command, "&")async = true}// 将命令中的 占位符替换为 analysisEntry 的字符串表示形式。command = strings.Replace(command, "{failureType}", string(analysisEntry.Analysis), -1)command = strings.Replace(command, "{instanceType}", string(analysisEntry.GetAnalysisInstanceType()), -1)command = strings.Replace(command, "{isMaster}", fmt.Sprintf("%t", analysisEntry.IsMaster), -1)command = strings.Replace(command, "{isCoMaster}", fmt.Sprintf("%t", analysisEntry.IsCoMaster), -1)command = strings.Replace(command, "{failureDescription}", analysisEntry.Description, -1)command = strings.Replace(command, "{command}", analysisEntry.CommandHint, -1)command = strings.Replace(command, "{failedHost}", analysisEntry.AnalyzedInstanceKey.Hostname, -1)command = strings.Replace(command, "{failedPort}", fmt.Sprintf("%d", analysisEntry.AnalyzedInstanceKey.Port), -1)command = strings.Replace(command, "{failureCluster}", analysisEntry.ClusterDetails.ClusterName, -1)command = strings.Replace(command, "{failureClusterAlias}", analysisEntry.ClusterDetails.ClusterAlias, -1)command = strings.Replace(command, "{failureClusterDomain}", analysisEntry.ClusterDetails.ClusterDomain, -1)command = strings.Replace(command, "{countSlaves}", fmt.Sprintf("%d", analysisEntry.CountReplicas), -1)command = strings.Replace(command, "{countReplicas}", fmt.Sprintf("%d", analysisEntry.CountReplicas), -1)command = strings.Replace(command, "{isDowntimed}", fmt.Sprint(analysisEntry.IsDowntimed), -1)command = strings.Replace(command, "{autoMasterRecovery}", fmt.Sprint(analysisEntry.ClusterDetails.HasAutomatedMasterRecovery), -1)command = strings.Replace(command, "{autoIntermediateMasterRecovery}", fmt.Sprint(analysisEntry.ClusterDetails.HasAutomatedIntermediateMasterRecovery), -1)command = strings.Replace(command, "{orchestratorHost}", process.ThisHostname, -1)command = strings.Replace(command, "{recoveryUID}", topologyRecovery.UID, -1)command = strings.Replace(command, "{isSuccessful}", fmt.Sprint(topologyRecovery.SuccessorKey != nil), -1)if topologyRecovery.SuccessorKey != nil {command = strings.Replace(command, "{successorHost}", topologyRecovery.SuccessorKey.Hostname, -1)command = strings.Replace(command, "{successorPort}", fmt.Sprintf("%d", topologyRecovery.SuccessorKey.Port), -1)// As long as SuccessorBinlogCoordinates != nil, we replace {successorBinlogCoordinates}// Format of the display string of binlog coordinates would be LogFile:LogPositonif topologyRecovery.SuccessorBinlogCoordinates != nil {command = strings.Replace(command, "{successorBinlogCoordinates}", topologyRecovery.SuccessorBinlogCoordinates.DisplayString(), -1)}// As long as SucesssorKey != nil, we replace {successorAlias}.// If SucessorAlias is "", it's fine. We'll replace {successorAlias} with "".command = strings.Replace(command, "{successorAlias}", topologyRecovery.SuccessorAlias, -1)}command = strings.Replace(command, "{lostSlaves}", topologyRecovery.LostReplicas.ToCommaDelimitedList(), -1)command = strings.Replace(command, "{lostReplicas}", topologyRecovery.LostReplicas.ToCommaDelimitedList(), -1)command = strings.Replace(command, "{countLostReplicas}", fmt.Sprintf("%d", len(topologyRecovery.LostReplicas)), -1)command = strings.Replace(command, "{slaveHosts}", analysisEntry.Replicas.ToCommaDelimitedList(), -1)command = strings.Replace(command, "{replicaHosts}", analysisEntry.Replicas.ToCommaDelimitedList(), -1)return command, async
}

2 根据命令生成一个临时的Shell 脚本

// generateShellScript 根据给定要执行的命令生成一个临时的 shell 脚本,
func generateShellScript(commandText string, env []string, arguments ...string) (*exec.Cmd, string, error) {// 获取配置中的 shell 命令shell := config.Config.ProcessesShellCommand// 将命令文本转换为字节切片commandBytes := []byte(commandText)// 创建临时文件tmpFile, err := ioutil.TempFile("", "orchestrator-process-cmd-")if err != nil {return nil, "", log.Errorf("generateShellScript() 失败创建临时文件: %v", err.Error())}// 将命令文本写入临时文件ioutil.WriteFile(tmpFile.Name(), commandBytes, 0640)// 构建 shell 命令的参数shellArguments := append([]string{}, tmpFile.Name())shellArguments = append(shellArguments, arguments...)// 创建 exec.Command,该命令可与创建的脚本名称一起执行cmd := exec.Command(shell, shellArguments...)cmd.Env = envreturn cmd, tmpFile.Name(), nil
}

3 执行脚本

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/695889.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

RoboRAVE世界机器人大会亚洲分会toio™专项挑战顺利收官,toio™实现“双首次”突破

2024年2月21日,北京——2024 RoboRAVE国际教育机器人大会(下称RoboRAVE)亚洲分会toio™专项挑战在北京科技大学成功举办。现场云集来自华北、华南、华东等全国各地40组杰出学生队伍,展开热烈的机器人编程限时挑战。本届toio™专项…

大模型中的token是什么?

定义 大模型的"token"是指在自然语言处理(NLP)任务中,模型所使用的输入数据的最小单元。这些token可以是单词、子词或字符等,具体取决于模型的设计和训练方式。 大模型的token可以是单词级别的,也可以是子…

项目总结(ALL)

项目1: 卡尔曼滤波(以及其他的滤波方法对比) 预处理 GRU,LSTM等时间序列预测方法 MPC(模型预测控制) 单机控制算法 粒子群优化算法 1. 卡尔曼滤波 smoother KalmanSmoother(componentlevel_trend,…

Docker安装Postgresql12

1、搜索仓库中postgres docker search postgres 2、拉取镜像 docker pull postgres docker pull postgres:12 #拉取12版本的PG库 3、创建数据库文件夹 cd /temp/ && mkdir -m 755 postgres-data 注:-m表示权限,类chmod命令 4、执行命令启动…

echarts - 数据更新但图表不更新

当修改setOption值的时候,如果 option.series 是动态增加减少,图表渲染会出错。 比如,echarts 图表一开始只有单一的柱状图,后来通过 option.series 动态插入数据,新增折线图。这时候 echarts 图表是柱状图折线图&…

并发编程入门指南

文章目录 并发编程进程和线程的区别并发和并行的区别创建线程的方式线程之间的状态,状态之间的转换新建三个线程,如何保证按顺序执行wait方法和sleep的区别如何停止一个正在运行的线程synchronized关键字底层原理Monitor属于重量级锁,了解过锁…

day04_流程语句_if_while_for

今日内容 1.if 2.switch 3.while,do-while,for 零、复习 1算术运算符中除法特性 整数相除不保留小数 10/33 2什么作用,i和i什么区别 让数据自增1i,是在后先使用后自增i,是在前先自增后使用 3&& 和 & 有相同点和不同点 相同点: 两边判断式子,一错就错全对才对不同点…

HTML+CSS滚动条样式如何单独给firefox设置 scrollbar-width: none;,而不影响其他浏览器

要在Firefox中单独设置滚动条样式,你可以使用​​@-moz-document​​规则。这个规则允许你为特定的浏览器或浏览器引擎应用样式。 下面是一个例子,演示如何在Firefox中隐藏滚动条: @-moz-document url-prefix() {/* 在这里添加只对Firefox生效的样式 */body {scrollbar-wi…

一文了解web开发基础知识【HTML、CSS、JavaScript】

文章目录 1 前言1.1 HTML1.2 CSS1.3 JavaScript1.4 理解HTML、CSS、JavaScript之间的关系 2 HTML2.1 什么是网页2.2 什么是HTML2.2.1 文本内容2.2.1.1 标题 2.2.2 图像2.2.3 链接2.2.4 列表2.2.5 表格2.2.6 HTML代码注释 2.3 第一个HTML文件2.3.1 示例2.3.2 补充2.3.2.1 < l…

苹果iPad通过Code APP应用实现SSH连接服务器远程进行开发

文章目录 1. 在iPad下载Code APP2.安装cpolar内网穿透2.1 cpolar 安装2.2 创建TCP隧道 3. iPad远程vscode4. 配置固定TCP端口地址4.1 保留固定TCP地址4.2 配置固定的TCP端口地址4.3 使用固定TCP地址远程vscode 本文主要介绍开源iPad应用IDE Code App 如何下载安装&#xff0c;并…

Linux-查看服务器--硬件配置信息

在Linux服务器上查看硬件配置信息&#xff0c;可以使用一系列命令行工具。以下是一些常用命令来获取不同硬件组件的详细信息&#xff1a; 查看CPU信息&#xff1a; cat /proc/cpuinfo&#xff1a;显示处理器类型、型号、频率、核心数等详细信息。lscpu&#xff1a;提供更为人性…

五个简单的C#编程案例

案例一&#xff1a;Hello, World! csharp using System; class Program { static void Main() { Console.WriteLine("Hello, World!"); } } 这个案例是最基础的C#程序&#xff0c;它打印出“Hello, World!”到控制台。每个C#程…

基于springboot + vue实现的前后端分离-酒店管理系统

项目介绍 基于springboot vue实现的酒店管理系统一共有酒店管理员和用户这两种角色。 管理员功能 登录&#xff1a;管理员可以通过登录功能进入系统&#xff0c;确保只有授权人员可以访问系统。用户管理&#xff1a;管理员可以添加、编辑和删除酒店的用户&#xff0c;包括前…

运维SRE-18 自动化批量管理-ansible4

12.2handles handles触发器(条件)&#xff0c;满足条件后再做什么事情应用场景&#xff1a;想表示&#xff1a;配置文件变化&#xff0c;再重启服务 配置handlers之前&#xff0c;每次运行剧本都会重启nfs&#xff0c;无论配置文件是否变化。 [rootm01 /server/ans/playbook]…

C++--输入一个数字判断是否是素数

一.算法思路 要判断数字n是否是素数&#xff0c;那么用n除以一个2~根号n的数字i&#xff0c;若有一个被整除&#xff0c;说明n不是素数&#xff0c;否则是素数 二.完整代码 #include<cmath> #include<iostream> bool IsPrime(int n) {for (int i 2;i < sqrt(n…

【计算机网络:DHCP协议】

文章目录 前言一、DHCP是什么&#xff1f;二、DHCP的工作原理1.基本流程发现&#xff08;DISCOVER&#xff09;提供&#xff08;OFFER&#xff09;请求&#xff08;REQUEST&#xff09;确认&#xff08;ACKNOWLEDGEMENT&#xff09; 2.DHCP租约的概念3.DHCP续租过程 三、DHCP服…

【MATLAB GUI】 1. 普通按钮、静态文本和可编辑文本

看B站up主freexyn的freexyn编程实例视频教程系列36Matlab GUI的学习笔记 文章目录 初步认识普通按钮静态文本和可编辑文本设计一个简易计算机 初步认识普通按钮 任务要求&#xff1a;点击一次“100”按钮&#xff0c;按钮上的文字值就递增1&#xff1b;点击“close”按钮&…

Python语言例题集(006)

#!/usr/bin/python3 #建立一个含3个节点的链表&#xff0c;然后打印此链表。 class Node(): def init(self,dataNone): self.datadata self.nextNone n1Node(5) n2Node(15) n3Node(25) n1.nextn2 n2.nextn3 ptrn1 while ptr: print(ptr.data) ptrptr.next

[精通linux]-302- linux 高级命令

查看bash类型 $ echo $0 #输出位zsh或者bash查看命令类型 $ type ls # 输出 ls is an alias for ls -G重定向 学会使用 > 和 < 来重定向输出和输入,学会使用 | 来重定向管道。明白 > 会覆盖了输出文件而 >> 是在文件末添加。 任务管理器 熟悉 Bash 中的任…

UniApp中打开蓝牙所需哪些权限

Hello&#xff0c;各位同学们新年好呀&#xff0c;咱们又见面了&#xff01;我是咕噜铁蛋&#xff01;随着移动应用的普及&#xff0c;蓝牙技术正变得越来越重要。在UniApp中&#xff0c;打开蓝牙功能为我们提供了更多便利和创新的可能性。然而&#xff0c;很多人可能不清楚在U…