Set variables on task in camunda - business-process-management

Is it possible to set variables to an user task in the camunda definition xml?
I would like to set a variable (deletable), that changes from task to task.
Instance of Task 1: deletable = true
Instance of Task 2: deletable = true
Instance of Task 3: deletable = false
Instance of Task 4: deletable = false
This is the actual task configuration:
<bpmn2:userTask id="createtrunkdoc" camunda:candidateUsers="${candidateUser}" camunda:candidateGroups="provisioning" camunda:assignee="${candidateUser}" name="Create New
Trunk Request">
<bpmn2:incoming>SequenceFlow_1</bpmn2:incoming>
<bpmn2:outgoing>SequenceFlow_3</bpmn2:outgoing>
</bpmn2:userTask>
Test case (camunda: 7.1.0-Final)
#RunWith(MockitoJUnitRunner.class)
public class testTest {
#Rule
public ProcessEngineRule processEngineRule = new ProcessEngineRule();
#Test
#Deployment(resources = { "test.bpmn20.xml" })
public void testHappyPath() {
ProcessInstance processInstance = runtimeService().startProcessInstanceByKey("nipa-createsipinterconnect");
assertThat(processInstance).isStarted().isNotEnded().task().hasDefinitionKey("reviewnewtrunk");
Task task = taskService().createTaskQuery().processInstanceId(processInstance.getId()).singleResult();
assertEquals(true, taskService().getVariable(task.getId(), "deletable"));
}
}
The full XML:
<?xml version="1.0" encoding="UTF-8"?>
<bpmn2:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bpmn2="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:camunda="http://activiti.org/bpmn" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL BPMN20.xsd" id="_1RW-0F22EeOq-_ehbw1S0Q" exporter="camunda modeler" exporterVersion="2.5.0" targetNamespace="http://activiti.org/bpmn">
<bpmn2:collaboration id="_Collaboration_8">
<bpmn2:participant id="nipacreatesipinterconnect" name="Create new SIP Interconnect" processRef="nipa-createsipinterconnect"/>
</bpmn2:collaboration>
<bpmn2:process id="nipa-createsipinterconnect" name="Create new SIP Interconnect" isExecutable="true">
<bpmn2:laneSet id="LaneSet_1" name="Lane Set 1">
<bpmn2:lane id="Lane_1" name="Lane 1">
<bpmn2:flowNodeRef>reviewnewtrunk</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>StartCreateSIPInterconnect</bpmn2:flowNodeRef>
</bpmn2:lane>
</bpmn2:laneSet>
<bpmn2:userTask id="reviewnewtrunk" camunda:candidateGroups="management" camunda:candidateUsers="" name="Review New
Trunk Request">
<bpmn2:extensionElements>
<camunda:inputOutput>
<camunda:inputParameter name="deletable">${true}</camunda:inputParameter>
</camunda:inputOutput>
</bpmn2:extensionElements>
<bpmn2:incoming>SequenceFlow_5</bpmn2:incoming>
</bpmn2:userTask>
<bpmn2:startEvent id="StartCreateSIPInterconnect" name="Describe New
SIP Interconnect
Request">
<bpmn2:outgoing>SequenceFlow_5</bpmn2:outgoing>
</bpmn2:startEvent>
<bpmn2:sequenceFlow id="SequenceFlow_5" name="" sourceRef="StartCreateSIPInterconnect" targetRef="reviewnewtrunk"/>
</bpmn2:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="_Collaboration_8">
<bpmndi:BPMNShape id="_BPMNShape_Participant_12" bpmnElement="nipacreatesipinterconnect" isHorizontal="true">
<dc:Bounds height="333.0" width="1381.0" x="48.0" y="16.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_9" bpmnElement="StartCreateSIPInterconnect">
<dc:Bounds height="36.0" width="36.0" x="228.0" y="154.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="54.0" width="116.0" x="188.0" y="195.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="_BPMNShape_UserTask_22" bpmnElement="reviewnewtrunk">
<dc:Bounds height="80.0" width="157.0" x="516.0" y="132.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="_BPMNShape_Lane_7" bpmnElement="Lane_1" isHorizontal="true">
<dc:Bounds height="333.0" width="1351.0" x="78.0" y="16.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="BPMNEdge_SequenceFlow_5" bpmnElement="SequenceFlow_5" sourceElement="_BPMNShape_StartEvent_9" targetElement="_BPMNShape_UserTask_22">
<di:waypoint xsi:type="dc:Point" x="264.0" y="172.0"/>
<di:waypoint xsi:type="dc:Point" x="516.0" y="172.0"/>
<bpmndi:BPMNLabel>
<dc:Bounds height="6.0" width="6.0" x="291.0" y="172.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn2:definitions>

On versions >= 7.2.0-alpha2
You could use an inputOuput extension element
So something like
<bpmn2:userTask id="createtrunkdoc" camunda:candidateUsers="${candidateUser}" camunda:candidateGroups="provisioning" camunda:assignee="${candidateUser}" name="Create New
Trunk Request">
<extensionElements>
<camunda:inputOutput>
<camunda:inputParameter name="deletable">${true}</camunda:inputParameter>
</camunda:inputOutput>
</extensionElements>
<bpmn2:incoming>SequenceFlow_1</bpmn2:incoming>
<bpmn2:outgoing>SequenceFlow_3</bpmn2:outgoing>
</bpmn2:userTask>
edit:
Assuming you have a process where this is the only task, the following works for me:
ProcessInstance pi = runtimeService.startProcessInstanceByKey("processKey");
Task task = taskService.createTaskQuery().processInstanceId(pi.getId()).singleResult();
assertEquals(true, taskService.getVariable(task.getId(), "deletable"));
Just make sure the task id is correct and be aware that this sets a Boolean value not a String.
On versions < 7.2.0-alpha2
There is no out-of-the-box support for this but you can achive it in the following way:
Create a custom extension element that defines the variable and value to set (or reuse the camunda extension elements like above). Then create a parse listener that parses these extension elements for every task and adds an execution listener to every task that listens for the "start" event. The execution listener can then set the variable that the parse listener provided it with.
For an example of the mechanism of combining parse and execution listener, see https://github.com/camunda/camunda-bpm-examples/tree/master/process-engine-plugin/bpmn-parse-listener

Related

Query Job Information

I was looking at the Onscreen Reference to see if there's an XML request for querying jobs. I found that there's just customer query request CustomerQueryRq and that too doesn't return the child jobs that it has.
Supposing this is how the customers & jobs centre looks like:
- Customer 1
-- Job 1
-- Job 2
-- Job 3
I was able to use CustomerQueryRq and get the details for Customer 1, but couldn't find anything for retrieving Job 1.
So my question is how do I query for a job and get the parent customer it's in? I'd really appreciate any help.
EDIT: Posting my QBXML request:
<?xml version="1.0" encoding="utf-8"?>
<?qbxml version="13.0"?>
<QBXML>
<QBXMLMsgsRq onError="continueOnError">
<CustomerQueryRq requestID="1">
<FullName>Customer name</FullName>
</CustomerQueryRq>
</QBXMLMsgsRq>
</QBXML>
The Customer name has child jobs and I'd like to query those.
ICustomerQuery returns the list of Jobs along with the Customers list. There isn't a separate query object for Jobs. Each job has a customer as a parent. Hence, you can also retrieve the associated customer for the job.
Here's an example: I have a job J1 associated with a customer C1 in my company file. In the below C# code sample, I create a customer query object (using QB SDK 13.0) and iterate over the results. I get two results in the customer list( C1 and J1 ):
using QBXMLRP2Lib;
using Interop.QBFC13;
public class SDKApp
{
private QBSessionManager sessionMgr;
public SDKApp()
{
// in the class constructor - sessionMgr is a member variable
sessionMgr = new QBSessionManager();
}
public void GetData()
{
// open connection and begin session before data fetch - intentionally skipped this code
// during data fetch
IMsgSetRequest msgset = sessionMgr.CreateMsgSetRequest("US", 13, 0);
ICustomerQuery customerQuery = msgset.AppendCustomerQueryRq();
IMsgSetResponse msgRes = sessionMgr.DoRequests(msgset);
IResponseList responseList = msgRes.ResponseList;
if (responseList.Count > 0)
{
IResponse response = responseList.GetAt(0);
ICustomerRetList customerList = response.Detail as ICustomerRetList;
for (int i = 0; i <= customerList.Count - 1; i++)
{
ICustomerRet qbCustomer = customerList.GetAt(i);
string displayName = qbCustomer.Name.GetValue();
string entityType = "Customer";
if (qbCustomer.ParentRef != null)
{
entityType = "Job of " + qbCustomer.ParentRef.FullName.GetValue();
}
Console.WriteLine(displayName + " " + entityType);
}
}
// end session and close connection after data fetch - intentionally skipped this code
}
}

UFT 12.02 QTP integration with TFS

I am looking for UFT and TFS integration (Run test from TFS like we did with HPQC)
I search on google but no help . If anyone know how to do this please let me know steps.
Thanks
You can use Generic Test to call QTP during the testing in TFS. Make sure QTP is installed on the test agent. See the code here for reference:
QTP TFS Generic Test Integration.
One more link for reference: Executing remote QTP scripts via Test Agents and Test Controllers.
Take a look at a solution from OpsHub.
More details:
Announcement:
http://blogs.msdn.com/b/visualstudioalm/archive/2013/05/16/enabling-seamless-integration-with-team-foundation-server-microsoft-test-professional-and-hp-alm-with-opshub-v5-3.aspx
Video:
http://opshub.com/ohrel/Resources/Videos/QTP_MTM_Video/QTP_MTM_Video.mp4
Case study:
https://customers.microsoft.com/Pages/CustomerStory.aspx?recid=17218
Take a look into this code:
import QTObjectModelLib dll from C:\Program Files (x86)\HP\Unified Functional Testing\bin location to your solution.
public void Fn_QTP()
{
qtApp.Launch();
qtApp.Visible = true;
qtApp.Options.Run.RunMode = "Fast";
qtApp.Options.Run.StepExecutionDelay = 0;
qtApp.Options.Run.ViewResults = false;
qtApp.Test.Settings.Run.OnError = "Stop";
//iterate for all test cases under selected module
// oTestSuiteDict : this dictionary conatins all the testsuites from TFS which meant to be executed.
//keys have their ID's
foreach (var item in oTestSuiteDict.Keys)
{
foreach (var TestCase in oTestSuiteDict[item].Keys)
{
Console.WriteLine("Executing TestCase : {0}", TestCase);
//update the XML file and upload in QTP
//this XML file is used to provide the data to QTP as a environment variables.
Fn_UpdateXMLFile(item, TestCase);
//Open the test Case
string scriptPath = #"path of script that will be opened in QTP (Action)";
qtApp.Open(scriptPath, true, false);
// Get a reference to the test object
qtTest = qtApp.Test; // Get reference to test object opened/created by application
qtTest.Settings.Run.OnError = "NextStep";
//check if the library is already associated.
if (qtTest.Settings.Resources.Libraries.Find(#"library path") == 1)
{
qtTest.Settings.Resources.Libraries.RemoveAll();
}
qtTest.Settings.Resources.Libraries.Add(#"Library Path");
//Console.WriteLine("Library is associated with Test");
// Get a reference to the Results Object for test results location
QTObjectModelLib.RunResultsOptions qtRRO = new QTObjectModelLib.RunResultsOptions();
// Run the test
//creates and start the instance of Stopwatch just to track the time period of testcase execution.
Stopwatch stopwatch = Stopwatch.StartNew();
qtTest.Run(qtRRO, true, null); // run the test
stopwatch.Stop();
string oTime = stopwatch.Elapsed.ToString();
oTestCaseTime.Add(TestCase, oTime);
string ostatus = qtTest.LastRunResults.Status;
oResults.Add(TestCase, ostatus);
qtTest.Close(); // Close the test
}
}
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(qtTest); // Cleanly release COM object
qtTest = null; // set object to null
//break;
//qtApp.Quit(); // Quit QTP
GC.Collect(); // Garbage collect
GC.WaitForPendingFinalizers(); // Wait for GC
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(qtApp); // Cleanly release COM Object
qtApp = null; // set to null
}
// Fn_UpdateXMLFile : function to update environment variables for qtp
//module name : the testsuite name(contains list of testcases); testcasename : testcases listed in modulename(test suite)
public void Fn_UpdateXMLFile(string modulename,string testcasename)
{
string oPath = #"path of xml file";
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(oPath);
XmlNodeList nodes = xmlDoc.SelectNodes("Environment/Variable/Value");
nodes[0].InnerText = modulename;
nodes[1].InnerText = testcasename;
xmlDoc.Save(oPath);
}
//format of XML file :
<Environment>
<Variable>
<Name>ModuleName</Name>
<Value>ToolsMenu</Value>
</Variable>
<Variable>
<Name>""</Name>
<Value>""</Value>
</Variable>
</Environment>

AutoUpdate of AIR application

I am learning Auto-update feature of AIR application. I created simple application which is not working. code is below:
AutoUpdate.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
creationComplete="checkForUpdate()" >
<fx:Script><![CDATA[
import air.update.ApplicationUpdaterUI;
import air.update.events.UpdateEvent;
private var appUpdater:ApplicationUpdaterUI=new ApplicationUpdaterUI();
private function checkForUpdate():void
{
setApplicationVersion();
appUpdater.delay = 1;
appUpdater.isDownloadProgressVisible = true;
appUpdater.isDownloadUpdateVisible = true
appUpdater.isInstallUpdateVisible = true;
appUpdater.isFileUpdateVisible = true;
appUpdater.updateURL = "http://localhost:8081/DynamicWeb/release/update.xml";
appUpdater.isCheckForUpdateVisible = false;
appUpdater.addEventListener(UpdateEvent.INITIALIZED, onUpdate);
appUpdater.addEventListener(ErrorEvent.ERROR, onError);
appUpdater.initialize();
}
}
// Find the current version for our Label below
private function setApplicationVersion():void
{
var appXML:XML = NativeApplication.nativeApplication.applicationDescriptor;
var ns:Namespace = appXML.namespace();
lbl.text = "Current version is " + appXML.ns::version;
//Common.helpDetails = appXML.ns::versionLabel;
}
private function onError(event:ErrorEvent):void
{
//Alert.show(event.toString());
}
private function onUpdate(event:UpdateEvent):void
{
appUpdater.checkNow(); // Go check for an update now }
}
]]></fx:Script>
<s:HGroup x="89" y="124" width="413" height="34">
<s:Label id="lbl" />
</s:HGroup>
</s:WindowedApplication>
*Initially in AutoUpdate-app.xml and update.xml file version tag is set to 1.0.0
* server side update.xml file is :
<?xml version="1.0" encoding="UTF-8"?>
<update xmlns="http://ns.adobe.com/air/framework/update/description/1.0">
<version>1.0.0</version>
<url>http://localhost:8081/DynamicWeb/release/Update_air.air</url>
<description><![CDATA[
Typically, this is used to summarize what's new in the release
]]></description>
</update>
Now I have exported application and installed it. After that i changed version on both file AutoUpdate-app.mxml and update.xml(server side) to 2.0.0 . Now i exported the application and dumped it to server (in 'release' folder where update.xml is there.).
Now when i launch the application , Update feature is not working. Its nothing happening.
CheckNow() method is called but doing nothing. Please help me.
I am working on AIR 3.1
Its not giving any kind of error. Only Updation Window is not working.
Please tell me what i m doing wrong. Thanks.
1) trace real version and from update.xml and be sure you did it correct. You must be sure you run old app with 1.0.0 version. BTW, you can use property ApplicationUpdaterUI.currentVersion instead of NativeApplication.nativeApplication.applicationDescriptor
2) You do not listen events after checkNow() calling. Listen all events, like in this article. In
http://thanksmister.com/2009/09/13/custom-air-updater-interface-using-applicationupdater/ (see UpdateManager.as#initialize()):
appUpdater.addEventListener(UpdateEvent.INITIALIZED, updaterEvent);
appUpdater.addEventListener(StatusUpdateEvent.UPDATE_STATUS, updaterEvent);
appUpdater.addEventListener(UpdateEvent.BEFORE_INSTALL, updaterEvent);
appUpdater.addEventListener(StatusUpdateErrorEvent.UPDATE_ERROR, updaterEvent);
appUpdater.addEventListener(UpdateEvent.DOWNLOAD_START, updaterEvent);
appUpdater.addEventListener(ProgressEvent.PROGRESS, updaterEvent);
appUpdater.addEventListener(UpdateEvent.DOWNLOAD_COMPLETE, updaterEvent);
appUpdater.addEventListener(DownloadErrorEvent.DOWNLOAD_ERROR, updaterEvent);
appUpdater.addEventListener(ErrorEvent.ERROR, updaterEvent);
private function updaterEvent(event : Event) : void {
trace(event.type);
}
possible, you missed some thing...
in your server side update.xml you should replace the tag version with versionNumber.
This changed since AIR 2.5.

how can i automate calling a url on a password protected asp.net-mvc site

i have an asp.net-mvc site with sqlserver backend and i am using membershipprovider for login, etc.
I have a few automated things that i want to run daily or weekly as i can do this today if i:
Log In
call URL
so lets say the URL is
www.mysite.com/MyController/RunCleanupScript
I know some people will suggest breaking the code of RunCleanupScript into a standalone script outside of the website but i wanted to see if there was a solution to automating the equivalent to the manual login and then entering in this url to call this script?
Phil Haak has a post about a solution which may work for you - he also warns of the dangers associated. You could use this method to schedule the clean up task. If you move your clean-up code out of the controller then there is no need for the login - it can never be called externally. If you need to still be able to login and force the clean up, then moving the clean up code out of your controller is still the way to go. Your secured action and the scheduler code will both call the clean-up code.
Another option could be to create a windows service that hits the action and stores the required credentials in its config file.
Forms auth together with some scripts calling web pages to aquire a cookie may not be the most stable and maintainable approach for your requirements.
You could support basic auth that makes passing username and password from a script easy. For an example how to implement basic auth in asp.net mvc see this blog post.
You could write a console application which will perform 2 HTTP requests: first to login and second to fetch the protected resource:
using System;
using System.Collections.Specialized;
using System.Net;
public class WebClientEx: WebClient
{
private readonly CookieContainer _cookieContainer = new CookieContainer();
protected override WebRequest GetWebRequest(Uri address)
{
var request = base.GetWebRequest(address);
((HttpWebRequest)request).CookieContainer = _cookieContainer;
return request;
}
}
class Program
{
static void Main()
{
using (var client = new WebClientEx())
{
var values = new NameValueCollection
{
{ "username", "user" },
{ "password", "pwd" },
};
// Login
client.UploadValues("http://example.com/account/logon", values);
// Fetch the protected resource
var result = client.DownloadString("http://example.com/home/foo");
Console.WriteLine(result);
}
}
}
This code will login to a FormsAuthentication site, then use the AUTH cookie to hit any other URL on the site...
string appURL = "https://.../LogOn";
// UserName and Password should match the names of the inputs on your form
string strPostData = String.Format("UserName={0}&Password={1}", "login", "pass");
Cookie authCookie;
CookieContainer cookieJar = new CookieContainer();
// Prepare post to the login form
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(appURL);
req.Method = "POST";
req.ContentLength = strPostData.Length;
req.ContentType = "application/x-www-form-urlencoded";
req.CookieContainer = cookieJar;
req.AutomaticDecompression = DecompressionMethods.GZip
| DecompressionMethods.Deflate;
// Proxy - Optional
// req.Proxy.Credentials = CredentialCache.DefaultCredentials;
// Post to the login form.
StreamWriter swRequestWriter = new StreamWriter(req.GetRequestStream());
swRequestWriter.Write(strPostData);
swRequestWriter.Close();
// Get the response.
HttpWebResponse hwrWebResponse = (HttpWebResponse)req.GetResponse();
// Store the required AUTH cookie
authCookie = cookieJar.GetCookies(new Uri("... your cookie uri ..."))[".ASPXAUTH"];
Now you can access any other URL of the site using the AUTH cookie.
HttpWebRequest req = (HttpWebRequest)WebRequest.Create("... url ...");
req.CookieContainer.Add(new System.Net.Cookie(authCookie.Name,
authCookie.Value,
authCookie.Path, "localhost"));
HttpWebResponse resp = (HttpWebResponse) req.GetResponse();
PowerShell might be a good option for you. Here's a sample that demonstrates how you would post form values to the log-on page and then use the response cookie to make a second call to the admin page.
Note, I borrowed much of this sample from this post.
$LogonUrl = "http://yoursite.com/Account/LogOn"
$UserName = "AdminUser"
$Password = "pass#word1"
$AdminUrl = "http://yoursite.com/MyController/RunCleanupScript"
$cookies = New-Object System.Net.CookieContainer
$formData = "UserName=" + $UserName + "&Password=" + $Password
[net.httpWebRequest] $web1 = [net.webRequest]::create($LogonUrl)
$web1.method = "POST"
$web1.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
$web1.Headers.Add("Accept-Language: en-US")
$web1.Headers.Add("Accept-Encoding: gzip,deflate")
$web1.Headers.Add("Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7")
$web1.AllowAutoRedirect = $false
$web1.ContentType = "application/x-www-form-urlencoded"
$buffer = [text.encoding]::ascii.getbytes($formData)
$web1.ContentLength = $buffer.length
$web1.TimeOut = 50000
$web1.KeepAlive = $true
$web1.Headers.Add("Keep-Alive: 300");
$web1.CookieContainer = $CookieContainer
$reqStrm = $web1.getRequestStream()
$reqStrm.write($buffer, 0, $buffer.length)
$reqStrm.flush()
$reqStrm.close()
[net.httpWebResponse] $response = $web1.getResponse()
$respStrm = $response.getResponseStream()
$reader = new-object IO.StreamReader($respStrm)
$result = $reader.ReadToEnd()
$response.close()
$web2 = new-object net.webclient
$web2.Headers.add("Cookie", $response.Headers["Set-Cookie"])
$result = $web2.DownloadString("$AdminUrl")
Write-Output $result
This could also easily be turned into a Windows Console app as well. Either way, they are easy to schedule with Task Scheduler.
Hope this helps.
Why don't you give WatiN or Selenium a try? You can set up a login step very easy and then test if the other RunCleanupScript page is working properly.
WatiN's main page example:
[Test]
public void SearchForWatiNOnGoogle()
{
using (var browser = new IE("http://www.google.com"))
{
browser.TextField(Find.ByName("q")).TypeText("WatiN");
browser.Button(Find.ByName("btnG")).Click();
Assert.IsTrue(browser.ContainsText("WatiN"));
}
}
You can then have something like:
[Test]
public void TestRunCleanupScript()
{
using (var browser = new IE("www.mysite.com/MyController/RunCleanupScript"))
{
DoLogin(browser)
//navigate to cleanupscript page
//your assert
}
}
public void DoLogin(browser)
{
//navigate to login
//type username and password and hit button
}
I am currently doing this in a production environment. In my case the solution was a no-brainer since MADAM had already been installed in order to allow normal RSS Readers to securely access RSS feeds on the site.
The trick to doing this is to enable Basic Authentication for the pages you want to call automatically using any external processes, that opens you up to a huge number of ways to access the site automatically; this VBScript file, for instance calls the maintenance URL and checks whether the response from the server is exactly SUCCESS.
Option Explicit
Dim result
result = PerformMaintenance("http://www.mysite.com/MyController/RunCleanupScript")
WScript.Quit(result)
Function PerformMaintenance(URL)
Dim objRequest
Set objRequest = CreateObject("Microsoft.XmlHttp")
'I use a POST request because strictly speaking a GET shouldn't change anything on the server.
objRequest.open "POST", URL, false, "LimitedDaemonUser", "SecretDaemonPassword"
objRequest.Send
if (objRequest.ResponseText = "SUCCESS") Then
PerformMaintenance = 0
Else
PerformMaintenance = 1
End If
set objRequest = Nothing
End Function
Basic Authentication is easy enough to get working. Just include MADAM with your project, and configure it in your Web.config.
Adding these Web.config sections/parameters (IIS6) should get your example request working if you use a standard MembershipProvider. You just have to change MyNamespace.MembershipUserSecurityAuthority to a reference to an actual class. The source code for MembershipUserSecurityAuthority is included with MADAM in the demo web application's App_Code folder.
<configuration>
<configSections>
<sectionGroup name="madam">
<section name="userSecurityAuthority" type="System.Configuration.SingleTagSectionHandler, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<section name="formsAuthenticationDisposition" type="Madam.FormsAuthenticationDispositionSectionHandler, Madam" />
</sectionGroup>
</configSections>
<madam>
<userSecurityAuthority realm="MyRealm" provider="MyNamespace.MembershipUserSecurityAuthority, MyNamespace" />
<formsAuthenticationDisposition>
<discriminators all="false">
<discriminator inputExpression="Request.AppRelativeCurrentExecutionFilePath" pattern="~/MyController/RunCleanupScript$" type="Madam.RegexDiscriminator, Madam" />
</discriminators>
</formsAuthenticationDisposition>
</madam>
<system.web>
<httpModules>
<add name="FormsAuthenticationDisposition" type="Madam.FormsAuthenticationDispositionModule, Madam" />
<add name="AuthenticationModule" type="Madam.BasicAuthenticationModule, Madam" />
</httpModules>
</system.web>
</configuration>

Best way to delete messages from SQS during development

During development, I'm generating a lot of bogus messages on my Amazon SQS. I was about to write a tiny app to delete all the messages (something I do frequently during development). Does anyone know of a tool to purge the queue?
If you don't want to write script or delete your queue. You can change the queue configuration:
Right click on queue > configure queue
Change Message Retention period to 1 minute (the minimum time it can be set to).
Wait a while for all the messages to disappear.
I found that this way works well for deleting all messages in a queue without deleting the queue.
As of December 2014, the sqs console now has a purge queue option in the queue actions menu.
For anyone who has come here, looking for a way to delete SQS messages en masse in C#...
//C# Console app which deletes all messages from a specified queue
//AWS .NET library required.
using System;
using System.Net;
using System.Configuration;
using System.Collections.Specialized;
using System.IO;
using System.Linq;
using System.Text;
using Amazon;
using Amazon.SQS;
using Amazon.SQS.Model;
using System.Timers;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Diagnostics;
namespace QueueDeleter
{
class Program
{
public static System.Timers.Timer myTimer;
static NameValueCollection appConfig = ConfigurationManager.AppSettings;
static string accessKeyID = appConfig["AWSAccessKey"];
static string secretAccessKeyID = appConfig["AWSSecretKey"];
static private AmazonSQS sqs;
static string myQueueUrl = "https://queue.amazonaws.com/1640634564530223/myQueueUrl";
public static String messageReceiptHandle;
public static void Main(string[] args)
{
sqs = AWSClientFactory.CreateAmazonSQSClient(accessKeyID, secretAccessKeyID);
myTimer = new System.Timers.Timer();
myTimer.Interval = 10;
myTimer.Elapsed += new ElapsedEventHandler(checkQueue);
myTimer.AutoReset = true;
myTimer.Start();
Console.Read();
}
static void checkQueue(object source, ElapsedEventArgs e)
{
myTimer.Stop();
ReceiveMessageRequest receiveMessageRequest = new ReceiveMessageRequest();
receiveMessageRequest.QueueUrl = myQueueUrl;
ReceiveMessageResponse receiveMessageResponse = sqs.ReceiveMessage(receiveMessageRequest);
if (receiveMessageResponse.IsSetReceiveMessageResult())
{
ReceiveMessageResult receiveMessageResult = receiveMessageResponse.ReceiveMessageResult;
if (receiveMessageResult.Message.Count < 1)
{
Console.WriteLine("Can't find any visible messages.");
myTimer.Start();
return;
}
foreach (Message message in receiveMessageResult.Message)
{
Console.WriteLine("Printing received message.\n");
messageReceiptHandle = message.ReceiptHandle;
Console.WriteLine("Message Body:");
if (message.IsSetBody())
{
Console.WriteLine(" Body: {0}", message.Body);
}
sqs.DeleteMessage(new DeleteMessageRequest().WithQueueUrl(myQueueUrl).WithReceiptHandle(messageReceiptHandle));
}
}
else
{
Console.WriteLine("No new messages.");
}
myTimer.Start();
}
}
}
Check the first item in queue. Scroll down to last item in queue.
Hold shift, click on item. All will be selected.
I think the best way would be to delete the queue and create it again, just 2 requests.
I think best way is changing Retention period to 1 minute, but here is Python code if someone needs:
#!/usr/bin/python
# -*- coding: utf-8 -*-
import boto.sqs
from boto.sqs.message import Message
import time
import os
startTime = program_start_time = time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime())
### Lets connect to SQS:
qcon = boto.sqs.connect_to_region(region,aws_access_key_id='xxx',aws_secret_access_key='xxx')
SHQueue = qcon.get_queue('SQS')
m = Message()
### Read file and write to SQS
counter = 0
while counter < 1000: ## For deleting 1000*10 items, change to True if you want delete all
links = SHQueue.get_messages(10)
for link in links:
m = link
SHQueue.delete_message(m)
counter += 1
#### The End
print "\n\nTerminating...\n"
print "Start: ", program_start_time
print "End time: ", time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime())
Option 1: boto sqs has a purge_queue method for python:
purge_queue(queue)
Purge all messages in an SQS Queue.
Parameters: queue (A Queue object) – The SQS queue to be purged
Return type: bool
Returns: True if the command succeeded, False otherwise
Source: http://boto.readthedocs.org/en/latest/ref/sqs.html
Code that works for me:
conn = boto.sqs.connect_to_region('us-east-1',
aws_access_key_id=AWS_ACCESS_KEY_ID,
aws_secret_access_key=AWS_SECRET_ACCESS_KEY,
)
q = conn.create_queue("blah")
#add some messages here
#invoke the purge_queue method of the conn, and pass in the
#queue to purge.
conn.purge_queue(self.queue)
For me, it deleted the queue. However, Amazon SQS only lets you run this once every 60 seconds. So I had to use the secondary solution below:
Option 2: Do a purge by consuming all messages in a while loop and throwing them out:
all_messages = []
rs = self.queue.get_messages(10)
while len(rs) > 0:
all_messages.extend(rs)
rs = self.queue.get_messages(10)
If you have access to the AWS console, you can purge a queue using the Web UI.
Steps:
Navigate to Services -> SQS
Filter queues by your "QUEUE_NAME"
Right-click on your queue name -> Purge queue
This will request for the queue to be cleared and this should be completed with 5 or 10 seconds or so.
See below for how to perform this operation:
To purge an SQS from the API see:
https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_PurgeQueue.html

Resources