尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

OneUptime × Jira 双向集成实战:用 Workflow 与 REST API 打通事故和 Issue 的双向同步

OneUptime × Jira 双向集成实战:用 Workflow 与 REST API 打通事故和 Issue 的双向同步 OneUptime × Jira 双向集成实战用 Workflow 与 REST API 打通事故和 Issue 的双向同步【免费下载链接】oneuptimeComplete open-source monitoring and observability platform.项目地址: https://gitcode.com/GitHub_Trending/on/oneuptime本篇基于 OneUptime 官方文档 Jira-Integration讲解如何不安装任何 Jira 专用组件仅靠 OneUptime 的 WorkflowOn Create/Update Incident 触发器、API 组件、Webhook 触发器调用 Jira REST API实现“事故创建即开 Issue、事故状态移动即评论/转移 Issue、Jira 状态变化回写事故”的完整双向同步方案。读完你可以直接照抄全局变量、工作流组件配置与 JQL 查询落地这套集成并掌握 Jira Cloud 与 Data Center 的差异、限流、认证过期等常见故障的排查方法。双向同步总体架构OneUptime 事故被宣布时打开一个 Jira Issue事故状态变化时让 Jira Issue 跟随移动Jira 中的状态变更再通过 Webhook 推回 OneUptime——整个链路只用两类通用组件完成OneUptime 侧通过 API 组件调用 Jira REST APIJira 侧通过 Webhook 触发器接收回调OneUptime Incident → On Create ──► API Post (POST /rest/api/3/issue) ──► Jira issue Jira issue transitioned ──► Automation rule (Send web request) ──► OneUptime Webhook trigger ──► Update One Incident下文除最后 Data Center 一节外均按Jira Cloud编写自托管读者请按文末的替换表调整。背景提示Atlassian 正在 Jira Cloud 中做大规模改名——project在界面上大多变成了spaceissue变成了work item。租户处于新旧两种叫法并存期因此本文在措辞重要的地方两种词汇都会出现。前置条件一个 Jira Cloud 站点https://your-domain.atlassian.net和一个用于建 Issue 的项目记下它的项目密钥——即OPS-1234中的OPS。一个有权限在该项目创建 Issue 的 Jira 账号以及对应的API-Token在 Atlassian 账号中心 id.atlassian.com 的 security/api-tokens 页面生成。强烈建议用服务账号而非个人账号——创建的 Issue 会归属到 Token 持有者名下。有在该项目创建自动化规则automation rule的权限用于入站方向。一个可以创建 Workflow 和全局变量的 OneUptime 项目。第一步把 Jira 凭据存为全局变量秘密Jira Cloud REST API 期望Basic-AuthAtlassian 账号邮箱 API-Token 拼成email:api_token后做 Base64 编码。只编码一次注意必须用printfprintf %s youexample.com:your_api_token | base64不要用echo。echo会追加换行符换行符被一起编码进字符串Jira 会直接回401——而问题就藏在你看不出来的编码字符串里。在 OneUptime 中进入Arbeitsabläufe工作流→ Globale Variablen全局变量→ 创建把变量命名为JIRA_AUTH粘贴 Base64 字符串作为内容Inhalt并勾选Geheimnis秘密。再创建一个非秘密变量JIRA_URL内容为https://your-domain.atlassian.net结尾不带斜杠。此后任何组件都可以用Basic {{global.variables.JIRA_AUTH}}作为Authorization头Token 永远不会出现在工作流定义或执行日志里——这一点在源码层面有直接保证OneUptime 的工作流日志写入前会经过一层秘密脱敏逻辑把所有标记为 secret 的全局变量取值替换为[REDACTED]见 SecretRedaction.ts。变量机制的完整说明见 变量文档。有两个关于 Atlassian API-Token 的事实迟早会找上每一个没人盯着的集成Token 会过期。Token 创建时长为 1 天到 1 年默认 1 年且没有续期机制——过期后必须回同一页面手动替换并重新编码进JIRA_AUTH。把到期日写进日历。如果某个工作流跑了几个月突然开始401这就是原因。带 Scopes 的 Token 走不同基址。Token 页面除经典Create API token外还提供Create API token with scopes。带 Scopes 的 Token 更安全但它不指向你的站点请求要发到https://api.atlassian.com/ex/jira/cloudId所以JIRA_URL要换成它下文所有路径原样拼接在后面即可。cloudId可以在https://your-domain.atlassian.net/_edge/tenant_info的 JSON 响应里找到。带 Scopes 的 Token 打到your-domain.atlassian.net上会直接失败。如果你的组织使用 Atlassian 集中用户管理还有第三条路可以从根本上绕开过期问题为服务账号创建OAuth 2.0 Credential。这样你拿到的是 Client-ID 和 Secret 而非 Token工作流在每次执行开头先换取一个短生命周期 Access Token——这正是 Microsoft Dynamics 365 集成所用的两组件结构一个API Post (JSON)组件负责取 Token其后所有组件发送Bearer token。一年后无需任何手动替换API 基址为https://api.atlassian.com具体 Token 请求格式见 Atlassian 官方文档。第二步为每个事故打开一个 Jira Issue打开Arbeitsabläufe → Workflow 创建命名为Incidents → Jira打开Builder。点击虚线占位组件添加触发器On Create Incident。在Select Fields里勾选要发送的列{ _id: true, title: true, description: true, incidentNumber: true, incidentSeverity: { name: true } }Identifier保持为incident-on-create-1——后续组件靠这个名字引用它的输出。点击Komponente hinzufügen添加组件加入API Post (JSON)组件从触发器的Erfolg成功输出口连线到新组件的输入口。打开它把Identifier设为create-issue填写URL{{global.variables.JIRA_URL}}/rest/api/3/issueRequest Headers{ Authorization: Basic {{global.variables.JIRA_AUTH}}, Accept: application/json }Request Body{ fields: { project: { key: OPS }, issuetype: { name: Bug }, summary: OneUptime #{{local.components.incident-on-create-1.returnValues.model.incidentNumber}}: {{local.components.incident-on-create-1.returnValues.model.title}}, labels: [oneuptime], description: { type: doc, version: 1, content: [ { type: paragraph, content: [ { type: text, text: {{local.components.incident-on-create-1.returnValues.model.description}} } ] } ] } } }把OPS换成你的项目密钥把Bug换成该项目实际存在的 Issue 类型。两者也可以按 ID 给出——{id: 10000}——这是 Atlassian 官方示例的做法当你站点上有两个 Issue 类型同名时应当优先用 ID。这些 ID 可以通过下文createmeta调用来获得。描述字段之所以显得笨重是因为 Jira Cloud 的 v3 API 把富文本作为Atlassian Document FormatADF接收——一个文档树而不是字符串。上面的形状就是最小合法文档一个段落里包一个文本节点。同样的规则适用于environment和任何多行自定义文本字段单行自定义文本字段仍然直接接收普通字符串。然后在工作流Übersicht概览→ Workflow 编辑 → 启用中打开开关宣布一个测试事故查看Ausführungen Protokolle执行与日志。create-issue组件应显示201和一个包含新 Issue 的id、key、self的响应体。画布上的修改会自动保存——没有保存按钮而禁用的工作流根本不会运行包括手动运行。新 Issue 的 Key 在此之后对每个组件可见{{local.components.create-issue.returnValues.response-body.key}}这一点可以从组件元数据中印证API 组件的返回值定义里确实包含response-status、response-headers、response-body三个字段见 API.ts并且带Success/Error两个输出口与文档描述完全一致。补全其他字段fields内几个常见补充优先级—priority: { id: 20000 }优先级 ID 取自你的站点。要把 OneUptime 严重度映射到 Jira 优先级就在触发器和 API 组件之间加一个If / Else组件按{{local.components.incident-on-create-1.returnValues.model.incidentSeverity.name}}分支。负责人—assignee: { id: accountId }。Jira Cloud 用 Atlassian Account ID 识别人username和userKey多年前已从 Cloud API 移除。标签—labels: [oneuptime, sev1]一个扁平的字符串数组。标签不能含空格。组件—components: [{ id: 10000 }]。自定义字段—customfield_10034: ...用字段自己的 ID。值的形式取决于字段类型单选是{value: red}多选是 ID 数组多行文本字段是 ADF 文档。与其猜项目要什么不如直接问 Jira。列出某项目的 Issue 类型再列出其中一种类型的字段要求curl -u youexample.com:your_api_token \ https://your-domain.atlassian.net/rest/api/3/issue/createmeta/OPS/issuetypes curl -u youexample.com:your_api_token \ https://your-domain.atlassian.net/rest/api/3/issue/createmeta/OPS/issuetypes/10001第二个调用会列出该 Issue 类型接受的每个字段、哪些是必填、以及精确的customfield_NNNNNID。想从已有 Issue 上读出字段 ID用?expandnames拉取它即可。第三步把事故 ID 带到 Jira 侧双向同步的两半都需要一个存放对方标识的位置而 Jira 是更好的选择OneUptime 事故上的customFields列是单个 JSON 块从工作流写一个值会覆盖该事故的全部自定义字段。有 Jira 管理员时。给项目的创建屏幕加一个简短的自定义文本字段——叫它OneUptime Incident ID——用createmeta查出它的 ID然后和其他字段一起写入customfield_10050: {{local.components.incident-on-create-1.returnValues.model._id}}没有管理员时。把它塞进标签。标签不容忍空格而 OneUptime ID 是纯 UUID所以oneuptime-id是合法标签labels: [oneuptime, oneuptime-{{local.components.incident-on-create-1.returnValues.model._id}}]入站工作流之后需要从标签数组里把这个值挑出来几行Run Custom JavaScript组件就能做到。能用自定义字段时它更干净。顺手值得再建一个从 Jira 指回事故的链接在create-issue之后加一个API Post (JSON)组件指向{{global.variables.JIRA_URL}}/rest/api/3/issue/{{local.components.create-issue.returnValues.response-body.key}}/remotelinkBody 为{ globalId: systemhttps://oneuptime.comid{{local.components.incident-on-create-1.returnValues.model._id}}, object: { url: https://oneuptime.com/dashboard/{{local.components.incident-on-create-1.returnValues.model.projectId}}/incidents/{{local.components.incident-on-create-1.returnValues.model._id}}, title: OneUptime incident #{{local.components.incident-on-create-1.returnValues.model.incidentNumber}} } }这样所有在 Jira 里的人都能一键跳回事故。为此需要把projectId加进触发器的Select Fields。globalId让这个调用可以安全重复Jira 会更新已携带该 ID 的链接而不是再加一个。由于更新操作会清空你没发送的部分请始终发送完整的object不要发片段。第四步事故移动时评论并转移 Issue把这做成第二个工作流这样这里的错误永远不可能阻塞第一步的开 Issue 动作。创建 Workflow命名Incident updates → Jira添加触发器On Update Incident。在Listen on填{currentIncidentStateId: true}。这样触发器只在状态变化时触发而不是每次编辑都触发。在Select Fields里要求{_id: true, currentIncidentState: {name: true}}。加一个If / Else组件Input 1为{{local.components.incident-on-update-1.returnValues.model.currentIncidentState.name}}Operator为Input 2为Resolved——或者你的项目里叫法不同的“已解决”状态名。状态与严重度的概念见 事故状态与严重度。从Ja是分支出发需要先找到第二步开的那个 Issue。用第三步存的 ID 向 Jira 查询通过一个API Post (JSON)组件完成Identifier设为find-issueURL{{global.variables.JIRA_URL}}/rest/api/3/search/jqlRequest Body{ jql: project OPS AND labels \oneuptime-{{local.components.incident-on-update-1.returnValues.model._id}}\, maxResults: 1 }如果第三步用的是自定义字段而不是标签这个子句变成cf[10050] ~ \...\用你自己的字段 ID。Issue ID 之后就是{{local.components.find-issue.returnValues.response-body.issues[0].id}}下文所有端点对 ID 和 Key 同样买账。关于这个端点有三件事必须知道。JQL 要走 POST 发送不要塞进 URL——值里带的 Query String 从工作流发出时会被截断而 JQL 几乎全是。查询必须有范围限定裸的order by key desc会被400拒绝所以project 子句必须在那里。另外/rest/api/3/search/jql是当前端点——老的/rest/api/3/search已废弃并计划下线别再去用它。留评论是一个API Post (JSON)组件打到{{global.variables.JIRA_URL}}/rest/api/3/issue/id/commentBody 同样是 ADF 文档{ body: { type: doc, version: 1, content: [ { type: paragraph, content: [{ type: text, text: Resolved in OneUptime. }] } ] } }移动 Issue 需要两次调用因为转移transition是按 ID 标识的而这个 ID 在不同 Jira 工作流之间、甚至在某些看板的不同 Issue 之间都会变。用API Get (JSON)组件请求{{global.variables.JIRA_URL}}/rest/api/3/issue/id/transitions返回从 Issue当前状态出发的所有可用转移各带id、name以及标明目标状态的to对象。用API Post (JSON)组件向同一 URL 执行其中一个{ transition: { id: 31 } }成功的转移返回204且无 Body。如果不想在运行时读列表可以手动对一个处于正确状态的 Issue 调一次把 ID 写死——但记住它绑定的是那个 Jira 工作流管理员一改 Jira 工作流就可能悄悄把它弄坏。入站方向从 Jira 推回 OneUptime现在做另一半有人把 Issue 拖到 DoneOneUptime 事故要跟随移动。先建接收侧工作流创建 Workflow命名Jira → OneUptime添加触发器Webhook。打开该工作流的Einstellungen设置复制秘密 Webhook 密钥。你的 URL 是https://oneuptime.com/workflow/trigger/webhook secret key自托管部署用自己的主机名。把 URL 当密码保管——拿到它的人就能触发这个工作流——一旦外泄就在同一页面重置密钥。加一个If / Else组件在任何逻辑运行前校验共享秘密。Input 1为{{local.components.webhook-1.returnValues.request-headers.x-oneuptime-secret}}Operator为Input 2为{{global.variables.JIRA_WEBHOOK_SECRET}}——一个你自己编出来、存为秘密全局变量的值。这个头部能被读到的前提是 Webhook 触发器确实会输出request-headers和request-body——这一点在组件元数据 Webhook.ts 中可见触发器定义了三组request-headers、request-params、request-body返回值。从Ja分支加Update One Incident组件Query{_id: {{local.components.webhook-1.returnValues.request-body.oneuptimeIncidentId}}}Data (JSON Object)Jira 的变更在这里意味着什么——通常是状态变化。要移动事故需要目标状态 ID用Find One Incident State组件以 Query{name: Resolved}查询拿到{{local.components.incident-state-find-one-1.returnValues.model._id}}写进currentIncidentStateId。这些数据库组件是引擎按模型自动生成注册的见 BaseModel.ts 的组件工厂与 ComponentMetadata.ts 的装配逻辑Incident 模型开启了工作流开关后就会以incidents-find-one、incident-state-find-one这类 ID 出现在 Builder 里其 Query 参数以列名为键ID 列名是_idid拼写也接受。把该工作流保持启用状态现在给 Jira 一个可以调用的东西。从 Jira 自动化规则发送事件在 Jira 打开项目的自动化规则新租户走Space settings → Automation旧租户走Project settings → Automation。跨项目的规则走Settings → System → Global automation需要全局权限Administer Jira。Create rule触发器选Work item transitioned——旧租户叫Issue transitioned。配置为状态变到onDone时运行。务必选这个触发器不要选Work item updatedUpdate 触发器刻意排除状态变更。添加动作Send web request发送 Web 请求并配置Web request URL上面的 OneUptime Webhook URL。HTTP methodPOSTHeadersContent-Type/application/json以及X-OneUptime-Secret/ 你的共享秘密。对秘密值使用Hide选项防止其他规则编辑者读到——注意隐藏不可逆规则被导出或复制时隐藏值会丢失。Web request body选Custom format以自行控制结构{ oneuptimeIncidentId: {{issue.customfield_10050}}, issueKey: {{issue.key}}, summary: {{issue.summary}}, status: {{issue.status.name}} }如果第三步用的是标签而非自定义字段就发送labels: {{issue.labels}}然后在 OneUptime 侧用Run Custom JavaScript组件提取 ID。启用规则把一个测试 Issue 拖到 Done然后两侧都检查Jira 里规则的审计日志以及 OneUptime 的执行与日志。依赖它之前需要知道的限制目标端口受限。Send web request 只能到达 80、8080、443、6017、8443、8444、7990、8090、8085、8060、8900、9900。OneUptime Cloud 在 443 上自托管部署跑在非标准端口上就无法被这样调用。请求没有签名。该动作没有 HMAC 选项HTTPS 加共享秘密头是 Atlassian 文档化的认证机制。接收侧工作流里那个 If / Else 检查才是让它值得做的部分。规则执行会被计数。Jira Cloud 把成功的规则执行计入按月配额取决于套餐Free 100 次、Standard 1,700 次、Premium 每用户 1,000 次、Enterprise 不限。一条在繁忙项目里每次转移都触发的规则累计起来很快。值不会替你 URL 编码。只有发送表单编码 Body 时才成为问题上面的 JSON 无碍。Atlassian 会在 ip-ranges.atlassian.com 公布其出站 IP 段如果你的 OneUptime 部署在正向允许名单之后可以用它。这些段会变请定期拉取该 feed不要写死地址。或者改用 Jira 原生 WebhookJira 管理员也可以在Settings → System → Advanced → WebHooks直接注册 Webhook选择要发送的事件并可选一条限定触发 Issue 范围的 JQL。与自动化规则相比Payload 是 Jira 自己的结构而非你自定义的webhookEvent、issue_event_type_name、完整issue对象以及一个changelog其items数组记录每个被改字段的前后值。状态变化要找field等于status的条目。在工作流里读它通常需要一个Run Custom JavaScript组件。Webhook可以签名——给 Webhook 设个密钥Jira 就会发送包含请求体 HMAC 的X-Hub-Signature头——但工作流无法校验它签名覆盖的是 Jira 发出的原始字节而 Webhook 触发器交给工作流的是已解析成 JSON 的 Body没有东西可再哈希。想认证请求请改用带共享秘密头的自动化规则。URL 必须是 HTTPS 且端口在 Jira 自己的列表内而这份列表和自动化动作用的那份不是同一份——这里 80 端口不允许。投递失败会重试最多 5 次退避间隔 5 到 15 分钟所以你的工作流必须能容忍同一事件到达两次幂等设计。通过/rest/api/3/webhook由应用注册的 Webhook 又另当别论不续期的话注册 30 天后失效上面描述的由管理员注册的 Webhook 不会过期。Jira Data Center 差异自托管 Jira 同样可以跑通只需做几处替换。Jira Server已于 2024 年 2 月停止支持、不再修复因此把 Data Center 作为自托管目标。CloudData Center/rest/api/3/.../rest/api/2/...——Data Center 没有 v3description用 ADF 文档description用 Wiki-Markup 纯字符串Authorization: Basic base64(email:api_token)Authorization: Bearer personal access tokenAPI-Token 来自 id.atlassian.com在你自己的 Jira 账号里Profile → Personal access tokens → Create token自动化动作Send web request自动化动作Send outgoing web request建 Issue 的组件因此变成向/rest/api/2/issue发POST{ fields: { project: { key: OPS }, issuetype: { name: Bug }, summary: OneUptime #123: Checkout is down, description: Plain text goes straight in here. } }没有文档树模板写起来更简单。还需要规划的更多差异Personal access token自 Jira Core / Jira Software 8.14 及 Jira Service Management 4.15 起可用。Token 会过期——默认 365 天——界面会在到期前 5 天标记Expires soon。Data Center 上用户名密码的 Basic-Auth 仍然可用但连续几次登录失败会触发 CAPTCHA把该账号彻底锁在 REST API 之外直到有人在浏览器里解开——发现笔误的糟糕方式。用 Token。Automation 自 Jira Data Center 10.0 起内置之前是需要单独安装的 Automation for Jira 应用。其出站请求默认超时 3000 ms可用属性outgoing.webhook.timeout.ms调整。Webhook在Administration → System → Advanced → WebHooks注册支持 JQL 过滤。保持过滤器紧凑Jira 在触发事件的那个线程上评估每个已注册 Webhook 的 JQL十几个宽松过滤器会拖慢触发它们的那次用户操作。Data Center 10.0 起 Webhook 投递是异步的且没有同步选项事件可能乱序到达。接收侧工作流要做成幂等。Jira 10 移除了 Webhook URL 变量里的$——${issue.id}变成{issue.id}——并把 Webhook REST 资源从/rest/webhooks/1.0/webhook挪到了/rest/jira-webhook/1.0/webhooks。对告警Alert使用同一套模式上面全部围绕事故展开因为那是常见场景但告警Alert完全一样——只换数据集类型其余不变事故告警On Create Incidentincident-on-create-1On Create Alertalert-on-create-1On Update Incidentincident-on-update-1On Update Alertalert-on-update-1incidentNumber、currentIncidentState、incidentSeverityalertNumber、currentAlertState、alertSeverityFind One Incident StateFind One Alert StateUpdate One IncidentUpdate One Alert一个工作流只能有一个触发器所以事故和告警各需要一个独立工作流。如果两者要做相同的工作把 Jira 那一半只建一次用Execute Workflow组件从两个触发工作流里调用它。故障排查先打开执行与日志里失败的那个组件。Jira 返回的 JSON Body 会准确说出拒绝原因而 API 组件把它保留在response-body中。401 Unauthorized。用printf重新编码email:api_token并更新JIRA_AUTHecho的尾部换行是最常见原因。然后确认 Token 所属账号在该项目有创建 Issue 的权限。Data Center 上确认你发的是Bearer而非Basic。400 Bad Request且点名某个字段。Issue 类型在该项目不存在或项目有必填字段而你没发。对项目和 Issue 类型跑一遍上面的createmeta调用并对照。400且抱怨description。Cloud v3 上描述必须是 ADF 文档而非字符串。发上面展示过的文档或把该组件改打/rest/api/2/issue发纯文本。404 Not Found。检查基址和 API 版本——Cloud 用/rest/api/3/...Data Center 用/rest/api/2/...。429 Too Many Requests。Jira 在限流。响应带Retry-After秒和RateLimit-Reason说明撞了哪条限制。对单个 Issue 的写操作限制很紧——量级约两秒 20 次——快速连续评论加转移的工作流完全可能在单个 Issue 上触发。在调用之间放一个Delay组件或把批量工作挪进计划触发的工作流。转移调用返回400。转移 ID 对 Issue当前状态无效。对该 Issue 拉一次/transitions从响应里取 ID。自动化规则显示成功但 OneUptime 没收到。先查端口——见上面的受限列表。然后自己用curl打一次 Webhook URL看它是否出现在执行与日志里你的请求到了而 Jira 的没到问题就在 Jira 侧。工作流跑了但事故没变。Update One Incident组件在 Query 未命中任何记录时报告Items Updated: 0并且算成功而非错误。检查 Payload 里的 ID 是不是真的 OneUptime 事故 ID并且你确实按_id查询。{{...}}引用原样出现在 Jira Issue 里。未解析的引用会作为文本透传而不是被清空。执行日志会列出每一个没能解析的引用——通常是组件 Identifier 拼错或变量被改名了。延伸阅读集成总览——入站与出站模式、认证速查表。Microsoft Dynamics 365——同一套结构对接 Dynamics 的双向集成。工作流总览与创建工作流——画布、Identifier、启用工作流。组件——API 组件、If / Else 与 OneUptime 数据组件。变量——秘密变量、以及在一个组件里读另一个组件的输出。配置与安全——Webhook 安全与出站网络访问。ServiceNow与PagerDuty——对接其他工具的同一套出站模式。【免费下载链接】oneuptimeComplete open-source monitoring and observability platform.项目地址: https://gitcode.com/GitHub_Trending/on/oneuptime创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表