在TeamCity中,将重启代理作为构建步骤或依赖项

3
有没有一种在TeamCity作业构建期间重启代理机器的方法,如何实现?
我尝试添加依赖作业或使用“shutdown -r -f -t 0”构建步骤,但是TeamCity报告构建已被取消,因为它无法再与代理通信直到重启并导致另一个代理接管构建。
单击“重新启动”时会显示确认弹出窗口。当我使用Curl时,我找不到实际链接。如何单击确认链接?它看起来相同!
          curl -u username:password "http://TeamCityServerURL/agentDetails.html?id=2&agentTypeId=3&realAgentName=ip_10.0.0.1"


           wget –method POST "http://TeamCityServerURL/agentDetails.html?id=2&agentTypeId=3&realAgentName=ip_10.0.0.1" –http-user=Username –http-password=password –header="Content-Length: 0" -O - -S  

重启代理机器有什么意义?它是否必须作为构建的一部分,还是只是在最后进行清理工作? - undefined
虚拟机必须重新启动以加入 AD 域,它必须从那里收集构建信息。 - undefined
代理是在云上动态配置的虚拟机,镜像无法预先加入,加入需要在Windows操作系统上进行电源循环。我离题了,关于你的-1。 - undefined
这就引出了一个问题,它为什么需要在域上运行构建? - undefined
那有什么关系!它必须收集信息!同步代码!并发布领域中的构件!在这个领域中,我能想到一些任务是必需的。 - undefined
你想做的事也许不可能,这种情况下找到另一种方法来完成它可能是你想要做的。我们拥有的信息越多,就越能提供建议。比如,将你的代码与Github同步,并让TeamCity自己处理构件,构建服务器将存储它们。还有这个链接可能与此相关 - undefined
6个回答

3

我可以使用以下curl请求重新启动代理。但是我不知道如何获取代理的ID列表。你如何获取代理ID?

         curl -u User:Password -X POST "http://MyTeamCityServerURL/remoteAccess/reboot.html?agent=2&rebootAfterBuild=true"

curl -s http://teamcityServer/guestAuth/app/rest/agents | xmlstarlet sel -t -v '//agents/agent[@name="YOUR_AGENT_NAME"]/@id' - undefined

2

以下是TeamCity问题跟踪器中相关的请求:https://youtrack.jetbrains.com/issue/TW-36298。 自9.0版本以来,可以在代理详细信息页面上使用“重新启动代理机器”链接手动重启代理。作为解决方法,您可以通过模拟从UI调用的手动操作发送的浏览器请求,在构建脚本中重启代理。


我需要将这个自动化,我想知道如果代理被动态配置,是否会起作用。POST查询参数会是什么样子! - undefined

1

我们有一个类似的需求,需要定期重置MacOS上的USB堆栈,因为Mac的USB堆栈不可靠(在Linux或Windows上完美运行的Android设备)。

我们有一个先决任务,有以下选项:

  • 在同一代理上运行构建
  • 在依赖失败时:使构建失败无法启动
  • 在启动失败/取消依赖时:使构建失败无法启动

该任务运行了 'shutdown -r now' 命令,并立即使用 'echo #teamcity...' 系统向服务器报告成功,试图捕捉重启实际开始和发送到服务器的回显之间的小时间差。

不幸的是,在脚本完成和代理实际重新启动之间有一个短暂的时间,当TeamCity尝试在代理上启动新作业时,我们会有大量的中止构建 - 它们会重新启动,所以它们并不会真正破坏任何东西,但会混乱日志。

我们尝试用以下方法替换它,将代理标记为正在重新启动,然后将关机命令委托给一个后台任务,在TeamCity任务完成之前等待再发出关机命令:

echo "Running: '/sbin/shutdown -r shortly'"
echo rebooting=yes >> $HOME/buildAgent/conf/buildAgent.properties

CONFIG_PROPERTIES=$(grep teamcity.configuration.properties.file $TEAMCITY_BUILD_PROPERTIES_FILE | cut -d= -f2)
TC_SERVER=$(grep teamcity.serverUrl $CONFIG_PROPERTIES | cut -d= -f2)
BUILD_ID=$(grep teamcity.build.id $CONFIG_PROPERTIES | cut -d= -f2)
STATUS=$( echo "${TC_SERVER}/guestAuth/app/rest/builds/id:${BUILD_ID}"|tr -d \\ )
echo Polling $STATUS in background until parent task cannot be confirmed still running.

((
  while true; do
    sleep 5
    if curl -s $STATUS | xmllint --xpath "//build/@running" - | grep true ; then
      :
    else
      echo "passw0rd" | /usr/bin/sudo -p "" -S /sbin/shutdown -r now
    fi
  done
) 2>/dev/null >/dev/null &)&

我在机器的重新启动过程中添加了一步,以便在代理重新启动之前的某个时刻删除“重新启动”参数。 (这是一台Mac电脑,所以我在/Library/LaunchDemon中添加了一个plist文件运行)
/usr/bin/sed -i~ -e /rebooting=yes/d /Users/qa/buildAgent/conf/buildAgent.properties

已经将日志文件目录费尽心思地设置为适当用户可写 - 否则 plist 将默默失败...)

不幸的是,TeamCity 在新的 9.1 版本中似乎没有注意到 'rebooting' 参数,因此我们不得不在此重新启动步骤和实际任务之间添加额外的依赖关系:这个新任务简单地等待,直到在配置文件中无法看到 'rebooting' 参数,而其中一半的时间它会被取消并重新安排 - 这没关系,因为它可以使 'cancelled' 消息不出现在主构建日志中,这正是我们想要的:

echo This task runs after the reboot script, as a buffer between the reboot script and the real reboot.
echo That is, THIS task will get all the INTERRUPTED errors, not the real scripts.

echo Uptime:
uptime

echo Infinite loop until machine reboot, unless reboot is already complete:
while grep rebooting=yes $HOME/buildAgent/conf/buildAgent.properties; do
  echo $(date) Awaiting reboot to interrupt task and clear rebooting=yes from buildAgent.properties file.
  sleep 15
done

显然,复制buildAgent.properties文件,然后将副本移动到原始文件上方,使9.x代理程序注意到更改,从而避免了这个中间步骤的需要,只要您的后续构建任务知道等待引导过程删除'rebooting=yes'参数。我没有尝试过,但那肯定是更可取的。

1
我需要在构建的最后一步重新启动一个(非云)构建代理,因为构建在代理上安装了需要重新启动的软件。然而,这是一个Windows构建代理 - 因此必须在PowerShell或批处理脚本中执行此操作。使用TeamCity 9.x的REST API documentationAccessing Server by HTTP,我能够构建一个简单的两行PowerShell构建步骤。第一个请求获取运行构建的代理的代理ID(安装软件的代理)。第二个请求使用相同的代理ID来重新启动代理。身份验证凭据是构建的配置参数,具有可以进行httpAuth到TeamCity的用户名和密码值。
感谢 Ivan Leonenko博客文章,介绍了正确获取授权头和使用 [System.Net.WebRequest] 的方法。
$username = "%buildAgentAccessUser%"
$password = "%buildAgentAccessPassword%"
$authInfo = $username + ":" + $password
$authInfo = [System.Convert]::ToBase64String([System.Text.Encoding]::Default.GetBytes($authInfo))

$uri = "%teamcity.serverUrl%/httpAuth/app/rest/agents/name:%teamcity.agent.name%/id"

$webRequest = [System.Net.WebRequest]::Create($uri)
$webRequest.Headers["Authorization"] = "Basic " + $authInfo
$webRequest.PreAuthenticate = $true 
[System.Net.WebResponse] $resp = $webRequest.GetResponse();
$rs = $resp.GetResponseStream();
[System.IO.StreamReader] $sr = New-Object System.IO.StreamReader -argumentList $rs;
[string] $id = $sr.ReadToEnd();
Write-Output "Rebooting Agent ID: $id"

$uri = "%teamcity.serverUrl%/httpAuth/remoteAccess/reboot.html?agent=$id&rebootAfterBuild=true"

$webRequest = [System.Net.WebRequest]::Create($uri)
$webRequest.Headers["Authorization"] = "Basic " + $authInfo
$webRequest.PreAuthenticate = $true 
[System.Net.WebResponse] $resp = $webRequest.GetResponse();
$rs = $resp.GetResponseStream();
[System.IO.StreamReader] $sr = New-Object System.IO.StreamReader -argumentList $rs;
$sr.ReadToEnd();

这是我的最后一步构建,构建完成后会重新启动代理。

0
基于Lantrix的解决方案,只需将请求方法设置为post。
$ErrorActionPreference = "Stop"
$auth = "%username%:%password%"
$auth = [System.Convert]::ToBase64String([System.Text.Encoding]::Default.GetBytes($auth))
$uri = "%teamcity.serverUrl%/httpAuth/app/rest/agents/name:%teamcity.agent.name%/id"
$request = [System.Net.WebRequest]::Create($uri)
$request.Headers["Authorization"] = "Basic " + $auth
$request.PreAuthenticate = $true 
[System.Net.WebResponse] $response = $request.GetResponse();
[System.IO.StreamReader] $streamReader = New-Object System.IO.StreamReader -argumentList $response.GetResponseStream();
[string] $id = $streamReader.ReadToEnd();
Write-Output "Trigger reboot of Agent ID: $id"
$uri = "%teamcity.serverUrl%/httpAuth/remoteAccess/reboot.html?agent=$id&rebootAfterBuild=true"
$request = [System.Net.WebRequest]::Create($uri)
$request.Method="POST"
$request.Headers["Authorization"] = "Basic " + $auth
$request.PreAuthenticate = $true 
[System.Net.WebResponse] $response = $request.GetResponse();
[System.IO.StreamReader] $streamReader = New-Object System.IO.StreamReader -argumentList $response.GetResponseStream();
[string] $response = $streamReader.ReadToEnd();

0
我已经对@lantrix的PowerShell脚本进行了改编,使其可以重启所有代理而不仅仅是当前代理。在TeamCity中将其作为一个单独的项目,并使用计划触发它,例如每天重启所有构建代理。
$username = "myUserName"
$password = "myPassword"
$authInfo = $username + ":" + $password
$authInfo = [System.Convert]::ToBase64String([System.Text.Encoding]::Default.GetBytes($authInfo))

$uri = "%teamcity.serverUrl%/httpAuth/app/rest/agents"

# Query which agents there are
$webRequest = [System.Net.WebRequest]::Create($uri)
$webRequest.Headers["Authorization"] = "Basic " + $authInfo
$webRequest.PreAuthenticate = $true 
[System.Net.WebResponse] $resp = $webRequest.GetResponse();
$rs = $resp.GetResponseStream();
[System.IO.StreamReader] $sr = New-Object System.IO.StreamReader -argumentList $rs;
[xml] $unitsXml = $sr.ReadToEnd();

# Schedule a reboot for every agent
$idNodes = $unitsXml.SelectNodes("//*[@id]")
foreach ($node in $idNodes) {
    $id = $node.attributes['id'].value
    $name = $node.attributes['name'].value
    
    Write-Output "Scheduling reboot for agent $name with ID $id"
    
    $uri = "%teamcity.serverUrl%/httpAuth/remoteAccess/reboot.html?agent=$id&rebootAfterBuild=true"
    
    $webRequest = [System.Net.WebRequest]::Create($uri)
    $webRequest.Method="POST"
    $webRequest.Headers["Authorization"] = "Basic " + $authInfo
    $webRequest.PreAuthenticate = $true 
    [System.Net.WebResponse] $resp = $webRequest.GetResponse();
    $rs = $resp.GetResponseStream();
    [System.IO.StreamReader] $sr = New-Object System.IO.StreamReader -argumentList $rs;
    $sr.ReadToEnd();
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接