How do I programmatically stop a teamcity build agent instance after current build? - teamcity

On Teamcity, when I click an agent, I get the "Agent Summary", "Build History", "Compatible Configurations", etc. etc. I can also see the running build and the "Miscellaneous" section, like this one:
I would like to know how I can run the "Stop instance after current build" with the Teamcity API. Does that correspond to deleting the agent or is there something else?

If you want to do it from the build itself, then you can emulate the HTTP request that UI sends when a user clicks the "Stop instance after current build" button

The best way I was advised to follow in order to solve my issue is to define a cloud profile which terminates agents after the first build. To achieve that, in my teamcity project, I have defined (in kotlin DSL):
project {
[...]
features {
feature(ProjectFeature({
type = "CloudProfile"
id = "stop_instance_after_current_build"
// various cloud profile parameters, like
// profileServerUrl, secure:access-id, total-work-time, etc.
// which you find by GETting <teamcity-url>/app/rest/projects/id:<project-id>/projectFeatures/
[...]
// there should be no terminate-idle-time parameter
param("terminate-after-build", true.toString())
})
}
}
With that in place, in a build configuration associated to that project, I do
class SomeBuildConfig() : BuildType({
[...]
requirements {
equals("system.cloud.profile_id", "stop_instance_after_current_build")
}
})
If we don't want to rely on %system.cloud.profile_id%, it is also possible to define a dedicated variable in the agent through the user-script parameter of a ProjectFeature of CloudImage type:
project {
[...]
features {
feature(ProjectFeature({
type = "CloudProfile"
id = "stop_instance_after_current_build"
// as above
[...]
})
feature(ProjectFeature({
type = "CloudImage"
// various parameters like e.g. image-name-prefix, key-pair-name, subnet-id, amazon-id, etc.
[...]
param("profileId", "stop_instance_after_current_build")
param("user-script", userData)
})
}
}
where userData is the content of a script like this:
#! /bin/sh
echo "teamcity.agent.killed_after_current_build=true" >> /home/ubuntu/buildAgent/conf/buildAgent.properties
Then, in a build configuration associated to that project, we can do
requirements {
equals("teamcity.agent.killed_after_current_build", "true")
}

Related

How to include some deps and source codes in Gradle conditionally

In a Maven project, it is easy to add extra deps and include extra source codes via defining a new Maven profile.
How to do the following things in a Gradle project.
Includes extra deps
Includes another source codes directory
And for example, use an extra property existence(eg. add to command line) to decide to activate it or not. I am not sure the best way in Gradle world.
I am not recommending your approach.
But it can be done via - project properties from gradle command line and groovy if (condition) { } for dependencies and multiple sourceset defs
on command line
gradle build -PbProfile=extra1
ext.buildFlag = 'default'
if (project.hasProperty('bProfile')) {
ext.buildFlag = property('bProfile')
}
println "running profile - ${buildFlag}"
dependencies {
//common-deps
if ("extra1".equals(buildFlag)) {
//extra deps
}
}
if ("extra1".equals(buildFlag)) {
//custom sourceset def
} // more else if needed
I use conditionally applied sub-configurations. This is done thru the apply from directive:
if (project.hasProperty('browsers')) {
ext.browsers.split(',').each {
def browser = it.trim()
if (browser) {
apply from: "${browser}Deps.gradle"
}
}
}
This block checks for specification of the browsers property (either from gradle.properties or the -P command line argument). If this property is defined, I split the property's value on commas and apply sub-configurations whose names conform to the pattern <browser>Deps.gradle.
The project in which I use this pattern is here

How do I execute a custom ResourceInitializer

I followed the instructions in the Template repository to create the Resources database. But now I want to use a custom ResourceInitializer to add Resources to the ResourceGraph. (see my code below)
namespace MyApplication.Resources.MyResource
{
[ResourceInitializer(nameof(DummyInitializer))]
public class DummyInitializer : ResourceInitializerBase
{
...
}
}
But when I go into the runtime console and execute exec ResourceManager initialize, the initializer is not shown in the list:
Output in the runtime window
How do I get the runtime to show me the DummyInitializer?
The Initializers you see in the console, are the ones configured in the resource managers initializer collection. In the MaintenanceWeb you can add an entry for your initializer under: http://localhost/maintenanceweb/#/modules/ResourceManager/configuration?path=ModuleConfig/Initializers
or you can add it the underlying config file.
{
"Initializers": [
{
"PluginName": "DummyInitializer"
}
]
}
Alternatively you can execute it using the resource managers console at: http://localhost/maintenanceweb/#/modules/ResourceManager/console
I hope that helps, let me know if you need further help.

Conditional logic in gradle build to only execute certain code when a specific task is running

So, I am using a plugin in my gradle build (the plugin is org.flywaydb.flyway but that is not really relevant). I want to validate the caller has passed in a runtime parameter when tasks from this plugin are executing but not when other tasks are executing.
I pass options to the flyway plugin based on a supplied parameter. I want an error to be returned when a flywayTask is being executed and no parameter is supplied. When a non-flyway task is being run, I do not want to validate if the parameter is supplied.
gradle -PmyParam=myValue flywayMigration
=> should run code and there should be no error
gradle flywayMigration
=> should run code and should produce error (as no parameter supplied)
gradle jar
=> should not run code and no error should be produced
I have been reading about gradle configuration and execution which is fine but I still can't find a way to only run the code when the flyway plugin is bveing executed OR specific flyway tasks are being executed.
This is my current code:
if(gradle.taskGraph.hasTask("flywayMigrate")) {
flyway {
def dbCode, dbUser, dbPassword, dbUrl
if (!project.hasProperty("db_env")) {
throw new GradleException("Expected db_env property to be supplied for migration task. Can be passed" +
" at command line e.g. [gradle -Pdb_env=ex1 flywayMigrate]")
} else {
// do stuff
}
user = balh
password = blah
url = blah
driver = 'oracle.jdbc.OracleDriver'
cleanDisabled = true
baselineOnMigrate = true
baselineVersion = '1.0.0'
}
}
To be clear, I only want this code:
if (!project.hasProperty("db_env")
to run for flyway tasks.
The code above throws this error:
Task information is not available, as this task execution graph has not been populated.
I've tried a few things here, any advice would be appreciated.
It's not really clear to me, what exactly do you want to do in case if this property is provided, but I think, you can do it without accesing task graph, just try to use doFirst Closure of the flywayMigrate task. Just something like this:
flywayMigrate.doFirst {
if(!project.hasProperty("db_env")) {
throw ...
} else {
//Do something
}
}
And leave your plugin configuration free of any additional logic.
As for exception, have you tried to wait until graph is ready? It's usualy done as follows:
gradle.taskGraph.whenReady {taskGraph ->
if(gradle.taskGraph.hasTask("flywayMigrate")) {
...
}
}
Update: to answer the question from the comments
if I can attach doFirst to multiple tasks?
Yes, you can use somthing like:
//declare task names
def names = ["taskA", "taskB", "taskC"]
tasks.findAll {it ->
//filter tasks with names
if (it.name in names)
return it
}.each { it ->
//add some extra logic to it's doFirst closure
it.doFirst {
println 'hello'
}
}
Just check, that all the tasks are exists before this configuration.

Custom conditional configuration for Gradle project

Having an extract from https://github.com/gradle/gradle/blob/master/build.gradle:
ext {
isDevBuild = {
gradle.taskGraph.hasTask(developerBuild)
}
}
task developerBuild {
description = 'Builds distributions and runs pre-checkin checks'
group = 'build'
dependsOn testedDists
}
When I used this approach to create custom configuration in my project I discovered that:
isDevBuild === true
i.e. it's always true because task 'developerBuild' is inside my build.gradle project, and hence in graph. They have a couple of "different" configs (isCIBuild, isCommitBuild, isFinalReleaseBuild, ...) so I suppose I got something wrong here.
Can someone explain how to make this configs conditional based on some external parameter?
taskGraph.hasTask() tells if a task is in the task execution graph, that is whether it will get executed. Because the task execution graph is only created after the configuration phase, this method has to be called from a whenReady callback (or in the execution phase):
gradle.taskGraph.whenReady { graph ->
if (graph.hasTask(developerBuild)) {
// do conditional configuration
}
}
To make this more readable, we can introduce a new method:
def onlyFor(task, config) {
gradle.taskGraph.whenReady { graph ->
if (graph.hasTask(task)) {
project.configure(project, config)
}
}
}
Now we can write:
onlyFor(developerBuild) { ... }
onlyFor(ciBuild) { ... }
Another, simpler way to solve this problem is to check whether a particular task name is contained in gradle.startParameter.taskNames. However, this has two limitations: First, it compares task names, which can make a difference in multi-project builds. Second, it will only find tasks that have been specified directly (e.g. on the command line), but not dependencies thereof.
PS.: In your code, isDevBuild always holds because a (non-null) closure is true according to Groovy truth. (In contrast to isDevBuild(), isDevBuild won't call the closure.)

Environment-specific web.xml in grails?

What's the best way to build environment-specific web.xml entries in grails?
I need to make certain modifications for production only, as they break running locally.
Any thoughts?
You can create scripts/_Events.groovy with an event handler for the 'WebXmlEnd' event which is fired once Grails and the plugins have finished making their changes. Update the XML with plain search/replace or via DOM methods by parsing the XML and write out the updated file:
import grails.util.Environment
eventWebXmlEnd = { String filename ->
if (Environment.current != Environment.PRODUCTION) {
return
}
String content = webXmlFile.text
// update the XML
content = ...
webXmlFile.withWriter { file -> file << content }
}
Here's the solution that's i'm using, from the guy over at death-head.ch
first install the templates
grails install-templates
then customize the web.xml you'll find in src/templates/war/web.xml. I chose to make a web_dev.xml and a web_prod.xml and delete the web.xml. I wanted web_prod.xml to contain a security-constraint block. anyway...
Place the following in BuildConfig.groovy:
// #########################################################
// ## Can't use environment switching block because BuildConfig doesn't support it.
// ## #url http://jira.grails.org/browse/GRAILS-4260
// ## So use this workaround:
// ## #url http://death-head.ch/blog/2010/09/finally-solved-the-base-authentication-in-grails/
// #########################################################
switch ("${System.getProperty('grails.env')}") {
case "development":
if (new File("/${basedir}/src/templates/war/web_dev.xml").exists()) {
grails.config.base.webXml = "file:${basedir}/src/templates/war/web_dev.xml"
}
break;
default:
if (new File("/${basedir}/src/templates/war/web_prod.xml").exists()) {
grails.config.base.webXml = "file:${basedir}/src/templates/war/web_prod.xml"
}
break;
}
Good luck!
I've never tried it, but it should be possible to specify the grails.config.base.webXml parameter in BuildConfig.groovy dependant on the current environment.
There's a list of available BuildConfig settings here
EDIT
Actually, due to this issue, this isn't a way forward :-( Maybe passing the property like:
grails -Dgrails.config.base.webXml=/path/to/web.xml
Is all that's possible?

Resources