Select Page

Check if all agents in this environment are online

One annoying thing about AnthillPro is that you need to do a lot of things manually that should already be automatic, leaving you to sift through a sea of beanshell bullsh-t. That being said, when you have an environment that has more then one agent / host in it. You probably don’t want to start a deployment to that environment if one or more of those agents are offline. If you do, you won’t know it till your deployment gets to an action connected to that offline agent. The answer, is to use a beanshell script to check if all agents in this environment (EnvironmentLookup.getCurrent()) are offline. If they are, we stop the deployment immediately. Along with this script, you will need to select a precondition for it that catches some text from commandOutput.println.

import com.urbancode.anthill3.domain.agent.*;
 import com.urbancode.anthill3.services.agent.AgentManager;
 import com.urbancode.anthill3.domain.servergroup.*;
 
 AgentFactory agentFactory = AgentFactory.getInstance();
 // get project environment group and pass to 
 Agent[] agentArray = agentFactory.restoreAll();
 ServerGroup env = ServerGroupFactory.getInstance().restoreForName(EnvironmentLookup.getCurrent().getName()); 
 
 for (z : agentArray){
 	if(env.containsServer(z)){
 		status = AgentManager.getInstance().getAgentStatus(z);
 		if (status == null || !status.isOnline()){
 			commandOutput.println(z.getName() + " is offline");
 		}else{
 			commandOutput.println(z.getName() + " is online");
                }
        }
 }

Urban Deploy – predefined variable list

Urban Deploy is the latest, bleeding-edge deployment tool created by Urban Code, the same creators of Anthill Pro. More information about uDeploy can be found here:
http://www.urbancode.com/html/products/deploy/default.html

Since this is such a new tool, with perhaps about 9 months on the market since the date of this post. There are some features of this tool that are not documented so well. I’ve been working with it, in an attempt to migrate deployment workflows out of Anthill Pro into uDeploy. The primary reason for this is because uDeploy provides something very specific that Anthill Pro does not. The means to connect singular versions of deploy-time components into what is referred to as a ‘snapshot’. Some people call this component based deployment. The general idea is that my application consists of a collection of components, each with their own versions and configurations. I want to be able to change any of these versions of these components and elegantly deploy them to test and see if they are going to work together. I also want to add and remove additional components. In order do this well, you would need to either use uDeploy, get very fancy with AnthillPro (which we’ve done) or write your own mechanism (which I’ve done, but I prefer uDeploy at this point).

As the effort moves forward using uDeploy, we see lots of variables being used in the application. I wanted to have a list of all the predefined vars, and I was luckily able to obtain one, right from the horses mouth. Here it is:

${p:version.name}
${p:version.id}
${p:component.name}
${p:component.id}
${p:resource.name}
${p:resource.id}
${p:application.name}
${p:application.id}
${p:environment.name}
${p:environment.id}

${p:} – Process properties. Defined on the process’s “properties” tab, given values by whoever is running the process.
${p:component/} – Component custom properties, set on the component’s “properties” tab.
${p:environment/} – Environment properties. These come from two places. You can define properties on the component’s properties tab, under the Environment Properties table. You then give values for these on each environment using the component. In addition, you can set custom environment properties on the environment’s properties tab. These custom properties will override the properties coming from components, although it’s recommended to avoid having the same name in both places.
${p:resource/} – Resource properties. This can include the built-in agent properties as well as any custom properties. Each of these have their own tab on the resource.
${p:resource//} – Resource role properties. These are defined on resource roles, and the values are set when you add a role to a resource.
${p:application/} – Global system properties. These are set on the “System Properties” page in the Settings area.

All of the following are comma-separated series of name=value, including each property on the given object.
${p:component/allProperties}
${p:environment/allProperties}
${p:resource/allProperties}
${p:system/allProperties}

One page installation report of any workflow

You can define this as its own job in the “Job Library” folder and include it as a last step of any workflow you want to generate a one page report for. Create a job with one step that does Miscellaneous -> Evaluate Script.

Then, paste in the beanshell script as such:

Now you can include this step in any workflow, and it will create a report in the “Reports” tab of the build-life dashboard called “Installation Report”.

import com.urbancode.anthill3.domain.jobtrace.*;
import com.urbancode.anthill3.domain.workflow.*;
import com.urbancode.anthill3.domain.buildlife.BuildLife;
import com.urbancode.anthill3.domain.buildlife.BuildLifeFactory;
import com.urbancode.anthill3.domain.workflow.*;
import com.urbancode.anthill3.domain.agent.*;

import com.urbancode.anthill3.runtime.*;
import com.urbancode.devilfish.services.*;

import java.io.*;
import java.util.*;
import com.urbancode.commons.fileutils.FileUtils;


private String getStreamAsString(InputStream inStream)
	throws IOException {
	StringBuffer result = new StringBuffer();
	try {
		byte[] buffer = new byte[4096];
		int length = 0;
		while ((length = inStream.read(buffer)) > 0) {
			result.append(new String(buffer, 0, length));
		}
	} finally {
		try {
			inStream.close();
		} catch (Exception e) {
		}
	}
		return result.toString();
}

WorkflowCase workflow = WorkflowLookup.getCurrentCase();
JobTrace[] jobTraces = workflow.getJobTraceArray();
JobTrace jobTrace = JobTraceLookup.getCurrent();
String publishPath = VarService.getInstance().resolve(PublishPathHelper.getInstance().getPublishPath(jobTrace, "Installation Report"));
FileUtils.assertDirectory(publishPath);
File reportFile = new File(publishPath, "installation-report.html");
BufferedWriter writer = new BufferedWriter(new FileWriter(reportFile));

writer.write(
	"\n" + "\n" +"\n" +
	"" +
	"\n" + "\n" + "\n" + "\n" + "\n"
);

for (int j=0; j<jobtraces.length; j++){="" agent="" thisagent="jobTraces[j].getAgent();" writer.write(="" "<tr=""></jobtraces.length;>"
	);
	StepTrace[] stepTraces = jobTraces[j].getStepTraceArray();
	for (int s=0; s<steptraces.length; s++)="" {="" writer.write("="" <tr=""></steptraces.length;>
		");
		
		try{
			CommandTrace cmdTrace = stepTraces[s].getCommandTraceArray()[0];
			FileInfo outputFile = LogPathHelper.getInstance().getLogFileInfoArray(cmdTrace)[0];
			InputStream inStream = FileInfoService.getInstance().getFileInfoAsStream(outputFile);
			String output = getStreamAsString(inStream);
			writer.write(
                                 // change /pr3 to /pre below. Thanks!
				""
			);
		}catch(Exception e) {
			writer.write(
				""
			);
			continue;
		}
	}
}
writer.write("
\n” + ”

Installation Report

\n” + “

JOB NAME: ” + jobTraces[j].name + ”
” + “Agent Name: ” + thisAgent.getName() + ”
Agent Hostname: ” + thisAgent.getHostname() + “
Step:
” + stepTraces[s].getName() + ”
Agent Name: ” + thisAgent.getName() + ”
Agent Hostname: ” + thisAgent.getHostname() + “
" + output + "
NO OUTPUT
"); writer.flush(); writer.close();

You can download the beanshell script here.

Fetching properties from codestation projects to perform component based automated database deployments using AnthillPro

In the case where you have a 3rd party component that does not have its own ability to mange its database changes, along with its incremental deployment. Each database change for the entire life-cycle  of the component should exist as changes which can be referenced by number. A good way to do this is with dbdeploy, where each database change is stored as a file, prefixed by a change number and an underscore like so:

  • 0001_init.sql
  • 0002_add_columns.sql
  • 0003_new_feature.sql
  • etc…

When the dbdeploy task is called, an additional optional property can be passed called: lastChangeToApply which tells dbdeploy up to which version to apply. All that we would need to know at this point is which version of our component goes with which database change and simply assign it as a property to the particular version (stamp) of the codestation component. Here is a test codestation project of version 1.2 where we see that with 1.2 we want to deploy up to database revision 3. To learn more about all the things you can pass to dbdeploy, visit their Google code Wiki site.

 

 

 

 

In your deployment, you will need to have a step that resolves (downloads) this version of this component to some target host in the environment. Just because you perform a “resolve another projects artifacts” step, doesn’t mean you also see the properties set in that codestation project. Therefore, you need to run a quick beanshell script that will allow you to take the db_revision property in the codestation project for that components particular revision, and populate it to a global anthill property that you can use to pass to your dbdeploy task, so it can do something meaningful with it. In order for this to work, we require 2 pieces of information. The COMPONENT_VERSION which is a version that you’ve previously defined of the component we’re deploying. Also the COMPONENT_NAME is the name of the codestation project that contains the property we want. The script will store the value in the anthill property db_revision, this can be addressed inside anthill as ${p:db_revision}. The script also outputs the number to standard output using the commandOutput.println method, for audit purposes. You should simply create project variables, per-environment in the “ALL” tab of your project as COMPONENT_VERSION and COMPONENT_NAME and set them properly. Or, use your own names and change the script as you like below. Once complete, simply be sure to run this step in your deployment job as: Miscellaneous -> Evalulate script.

 

 

 

 

Paste in code:

import com.urbancode.codestation2.domain.buildlife.*;
import com.urbancode.codestation2.domain.project.*;
import com.urbancode.anthill3.runtime.scripting.helpers.*;

String component_version = PropertyLookup.get("COMPONENT_VERSION");
CodestationProject csp = CodestationProjectFactory.getInstance().restoreForName("COMPONENT_NAME");
CodestationBuildLife csbl = CodestationBuildLifeFactory.getInstance().restoreMostRecentForProjectAndStatusAndStampValue(csp,null,component_version);
PropertyLookup.set("db_revision",csbl.getProperty("db_revision").getValue());
commandOutput.println(PropertyLookup.get("db_revision"));

 

 

 

 

 

 

Now that we went through all that, we can pull it all together by having the ability to pass this new information to any script as in this example of an ant task property.

 

 

 

 

 

 

 

 

Home networks beware: Do not use your router as a DNS server.

This is a bit out of context, but I must share…

After months and months of intermittent connectivity loss on random devices and computers on my home network. I’ve finally figured out the problem was that my router was issuing itself as the DNS server.. Never do this. I changed the problem nodes to use google public dns 8.8.8.8 and 8.8.4.4… problem solved. This largely effected PS3, my internet tv and 1 notebook. Maybe this will save someone else the headache.

In my case, I am using one of those Time Warner wide band 50Mb cable modems that act as a router. Some sort of Ubee device. This device does not have the ability to allow you to choose which dns servers are issued in the dhcp request. So weak.