module.exports = (robot) ->
robot.respond /log (.*)/i, (msg) ->
group = "test"
incident_message = msg.match[0]
service_key = keys[group]
curtime = new Date().getTime()
incident_key = "hubot/#{curtime}"
reporter = msg.message.user.name
query = {
"service_key": service_key,
"incident_key": incident_key,
"event_type": "trigger",
"description": "Change Log #{reporter}",
"details": "#{incident_message}"
}
string_query = JSON.stringify(query)
content_length = string_query.length
msg
.http("https://events.pagerduty.com/generic/2010-04-15/create_event.json")
.headers
"Content-type": "application/json",
"Content-length": content_length
.post(string_query) (err, res, body) ->
result = JSON.parse(body)
if result.status == "success"
msg.send "Your log has been sent"
else
msg.send "There was an error sending your log."
msg
.http("https://xyz.pagerduty.com/api/v1/incidents/#{incident_key}/acknowledge")
I am trying to auto acknowledge an event triggered in pagerduty. The first http request takes effect. But the second http request (last line of the code) never takes effect. I have tried varipus combinations. But it does not help. I am new to coffeescript and only use it for hubot.Can anyone help me ?
First, you don't specify what HTTP action you are doing:
msg.http("https://xyz.pagerduty.com/api/v1/incidents/#{incident_key}/acknowledge")
Should end with .get() or .post().
Also, possibly due to bad paste, your indentation if off a bit in the middle:
.post(string_query) (err, res, body) ->
result = JSON.parse(body)
if result.status == "success"
msg.send "Your log has been sent"
else
msg.send "There was an error sending your log."
Should be:
.post(string_query) (err, res, body) ->
result = JSON.parse(body)
if result.status == "success"
msg.send "Your log has been sent"
else
msg.send "There was an error sending your log."
Another thing, due to nature of NodeJS, these HTTP calls are made asynchronously, and there is a good chance that second call finishes before first one does. To avoid that, run the second request from callback of the first one:
msg
.http("https://events.pagerduty.com/generic/2010-04-15/create_event.json")
.headers
"Content-type": "application/json",
"Content-length": content_length
.post(string_query) (err, res, body) ->
result = JSON.parse(body)
if result.status == "success"
msg.send "Your log has been sent"
msg
.http("https://xyz.pagerduty.com/api/v1/incidents/#{incident_key}/acknowledge")
.get()
else
msg.send "There was an error sending your log."
You can find some examples of Hubot HTTP requests and other scripting tricks here.
Related
I've been having issues trying to get my hubot instance to perform an http request while in a callback from a http listener. My guess is that it is in the middle of a req/res cycle and unable to complete a different request. Usually the robot object has the http method that allows for sending one, but I keep getting "TypeError: Cannot read property 'on' of undefined" In other hubot examples I've seen online, they refer to the use of the response object, but that is only the case inside of a chat listener and indeed when I attempt to use the response object it throws an error, "TypeError: res.http is not a function". Any help is much appreciated. Thanks!
robot.router.post '/gitlab-incoming', (req, res) ->
data = {
"request_type": req.body.object_kind,
"status": req.body.object_attributes.state,
"project_name": req.body.object_attributes.source.name,
"branch_name": req.body.object_attributes.source_branch,
"job_name": 'review_stop',
"team_name": process.env.GITLAB_TEAM_NAME,
"gitlab_ci_token": process.env.GITLAB_CI_TOKEN,
"action": 'play',
"project_id": "#{process.env.GITLAB_TEAM_NAME}%2F#{req.body.object_attributes.source.name}"
}
if data['status'] == 'merged'
robot.http("https://gitlab.com/api/v4/projects/#{data['project_id']}/jobs")
.header('Accept', 'application/json')
.header('PRIVATE-TOKEN', data['gitlab_ci_token'])
.get() (err, http_res, body) ->
if err
res.send 'Sorry. Unable to fetch the list of jobs from Gitlab'
job_found = false
job_id = undefined
I try to do a client-server application with on the client side a Angular2/typescript web site and on the server side a Kitura server in Swift on Mac OSX.
On the client side, the typescript code instanciates an EventSource object :
this.eventSource = new EventSource(this.webSocketServerUrl);
this.eventSource.onopen = (event: Event): any => {
console.log("ServerNotificationsService.onopen - " + JSON.stringify(event) + " " + this.eventSource.readyState);
event.stopPropagation();
return null;
}
this.eventSource.onerror = (event: sse.IOnMessageEvent) => {
console.log("ServerNotificationsService.onerror - " + JSON.stringify(event) + " " + this.eventSource.readyState);
}
this.eventSource.onmessage = (event: Event): any => {
console.log("ServerNotificationsService.onmessage - " + JSON.stringify(event) + " " + this.eventSource.readyState);
event.stopPropagation();
return null;
}
console.log("ServerNotificationsService.constructor - " + this.eventSource.readyState);
On the server side, my code to handle the GET request looks like this :
router.get("/notifications") { request, response, next in
response.headers.append("Access-Control-Allow-Origin", value: "*")
if((request.accepts(header: "Accept", type: "text/event-stream")) != nil)
{
response.headers.append("content-type", value: "text/event-stream; charset=utf-8")
response.headers.append("cache-control", value: "no-cache")
response.headers.append("connection", value: "keep-alive")
try response.end()
Logger.sharedInstance.verbose(msg: "Request GET /notifications OK")
}
else
{
try response.status(.internalServerError).end()
Logger.sharedInstance.verbose(msg: "Request GET /notifications internalServerError")
}
next()
}
and to handle the post request :
router.post("/notifications") { request, response, next in
Logger.sharedInstance.verbose(msg: "Request POST /notifications ...")
response.headers.append("Access-Control-Allow-Origin", value: "*")
response.headers.append("content-type", value: "text/event-stream; charset=utf-8")
response.headers.append("cache-control", value: "no-cache")
response.headers.append("connection", value: "keep-alive")
while (true)
{
// wait here 5s. for the <nextMessage>
response.send(<nextMessage>)
try response.end()
Logger.sharedInstance.verbose(msg: "Request POST /notifications OK")
next()
}
}
The problem is that on the client side I receive the onopen notification, the event source's readyState pass to "Open" (1) but I receive immediately after a onerror notification and the readyState pass to "Connecting" (0). And so on : connecting, close, connecting, close, ... And in consequence the post request is never executed.
I will appreciate some help to have a code that maintains an open connexion.
Thank you,
Notux
Kitura does not currently support persistent, open HTTP connections. However, you might be able to replicate the functionality using WebSocket instead of server-sent events over HTTP (you will need to rewrite your frontend code to use WebSockets instead of EventSource):
https://github.com/IBM-Swift/Kitura-WebSocket
And example Kitura-WebSocket app can be found here:
https://github.com/IBM-Swift/Kitura-Chat-Server
Been trying to write a pebble app for wemo switches, currently this is the code i'm using:
function WemoRequest(callback) {
if (SOAPData === false || SOAPData === undefined) {
console.log("Invalid SOAP data: " + JSON.stringify(SOAPData));
return;
}
var url = "http://192.168.1.230:49153/upnp/control/basicevent1";
try {
var request = new XMLHttpRequest();
request.open("POST", url, false);
request.setRequestHeader("SOAPAction", "urn:Belkin:service:basicevent:1#GetBinaryState");
request.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
request.onreadystatechange = function() {
if (request.readyState == 4 && request.status === 200 && callback) {
callback(request, SOAPData);
}else{console.log("Status: "+request.status + " State: "+request.readyState+" Callback: "+callback);}
};
var packet = '<?xml version="1.0" encoding="utf-8"?>'+
'<s:Envelope xmls:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">'+
'<s:Body>'+
'<u:GetBinaryState xmlns:u="urn:Belkin:service:basicevent:1"></u:GetBinaryState>'+
'</s:Body>'+
'</s:Envelope>';
request.send(packet);
} catch (error) {
console.log("Error in XMLHttpRequest: " + error);
}}
I currently get status 500 from OnReadyStateChange and have no idea what I'm doing wrong. If this isn't enough code, app code is available here:https://github.com/dmf444/Webble
So...I know this is from 4 years ago lol, but I found this during a google search and just found the answer, so I figured I would respond for that reason: I think your header just needs an extra set of quotes around "urn:Belkin:service:basicevent:1#SetBinaryState" so that the string specifying the soapaction literally starts and ends with quotes.
I'm working in Python (because that's what all the kids seem to be doing these days), but I too was getting the 500 error until I made a very subtle change (the single quote marks around my double quotes) and almost cried tears of joy when my light turned off:
"SOAPACTION": '"urn:Belkin:service:basicevent:1#SetBinaryState"'
So here's the working version of the code (in Python lol):
import http.client
#Variables (value=on/off, ipaddress=address of your wemo)
value = 0 #1=ON, 0=OFF
ipAddress = "192.168.0.108"
#Build the SOAP Envelope (data)
data = '<?xml version="1.0" encoding="utf-8"?><s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:SetBinaryState xmlns:u="urn:Belkin:service:basicevent:1"><BinaryState>' + str(value) + '</BinaryState></u:SetBinaryState></s:Body></s:Envelope>'
#Build the Header (headers)
headers = {"Content-type" : 'text/xml; charset="utf-8"', "SOAPACTION": '"urn:Belkin:service:basicevent:1#SetBinaryState"', "Content-Length": len(data)}
#Send request and check response data (resp_data)
conn = http.client.HTTPConnection(ipAddress, 49153)
conn.request("POST", "/upnp/control/basicevent1", data, headers)
response = conn.getresponse()
resp_data = response.read()
if response.status == 200:
conn.close()
print("SUCCESS!")
elif response.status == 403:
print("ERROR: 403 (FORBIDDEN)")
else:
print("ERROR: " + str(response.status))
Having never worked with coffescript before, I'm trying to update the hubot script for jenkins integration. In a nutshell I want to call jenkins, get a result from that call and use it in a subsequent call. Based on the existing code in the hubot script I've added the following function:
jenkinsCrumb = (msg) ->
url = process.env.HUBOT_JENKINS_URL
path = "#{url}/crumbIssuer/api/json"
req = msg.http(path)
if process.env.HUBOT_JENKINS_AUTH
auth = new Buffer(process.env.HUBOT_JENKINS_AUTH).toString('base64')
req.headers Authorization: "Basic #{auth}"
req.get() (err, res, body) ->
if err
msg.reply "Jenkins says: #{err}"
else if 200 <= res.statusCode < 400 # Or, not an error code.
msg.reply "#{body}"
body
else if 404 == res.statusCode
msg.reply "Unable to fetch crumb from Jenkins..."
else
msg.reply "Jenkins says: Status #{res.statusCode} #{body}"
When this function is called, the value I want is reported in the variable body. The call to msg.reply properly displays the value in the hubot chat window.
What I would like to do, but can't figure out, is how to have this function return the value of body? I've tried explicitly returning the value of req.get() but it seems that it's returning the full request object.
You can do that by simply adding return body or just body (because of CoffeeScript) to the end of your anonymous function:
jenkinsCrumb = (msg, callback) ->
url = process.env.HUBOT_JENKINS_URL
path = "#{url}/crumbIssuer/api/json"
req = msg.http(path)
if process.env.HUBOT_JENKINS_AUTH
auth = new Buffer(process.env.HUBOT_JENKINS_AUTH).toString('base64')
req.headers Authorization: "Basic #{auth}"
req.get() (err, res, body) ->
if err
msg.reply "Jenkins says: #{err}"
else if 200 <= res.statusCode < 400 # Or, not an error code.
msg.reply "#{body}"
body
else if 404 == res.statusCode
msg.reply "Unable to fetch crumb from Jenkins..."
else
msg.reply "Jenkins says: Status #{res.statusCode} #{body}"
# critical part
callback(body)
I'm trying to use Hubot to merge a pull request for a specified repository, but I get a response object like this: { message: 'Not Found', documentation_url: 'https://developer.github.com/v3' }.
Here is my code, with the sha removed:
module.exports = (robot) ->
robot.respond /deploy pr (.*) in (.*)/i, (res) ->
prNumber = res.match[1]
repo = res.match[2]
owner = process.env.HUBOT_GITHUB_OWNER
base_url = process.env.HUBOT_GITHUB_API || 'https://api.github.com'
mergeUrl = "#{base_url}/repos/#{owner}/#{repo}/pulls/#{prNumber}/merge"
data =
commit_message: "Merged pull request #{prNumber} into #{repo}",
sha: "my-sha-here"
stringData = JSON.stringify data
res.http(mergeUrl)
.put(stringData) (err, response, body) ->
if err
res.send "Error: #{err}"
else
parsedBody = JSON.parse(body)
res.send parsedBody.message
Not sure what I'm doing wrong. I think my auth is set up correctly, as I'm able to make a call with the github api to list all open pull requests for a specified repository.
I realized I wasn't passing my auth token, as I was previously using a library that did it for me. You can do it in a header like this:
module.exports = (robot) ->
robot.respond /deploy pr (.*) in (.*)/i, (res) ->
prNumber = res.match[1]
repo = res.match[2]
owner = process.env.HUBOT_GITHUB_OWNER
base_url = process.env.HUBOT_GITHUB_API || 'https://api.github.com'
mergeUrl = "#{base_url}/repos/#{owner}/#{repo}/pulls/#{prNumber}/merge"
data =
commit_message: "Merged pull request #{prNumber} into #{repo}",
sha: "my-sha-here"
stringData = JSON.stringify data
res.http(mergeUrl)
.header("Authorization", "token #{your-auth-token}")
.put(stringData) (err, response, body) ->
if err
res.send "Error: #{err}"
else
parsedBody = JSON.parse(body)
res.send parsedBody.message