问题
Original Post: I'm trying to create defects programmatically. I am getting a couple errors and having trouble getting any further. Here, essentially, is the code:
import requests, json
rally_auth = ('my_user', 'my_pw')
rally_auth_url = 'https://rally1.rallydev.com/slm/webservice/v2.0/security/authorize'
rally_defect = 'https://rally1.rallydev.com/slm/webservice/v2.0/defect/defect'
workspace_ref = 'https://rally1.rallydev.com/slm/webservice/v2.0/workspace/12345'
fe_project_ref = 'https://rally1.rallydev.com/slm/webservice/v2.0/project/7890'
current_fe_release_ref = "https://rally1.rallydev.com/slm/webservice/v2.0/release/45678"
r = requests.get(rally_auth_url, auth=rally_auth)
token = r.json()['OperationResult']['SecurityToken']
url = rally_defect + '/create?key=' + token
payload = {
'Name': 'My defect',
'State': 'Open',
'Project': fe_project_ref,
'Rank': 120,
'Release': current_fe_release_ref,
'key': token
}
headers = {'content-type': 'application/json'}
r = requests.post(url, data=json.dumps(payload), auth=rally_auth, headers=headers)
You'll notice that i've put the token in both the POST's URL and data. The API docs say that I should have the key in the URL, but if I do not include the key in the POST data I get:
{"CreateResult": {"_rallyAPIMajor": "2", "_rallyAPIMinor": "0", "Errors": ["Not authorized to perform action: Invalid key"], "Warnings": []}}
If I do include the key, the API request falls over differently. It will fail on the first comma.
{"CreateResult": {"_rallyAPIMajor": "2", "_rallyAPIMinor": "0", "Errors": ["Cannot parse input stream due to I/O error as JSON document: Parse error: expected '}' but saw ',' [ chars read = >>>{\"Name\": \"My defect\",<<< ]"], "Warnings": []}}
I am baffled.
Fixed code Thanks to @nickm
import requests, json
rally_auth = ('my_user', 'my_pw')
rally_auth_url = 'https://rally1.rallydev.com/slm/webservice/v2.0/security/authorize'
rally_defect = 'https://rally1.rallydev.com/slm/webservice/v2.0/defect/defect'
workspace_ref = 'https://rally1.rallydev.com/slm/webservice/v2.0/workspace/12345'
fe_project_ref = 'https://rally1.rallydev.com/slm/webservice/v2.0/project/7890'
current_fe_release_ref = "https://rally1.rallydev.com/slm/webservice/v2.0/release/45678"
s = requests.Session()
r = s.get(rally_auth_url, auth=rally_auth)
token = r.json()['OperationResult']['SecurityToken']
url = rally_defect + '/create?key=' + token
payload = {
'Name': 'My defect',
'State': 'Open',
'Project': fe_project_ref,
'Rank': 120,
'Release': current_fe_release_ref,
}
headers = {'content-type': 'application/json'}
r = s.post(url, data=json.dumps(payload), headers=headers)
回答1:
If you are using v2.0 of WS API, the token is required for update and create requests, so you are correct by including it in your post request url.
The invalid key error will come up if a token is not appended to the request or if the token is invalid for a specific session. When hitting the endpoints directly we have to maintain an http session with a cookie, otherwise the post happens in the context of a new session - different from the one in which we got the token.
Please see this post. It is not specific to Python, but conceptually it's the same.
I noticed Rank in the payload. Do you have a Rank custom field? There is no such built-in field in v2.0 in Rally. There is a DragAndDropRank, which is not numeric, and setting it by supplying a value of 120 will not work.Also, did you try double quotes instead of single quotes in the payload?
There is a pyral - Rally Python toolkit that provide convenience methods so you do not have to hit endpoints directly. Currently it works with 1.43 of WS API. The toolkit is not officially supported, but I expect that it will be updated to work with v2.0 of WS API before June 2014, when 1.43 is no longer supported (per this schedule). Security token was introduced in v2.0. This extra authentication layer for post requests does not exist in 1.43 of WS API, and you do not have to deal with the token if using pyral.
来源:https://stackoverflow.com/questions/22573359/rallydev-unable-to-create-defect-server-says-cannot-parse-input