Quering for Test folder that contains a whitespace using rally_api - api

I’m doing a tool to create Test folders (test suites) and test cases automatically from a xml file that a Jenkins job provides me.
Probably is a silly thing but I cannot find the solution, the thing is when the test folder name contains a white space, I’m not able to query it to see if already exists. I’ve trid to escape the whitespace and also encode it as url but nothing happens.
test_suite_name = ts_line["name"]
if test_suite_name.match(/\s/)
#test_suite_name_nows = test_suite_name.gsub(/ /,"\\ \\")
test_suite_name_nows = URI::encode(test_suite_name)
end
#==================== Querying the test suite in Rally ==========================
test_suite_query = RallyAPI::RallyQuery.new({:type => :testfolder, :query_string => "(Name = #{test_suite_name_nows})"})
Do you know which should be the format for being able to query test folder names as “Test folder1”??
I always get:
/usr/local/rvm/gems/ruby-2.0.0-p195/gems/rally_api-0.9.14/lib/rally_api/rally_json_connection.rb:153:in `send_request': (StandardError)
Error on request - https://rally1.rallydev.com/slm/webservice/1.42/testfolder.js -
{:errors=>["Could not parse: Cannot parse expression \"Version tests\" as a query"]
Thanks a lot.

Here is the format:
query.query_string = "(Name = \"My Test Folder 1\")"
and a full example:
require 'rally_api'
#Setup custom app information
headers = RallyAPI::CustomHttpHeader.new()
headers.name = "find test folder"
headers.vendor = "NickM RallyLab"
headers.version = "1.0"
# Connection to Rally
config = {:base_url => "https://rally1.rallydev.com/slm"}
config[:username] = "user#co.com"
config[:password] = "1984"
config[:workspace] = "W"
config[:project] = "P"
config[:headers] = headers #from RallyAPI::CustomHttpHeader.new()
#rally = RallyAPI::RallyRestJson.new(config)
query = RallyAPI::RallyQuery.new()
query.type = :test_folder
query.fetch = "Name,FormattedID"
query.workspace = {"_ref" => "https://rally1.rallydev.com/slm/webservice/1.43/workspace/12345.js" } #use yoru OID
query.project = {"_ref" => "https://rally1.rallydev.com/slm/webservice/1.43/project/67890.js" } #user yoru OID
query.page_size = 200 #optional - default is 200
query.limit = 1000 #optional - default is 99999
query.project_scope_up = false
query.project_scope_down = true
query.order = "Name Asc"
query.query_string = "(Name = \"My Test Folder 1\")"
results = #rally.find(query)
results.each do |t|
puts "Name: #{t["Name"]}, FormattedID: #{t["FormattedID"]}"
t.read
#.............
end

Related

How come I cannot set multiple cookies

I'm trying to set multiple cookies, but it's not working:
if type(ngx.header["Set-Cookie"]) ~= "table" then
ngx.header["Set-Cookie"] = {}
end
table.insert(ngx.header["Set-Cookie"], "Cookie1=abc; Path=/")
table.insert(ngx.header["Set-Cookie"], "Cookie2=def; Path=/")
table.insert(ngx.header["Set-Cookie"], "Cookie3=ghi; Path=/")
On the client I do not receive any cookies.
ngx.header["Set-Cookie"] is a special table, and must be reassigned to with a new table every time you modify it (elements inserted or removed from it have no effect on the cookies that will be sent to the client):
if type(ngx.header["Set-Cookie"]) == "table" then
ngx.header["Set-Cookie"] = { "AnotherCookieValue=abc; Path=/", unpack(ngx.header["Set-Cookie"]) }
else
ngx.header["Set-Cookie"] = { "AnotherCookieValue=abc; Path=/", ngx.header["Set-Cookie"] }
end
You can use https://github.com/cloudflare/lua-resty-cookie
local ck = require "resty.cookie"
local cookie, err = ck:new()
cookie:set({key = "Cookie1", value = "abc", path = "/"})
cookie:set({key = "Cookie2", value = "def", path = "/"})
cookie:set({key = "Cookie3", value = "ghi", path = "/"})

AttributeError: 'unicode' object has no attribute 'key'

I'm very new to Python coding and have run into an issue while trying to upgrade some code. I'm working with an app that pulls data via an API from stored data from a scan.
here is the code as it sits working
def _collect_one_host_scan_info(self, host_id, sid, scan_info):
"""
The method to collect all the vulnerabilities of one host and generate the event data.
"""
count = 0
host_uri = self.endpoint + '/' + str(sid) + '/hosts/' + str(host_id)
result = self.client.request(host_uri).get("content")
# if there is exception in request, return None
if result is None:
_LOGGER.info("There is exception in request, return None")
return None
else:
host_info = result.get("info", {})
host_end_time = host_info.get("host_end", "")
if self.ckpt.is_new_host_scan(host_end_time,
self.config.get("start_date")):
self.source = self.url + self.endpoint + '/' + str(
sid) + '/hosts/' + str(host_id)
for vuln in result.get("vulnerabilities", []):
vuln["sid"] = sid
vuln["host_id"] = host_id
#get the port info
plugin_id = vuln.get("plugin_id", "")
port_info = []
if plugin_id:
plugin_uri = "{}/plugins/{}".format(host_uri,
plugin_id)
plugin_outputs = self.client.request(plugin_uri).get(
"content", {}).get("outputs")
ports = []
for output in plugin_outputs:
ports.extend(output.get("ports", {}).keys())
for port in ports:
port_elem = {}
port_items = re.split(r"\s*/\s*", port)
port_elem["port"] = int(port_items[0])
if port_items[1]:
port_elem["transport"] = port_items[1]
if port_items[2]:
port_elem["protocol"] = port_items[2]
port_info.append(port_elem)
vuln = dict(vuln, **scan_info)
vuln = dict(vuln, **host_info)
if port_info:
vuln["ports"] = port_info
entry = NessusObject(
vuln.get("timestamp"), self.sourcetype, self.source,
vuln)
self._print_stream(entry)
count += 1
return count
The data that is being pulled from looks like this
"outputs": [
{
"ports": {
"445 / tcp / cifs": [
{
"hostname": "computer.domain.com"
}
]
},
"has_attachment": 0,
"custom_description": null,
"plugin_output": "\nPath : c:\\program files (x86)\\folder\\bin\\fax.exe\nUsed by services : RFDB\nFile write allowed for groups : Domain Users\nFull control of directory allowed for groups : Domain Users\n\nPath : c:\\program files (x86)\\folder\\bin\\faxrpc.exe\nUsed by services : RFRPC\nFile write allowed for groups : Domain Users\nFull control of directory allowed for groups : Domain Users\n\nPath : c:\\program files (x86)\\folder\\bin\\faxserv.exe\nUsed by services : RFSERVER\nFile write allowed for groups : Domain Users\nFull control of directory allowed for groups : Domain Users\n`,
"hosts": null,
"severity": 3
}
with the working code the return is
ports{}.port 445
ports{}.protocol tcp
ports{}.transport cifs
What I really would like is to grab the "plugin_output" data with the "port" data
I'm currently just trying to replace the "port" data with "plugin_output" data
#get the output info
plugin_id = vuln.get("plugin_id", "")
output_info = []
if plugin_id:
plugin_uri = "{}/plugins/{}".format(host_uri,
plugin_id)
plugin_outputs = self.client.request(plugin_uri).get(
"content", {}).get("outputs")
outputs = []
for output in plugin_outputs:
outputs.extend(output.get("plugin_output", "").keys())
for plugin in plugin_outputs:
plugin_elem = {}
plugin_items = re.split(r"nPath\s*", plugin)
plugin_elem["location1"] = plugin_items[0]
if plugin_items[1]:
plugin_elem["location2"] = plugin_items[1]
if plugin_items[2]:
plugin_elem["location3"] = plugin_items[2]
output_info.append(plugin_elem)
vuln = dict(vuln, **scan_info)
vuln = dict(vuln, **host_info)
if output_info:
vuln["plugin_output"] = output_info
entry = NessusObject(
vuln.get("timestamp"), self.sourcetype, self.source,
vuln)
self._print_stream(entry)
count += 1
what I've done as you can see if just replace the "ports" data with "plugin_output" data and the error received is
AttributeError: 'unicode' object has no attribute key
Well after further efforts I was able to figure out what I needed to do with the code. It was much easier than I thought it would be but sometime when learning a new language its hard to envision what is needed. Code posted below.
def _collect_one_host_scan_info(self, host_id, sid, scan_info):
"""
The method to collect all the vulnerabilities of one host and generate
the event data.
"""
count = 0
host_uri = self.endpoint + '/' + str(sid) + '/hosts/' + str(host_id)
result = self.client.request(host_uri).get("content")
# if there is exception in request, return None
if result is None:
_LOGGER.info("There is exception in request, return None")
return None
else:
host_info = result.get("info", {})
host_end_time = host_info.get("host_end", "")
if self.ckpt.is_new_host_scan(host_end_time,
self.config.get("start_date")):
self.source = self.url + self.endpoint + '/' + str(
sid) + '/hosts/' + str(host_id)
for vuln in result.get("vulnerabilities", []):
vuln["sid"] = sid
vuln["host_id"] = host_id
plugin_id = vuln.get("plugin_id", "")
# get plugin_output data
plugin_output_info = []
if plugin_id:
plugin_uri = "{}/plugins/{}".format(host_uri,
plugin_id)
plugin_outputs = self.client.request(plugin_uri).get(
"content", {}).get("outputs", [])
data_output = []
for output in plugin_outputs:
items = output.get("plugin_output", 'no value')
item = str(items)
#clean = re.sub('[^a-zA-Z0-9-()_*.(:\\)]', ' ', item)
plugin_output_info.append(item)
# get the port info
port_info = []
if plugin_id:
plugin_uri = "{}/plugins/{}".format(host_uri,
plugin_id)
plugin_outputs = self.client.request(plugin_uri).get(
"content", {}).get("outputs", [])
ports = []
for output in plugin_outputs:
ports.extend(output.get("ports", {}).keys())
for port in ports:
port_elem = {}
port_items = re.split(r"\s*/\s*", port)
port_elem["port"] = int(port_items[0])
if port_items[1]:
port_elem["transport"] = port_items[1]
if port_items[2]:
port_elem["protocol"] = port_items[2]
port_info.append(port_elem)
vuln = dict(vuln, **scan_info)
vuln = dict(vuln, **host_info)
if port_info:
vuln["ports"] = port_info
if plugin_output_info:
vuln["plugin_output"] = plugin_output_info
entry = NessusObject(
vuln.get("timestamp"), self.sourcetype, self.source,
vuln)
self._print_stream(entry)
count += 1
return count

Slashes in Rally Query

I have a Feature name such as: "This / is / the / name / of my feature ". Rally throws me an error when I try to mention this name as a query string. Is there a way to get around this?
Where do you get the error? I tested this query in WS API, a custom grid and a Ruby script using a feature named "feat/ure"
(Name = feat/ure)
and the query worked in all 3 cases.
Here is the Ruby code that query on a feature with forward slash in the name and assigns a new story to it:
require 'rally_api'
#Setup custom app information
headers = RallyAPI::CustomHttpHeader.new()
headers.name = "My Utility"
headers.vendor = "Nick M RallyLab"
headers.version = "1.0"
# Connection to Rally
config = {:base_url => "https://rally1.rallydev.com/slm"}
config[:username] = "user#co.com"
config[:password] = "secret"
config[:workspace] = "W"
config[:project] = "P"
config[:headers] = headers #from RallyAPI::CustomHttpHeader.new()
#rally = RallyAPI::RallyRestJson.new(config)
obj = {}
obj["Name"] = "new story efd3"
new_s = #rally.create("hierarchicalrequirement", obj)
query = RallyAPI::RallyQuery.new()
query.type = "portfolioitem"
query.fetch = "Name,FormattedID"
query.workspace = {"_ref" => "https://rally1.rallydev.com/slm/webservice/v2.0/workspace/111" }
query.project = {"_ref" => "https://rally1.rallydev.com/slm/webservice/v2.0/project/222" }
query.query_string = "(Name = \"feat/ure\")"
result = #rally.find(query)
feature = result.first
puts feature
field_updates={"PortfolioItem" => feature}
new_s.update(field_updates)
You can also utilize the html replacements for those characters.

Returning object type Rally

So I have this query using Rally:
query_result = stuff.slm.find(:hierarchical_requirement, :project => project, :workspace => stuff.workspace, :project_scope_up => false, :project_scope_down => true){ equal :name, parent_name.strip }
and then I do,
parent = query_result.results.first
and I am curious to know what kind of object is assigned to the parent. I am not on the exceptions list in Rally so unable to run the script. But I am writing an SSO integration for this script and having some problems. I feel my problem would be solved if I get to inspect the "parent" because the function is returning this "parent". If anyone has any information on this , please share. Thanks!
A story (HierarchicalRequirement) object is assigned. Using Rally Ruby REST toolkit
The code below prints:
my_story: abc, FormattedID: US86, _ref:https://rally1.rallydev.com/slm/webservice/v2.0/hierarchicalrequirement/12891971030
.
#rally = RallyAPI::RallyRestJson.new(config)
some_name = "abc"
query = RallyAPI::RallyQuery.new()
query.type = :story
query.fetch = "FormattedID"
query.query_string = "(Name = \"#{some_name}\")"
results = #rally.find(query)
my_story = results.first
puts "my_story: #{my_story}, FormattedID: #{my_story["FormattedID"]}, _ref:#{my_story["_ref"]}"
If in your code you try to find a user story based on FormattedID, here is an example. It does not really matter if it is a parent or not, since a parent of a story is a story, and I used "story" instead of "parent" in my script for clarity. A FormattedID is entered as a command line argument in this example. Notice I use story = result.first, and not story=result. Here is a screenshot of the output:
require 'rally_api'
#Setup custom app information
headers = RallyAPI::CustomHttpHeader.new()
headers.name = "find story"
headers.vendor = "Nick M RallyLab"
headers.version = "1.0"
# Connection to Rally
config = {:base_url => "https://rally1.rallydev.com/slm"}
config[:username] = "user#co.com"
config[:password] = "secret"
config[:workspace] = "X"
config[:project] = "Y"
config[:version] = "v2.0"
config[:headers] = headers #from RallyAPI::CustomHttpHeader.new()
unless ARGV.length == 1
puts "enter one argument, e.g. US123, with no spaces"
exit
end
story = nil
story_id = ARGV[0]
puts "find story by FormattedID: #{story_id}"
#rally = RallyAPI::RallyRestJson.new(config)
query = RallyAPI::RallyQuery.new()
query.type = :story
query.fetch = "Name,FormattedID,ScheduleState"
query.workspace = {"_ref" => "https://rally1.rallydev.com/slm/webservice/v2.0/workspace/1111.js" }
query.project = {"_ref" => "https://rally1.rallydev.com/slm/webservice/v2.0/project/2222.js" }
query.project_scope_up = true
query.project_scope_down = true
query.query_string = "(FormattedID = \"#{story_id}\")"
result = #rally.find(query)
if(result.length > 0)
puts "found the story"
story = result.first
puts "FormattedID: #{story["FormattedID"]}, Name: #{story["Name"]}, ScheduleState: #{story["ScheduleState"]}"
else
puts "did not find a story with FormattedID #{story_id}"
end
puts story.class
puts story.inspect

How to access project name from a query of type portfolioitem

I am trying to match Project name in my query and also trying to print the name of the project associated with each feature record. I know there are plenty of answers but I couldn't find anything that could help me. I am trying to do something like this:
pi_query.type = "portfolioitem"
pi_query.fetch="Name,FormattedID,Owner,c_ScopingTeam,c_AspirationalRelease,c_AssignedProgram,Tags"
#To be configured as per requirement
pi_query.project_scope_up = false
pi_query.project_scope_down = false
pi_query.order = "FormattedID Asc"
pi_query.query_string = "(Project.Name = \"Uni - Serviceability\")"
pi_results = #rally.find(pi_query)
I am trying to match the project name but it simply doesn't work, I also tried printing the name of the project, i tried Project.Name, Project.Values or simply Project. But it doesn't work. I am guessing it is because of my query type which is "portfolioItem" and I can't change my type because I am getting all other attribute values correctly.
Thanks.
Make sure to fetch Project, e.g: feature_query.fetch = "Name,FormattedID,Project"
and this should work:
feature_query.query_string = "(Project.Name = \"My Project\")"
Here is an example where a feature is found by project name.
require 'rally_api'
#Setup custom app information
headers = RallyAPI::CustomHttpHeader.new()
headers.name = "create story in one project, add it to a feature from another project"
headers.vendor = "Nick M RallyLab"
headers.version = "1.0"
# Connection to Rally
config = {:base_url => "https://rally1.rallydev.com/slm"}
config[:username] = "user#co.com"
config[:password] = "secret"
config[:workspace] = "W"
config[:project] = "Product1"
config[:headers] = headers #from RallyAPI::CustomHttpHeader.new()
#rally = RallyAPI::RallyRestJson.new(config)
obj = {}
obj["Name"] = "new story xyz123"
new_s = #rally.create("hierarchicalrequirement", obj)
query = RallyAPI::RallyQuery.new()
query.type = "portfolioitem"
query.fetch = "Name,FormattedID,Project"
query.workspace = {"_ref" => "https://rally1.rallydev.com/slm/webservice/v2.0/workspace/12352608129" }
query.query_string = "(Project.Name = \"Team Group 1\")"
result = #rally.find(query)
feature = result.first
puts feature
field_updates={"PortfolioItem" => feature}
new_s.update(field_updates)