One of the biggest complaints I heard during my time in Boston during the 2006 Actuate Users Conference was a lack of information in general on the web pertaining to Actuate Products. I totally agree. Do a search on Google for Apache and you can find hundreds of How-Tos, FAQs, Configuration Examples, Customizations, deployment examples, and just tons of information. Do a search for Actuate, and you will find press releases, and some obscure user forums with unanswered questions. I thought this was odd considering Actuates best of breed reputation and the large turnout at the users conference. I told people I would try my best to get more Actuate focused articles out there, so I was excited when I wrote this article.
For some time now, ever since we started our Actuate Cluster, we have been plagued by a particular issue. Since these are Windows servers, we schedule a weekly reboot. Now while I have heard that the need to reboot Windows servers is a myth, lets just that in practice I have yet to dispel that myth. Even it is a falsehood, it doesn’t seem to cause any harm. The problem here is that when the servers reboot, the child nodes on the cluster do not automatically restart or rejoin the cluster. While that is a pain, we have been fortunate since our cluster only has two nodes. There are others that have much larger nodes, and manually restarting all the nodes can be a big pain. Since this is one of the most requested fixes, I did a little mucking around, and came across some of the undocumented Actuate SOAP calls that will help to solve that little issue. One thing to take note of, because it is undocumented that also means it is unsupported, and they can pull the rug out at any time.
This article will show the source code I used to correct this issue. It demonstrates a couple of different things. First, it shows in Visual Basic .Net 2005 Express, how you can connect to an Actuate 8 SP1 Fix 3 servers SOAP ports and retrieve the exposed web services. It will also demonstrate how a SOAP message can be constructed using the StringBuilder class. Originally I had used the XmlDocument object to manually build, however I removed that big of code to save on sanity and create an easier to manage code base. It will also demonstrate how to use HttpRequest object to send the message, because after all, SOAP is nothing more than XML over HTTP.
First, create a new Console Application from the File/New menu. I called my project ActuateServerRestartConsole.
Once the project has been started, I need to add the Actuate Servers exposed SOAP API. In order to do this, I go up to the Project/Add Web Reference menu. This starts a simple dialog that prompts for a URL. By default, an Actuate 8 will use port 8000 as its exposed SOAP service, and the WSDL file describing the available services is under the /wsdl folder. Since I am connecting to a server called BISSW005, the url will look something like: http://bissw005:8000/wsdl. Once I put this URL in, I get a description page with some various platforms. I chose the Actuate 8, Visual Basic Link to get the exposed services for this version of Actuate that are formatted for VB .Net. One the next page I choose All to get a collection of all the Actuate API’s. Although I only need a few of the API’s, I have had limited success with selecting individual API’s. Once the API list is shown, I click on Add Reference.
Then, I wrote the following program:
Module Module1
'Send a message to the server
Private Function sendMessageToServer(ByVal message As String, ByVal server As String) As String
Dim ht As System.Net.HttpWebRequest
Dim enc As System.Text.Encoding
Dim buffer(4000) As Byte
'We need the enc object to convert Bytes to Strings and the other way around
enc = New System.Text.ASCIIEncoding
'Create our new HTTP Web Request and set the appropriate header information
ht = System.Net.HttpWebRequest.Create(server)
ht.Method = "POST"
ht.ContentType = "text/xml;charset=""utf-8"""
ht.ContentLength = message.Length
ht.Headers.Add("SOAPAction", "")
'Send the request and get the response, and store in the buffer
ht.GetRequestStream.Write(enc.GetBytes(message), 0, message.Length)
ht.GetResponse.GetResponseStream.Read(buffer, 0, 3000)
'Return the result and free memory
sendMessageToServer = enc.GetString(buffer)
enc = Nothing
ht = Nothing
End Function
'Message to bring the server online
Private Function bringOnlineMessage(ByVal servername As String, ByVal authID As String) As String
Dim sb As New System.Text.StringBuilder
'Use a string buffer to build up the string, then return to caller
sb.AppendLine("<?xml version=""1.0"" encoding=""UTF-8""?>")
sb.AppendLine("<SOAP-ENV:Envelope xmlns:SOAP-ENV=""http://schemas.xmlsoap.org/soap/envelope/"" SOAP-ENV:encodingstyle=""http://schemas.xmlsoap.org/soap/encoding"" xmlns:xsd=""http://www.w3.org/2000/10/XMLSchema"" xmlns=""http://schemas.actuate.com/actuate8"" xmlns:SOAP-ENC=""http://schemas.xmlsoap.org/soap/encoding/"">")
sb.AppendLine("<SOAP-ENV:Header>")
sb.AppendLine("<AuthId>" & authID & "</AuthId>")
sb.AppendLine("<Locale>en_US</Locale>")
sb.AppendLine("</SOAP-ENV:Header>")
sb.AppendLine("<SOAP-ENV:Body>")
sb.AppendLine("<SOAP-ACTU:StartServer xmlns:SOAP-ACTU=""http://schemas.actuate.com/actuate8"">")
sb.AppendLine("<ServerName>" & servername & "</ServerName>")
sb.AppendLine("<SystemHeartbeatInformation><UseMulticast>false</UseMulticast></SystemHeartbeatInformation>")
sb.AppendLine("</SOAP-ACTU:StartServer>")
sb.AppendLine("</SOAP-ENV:Body></SOAP-ENV:Envelope>")
bringOnlineMessage = sb.ToString
sb = Nothing
End Function
'Message to bring the server offline
Private Function bringOfflineMessage(ByVal servername As String, ByVal authID As String) As String
Dim sb As New System.Text.StringBuilder
sb.AppendLine("<?xml version=""1.0"" encoding=""UTF-8""?>")
sb.AppendLine("<SOAP-ENV:Envelope xmlns:SOAP-ENV=""http://schemas.xmlsoap.org/soap/envelope/"" SOAP-ENV:encodingstyle=""http://schemas.xmlsoap.org/soap/encoding"" xmlns:xsd=""http://www.w3.org/2000/10/XMLSchema"" xmlns=""http://schemas.actuate.com/actuate8"" xmlns:SOAP-ENC=""http://schemas.xmlsoap.org/soap/encoding/"">")
sb.AppendLine("<SOAP-ENV:Header>")
sb.AppendLine("<AuthId>" & authID & "</AuthId>")
sb.AppendLine("<Locale>en_US</Locale>")
sb.AppendLine("</SOAP-ENV:Header>")
sb.AppendLine("<SOAP-ENV:Body>")
sb.AppendLine("<SOAP-ACTU:StopServer xmlns:SOAP-ACTU=""http://schemas.actuate.com/actuate8"">")
sb.AppendLine("<ServerName>" & servername & "</ServerName>")
sb.AppendLine("<SystemHeartbeatInformation><UseMulticast>false</UseMulticast></SystemHeartbeatInformation>")
sb.AppendLine("</SOAP-ACTU:StopServer>")
sb.AppendLine("</SOAP-ENV:Body></SOAP-ENV:Envelope>")
bringOfflineMessage = sb.ToString
sb = Nothing
End Function
'Login to the Actuate Server and return the AuthID for future calls
Private Function ActuateLogin(ByVal password As String) As String
Dim login As bissw005.SystemLogin
Dim api As bissw005.ActuateAPI
'First thing we need to do is login to the cluster master to get an Auth ID. So login to the cluster
'master, get the authID and free the memory afterwards
login = New bissw005.SystemLogin
login.SystemPassword = "admin"
api = New bissw005.ActuateAPI
'Make the call to login and return the AuthID
ActuateLogin = api.systemLoginOperation(login).AuthId
'Free memory
api = Nothing
login = Nothing
End Function
'Get a list of servers and their current status
Private Function getServerList(ByVal authID As String) As bissw005.ServerInformation()
Dim api As bissw005.ActuateAPI
Dim serverCall As bissw005.GetSystemServerList
'Create an API object, and set the authID so we do not need to re-login
api = New bissw005.ActuateAPI
api.HeaderValue = New bissw005.Header
api.HeaderValue.AuthId = authID
'Get a list of servers and return the array to the caller
serverCall = New bissw005.GetSystemServerList
getServerList = api.getSystemServerListOperation(serverCall).ServerList
'Free memory
serverCall = Nothing
api.HeaderValue = Nothing
api = Nothing
End Function
Sub Main()
'used to store the XMl message and the AuthID once logged in
Dim xm As New System.Xml.XmlDocument
Dim authID As String
'Objects used to get Server List and determine Online/Offline status
Dim serverResponse As bissw005.ServerInformation()
Dim serverInformation As bissw005.ServerInformation
'First thing we need to do is login to the cluster master to get an Auth ID. So login to the cluster
'master, get the authID
Try
authID = ActuateLogin("admin")
Catch ex As Exception
Console.WriteLine("There was an error login into the system")
Exit Sub
End Try
'Get a list of the servers, then go through each server and turn on the server
serverResponse = getServerList(authID)
For Each serverInformation In serverResponse
'Now, with the second request, we need to do something a little different. We need to load the XML
'message to send, then change the AuthID section to our new AuthID. Once completed, then we send off
Console.WriteLine("Status of server " & serverInformation.ServerName & ": " & serverInformation.ServerStatusInformation.ServerState.ToString)
'If there is a command line switch for offline, then turn off child nodes, otherwise, turn them on
If My.Application.CommandLineArgs.Contains("-offline") Then
Try
'Make sure this server is not our master server and that the server is offline
If ((serverInformation.ServerName.ToUpper <> "BISSW005") And (serverInformation.ServerStatusInformation.ServerState = bissw005.ServerState.ONLINE)) Then
xm.InnerXml = bringOfflineMessage(serverInformation.ServerName, authID)
Console.WriteLine("Attempting to bring server " & serverInformation.ServerName & " offline")
Console.WriteLine("Soap Response Message: " & sendMessageToServer(xm.InnerXml, "http://bissw005:8000/").Trim)
End If
Catch ex As Exception
Console.WriteLine(ex.Message)
End Try
Else
Try
'Make sure this server is not our master server and that the server is online
If ((serverInformation.ServerName.ToUpper <> "BISSW005") And (serverInformation.ServerStatusInformation.ServerState = bissw005.ServerState.OFFLINE)) Then
xm.InnerXml = bringOnlineMessage(serverInformation.ServerName, authID)
Console.WriteLine("Attempting to bring server " & serverInformation.ServerName & " online")
Console.WriteLine("Soap Response Message: " & sendMessageToServer(xm.InnerXml, "http://bissw005:8000/").Trim)
End If
Catch ex As Exception
Console.WriteLine(ex.Message)
End Try
End If
Next
'Now, get a list of all the servers and print to the console for any external logging
serverResponse = getServerList(authID)
Console.WriteLine("---------------------------")
Console.WriteLine("Status of servers after run")
For Each serverInformation In serverResponse
Console.WriteLine("Status of server " & serverInformation.ServerName & ": " & serverInformation.ServerStatusInformation.ServerState.ToString)
Next
'Free memory
serverResponse = Nothing
serverInformation = Nothing
xm = Nothing
End Sub
End Module
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment