This question was asked by a different user earlier:
Copying Test Cases and Test Folder using Rally Python or Ruby API [closed]
but closed by moderators as being an overly broad question. However, given the inability to copy Test Folders and their member Test Cases within the Rally UI, this is a common need for Rally Users.
Thus - I'll re-pose the question, hopefully with enough detail to stand as a valid question. I'll also re-post the answers that I developed for the original question.
Question: As a Rally user and developer in the Rally Python and Ruby REST APIs: how can I leverage the Rally API toolkits to accomplish this task?
Python:
Here is a script that performs this task - it will copy all Test Cases from a Source Test Folder identified by FormattedID, to a Target Test Folder, also identified by FormattedID. It will copy all Test Steps and Attachments as well. The Target Test Folder must exist, i.e. the script will not create a Test Folder for you if the Target is not found.
The script does not associate the new Test Case to original Test Case's Work Product (i.e. Defect, User Story), or copy Discussion items, Test Case Results, or Last Build, Verdict, etc. as it is assumed the new Test Case is desired to be in a "blank" state.
For those needing to install and configure the Rally Python REST Library:
Rally Developer Portal: Pyral Download and Installation
Pyral Documentation
#!/usr/bin/env python
#################################################################################################
#
# copy_test_folder.py -- Copy all Test Cases in Source Test Folder to Target. Includes Test Steps
# and attachments. Target Test Folder must exist (i.e. the script will not
# create a new targeet Test Folder for you)
#
USAGE = """
Usage: copy_test_folder.py
"""
#################################################################################################
# import needed python libs
import sys, os
import re
import string
import base64
from pprint import pprint
# import needed pyral libs
from pyral import Rally, rallySettings, RallyRESTAPIError
errout = sys.stderr.write
my_server = "rally1.rallydev.com"
my_user = "user#company.com"
my_password = "topsecret"
my_workspace = "My Workspace"
my_project = "My Project"
source_test_folder_formatted_id = "TF1"
target_test_folder_formatted_id = "TF4"
rally = Rally(my_server, my_user, my_password, workspace=my_workspace, project=my_project)
# rally = Rally(my_server, my_user, my_password, workspace=my_workspace, project=my_project, debug=True)
rally.enableLogging('copy_test_folder.log')
# Query for source and target test folders
source_test_folder_response = rally.get('TestFolder', fetch=True, query='FormattedID = %s' % source_test_folder_formatted_id)
target_test_folder_response = rally.get('TestFolder', fetch=True, query='FormattedID = %s' % target_test_folder_formatted_id)
# Check to make sure folders exist
if source_test_folder_response.resultCount == 0:
errout('No Source Test Folder Found matching Formatted ID: %s\n' % (source_test_folder_formatted_id))
sys.exit(4)
if target_test_folder_response.resultCount == 0:
errout('No Target Test Folder Found matching Formatted ID: %s\n. Target Test Folder must be created before copying.' % (target_test_folder_formatted_id))
sys.exit(4)
# Get references to source Test Folder and Test Cases, etc.
source_test_folder = source_test_folder_response.next()
source_test_cases = source_test_folder.TestCases
# Get reference to target Test Folder
target_test_folder = target_test_folder_response.next()
for source_test_case in source_test_cases:
# Create update fields for target Test Case
# Does NOT associate new Test Case to original Test Case's work product (i.e. Defect, User Story)
# Does NOT copy Discussion items - as the old Discussions are likely not desired on new Test Case
# Does NOT copy Last Build, Last Run, Last Update Date, Last Verdict as new Test Case will effectively
# be "blank" and not have any results associated to it
if source_test_case.Owner != None:
target_owner = source_test_case.Owner.ref
else:
target_owner = None
target_test_case_fields = {
"Package": source_test_case.Package,
"Description": source_test_case.Description,
"Method": source_test_case.Method,
"Name": source_test_case.Name,
"Objective": source_test_case.Objective,
"Owner": target_owner,
"PostConditions": source_test_case.PostConditions,
"PreConditions": source_test_case.PreConditions,
"Priority": source_test_case.Priority,
"Project": source_test_case.Project.ref,
"Risk": source_test_case.Risk,
"ValidationInput": source_test_case.ValidationInput,
"ValidationExpectedResult": source_test_case.ValidationExpectedResult,
"TestFolder": target_test_folder.ref,
}
# Create the target test case
try:
target_test_case = rally.create("TestCase", target_test_case_fields)
message = "Copied Source Test Case: " + source_test_case.FormattedID + \
" To: " + target_test_folder.FormattedID + ": " + target_test_folder.Name + \
": " + target_test_case.FormattedID
print message
except RallyRESTAPIError, details:
sys.stderr.write('ERROR: %s \n' % details)
sys.exit(2)
# Copy Test Steps
# Add Test Case Steps
source_test_case_steps = source_test_case.Steps
for source_step in source_test_case_steps:
target_step_fields = {
"TestCase" : target_test_case.ref,
"StepIndex" : source_step.StepIndex,
"Input" : source_step.Input,
"ExpectedResult" : source_step.ExpectedResult
}
target_test_case_step = rally.put('TestCaseStep', target_step_fields)
print "===> Copied TestCaseStep: %s OID: %s" % (target_test_case_step.StepIndex, target_test_case_step.oid)
# Copy Attachments
source_attachments = rally.getAttachments(source_test_case)
for source_attachment in source_attachments:
# First copy the content
source_attachment_content = source_attachment.Content
target_attachment_content_fields = {
"Content": base64.encodestring(source_attachment_content)
}
try:
target_attachment_content = rally.put('AttachmentContent', target_attachment_content_fields)
print "===> Copied AttachmentContent: %s" % target_attachment_content.ref
except RallyRESTAPIError, details:
sys.stderr.write('ERROR: %s \n' % details)
sys.exit(2)
# Next copy the attachment object
target_attachment_fields = {
"Name": source_attachment.Name,
"Description": source_attachment.Description,
"Content": target_attachment_content.ref,
"ContentType": source_attachment.ContentType,
"Size": source_attachment.Size,
"Artifact": target_test_case.ref,
"User": source_attachment.User.ref
}
try:
target_attachment = rally.put('Attachment', target_attachment_fields)
print "===> Copied Attachment: %s" % target_attachment.ref
except RallyRESTAPIError, details:
sys.stderr.write('ERROR: %s \n' % details)
sys.exit(2)
# Copy Tags
source_tags = source_test_case.Tags;
target_tags = list()
for source_tag in source_tags:
target_tags.append({"_ref":source_tag.ref})
target_test_case_fields = {
"FormattedID": target_test_case.FormattedID,
"Tags": target_tags
}
try:
update_response = rally.update('TestCase', target_test_case_fields)
except RallyRESTAPIError, details:
sys.stderr.write('ERROR: %s \n' % details)
sys.exit(2)
Ruby:
This Ruby script will copy all Test Cases from a Source Test Folder identified by FormattedID, to a Target Test Folder, also identified by FormattedID. It will copy all Test Steps and Attachments as well. The Target Test Folder must exist, i.e. the script will not create a Test Folder for you if the Target is not found.
The script does not associate the new Test Case to original Test Case's Work Product (i.e. Defect, User Story), or copy Discussion items, Test Case Results, or Last Build, Verdict, etc. as it is assumed the new Test Case is desired to be in a "blank" state.
For those needing to install and configure the Ruby REST Toolkit, links are here:
Developer Portal: Rally REST API for Ruby
Github
# Copyright 2002-2012 Rally Software Development Corp. All Rights Reserved.
require 'rally_api'
$my_base_url = "https://rally1.rallydev.com/slm"
$my_username = "user#company.com"
$my_password = "password"
$my_workspace = "My Workspace"
$my_project = "My Project"
$wsapi_version = "1.37"
# Test Folders
$source_test_folder_formatted_id = "TF4"
$target_test_folder_formatted_id = "TF8"
# Load (and maybe override with) my personal/private variables from a file...
my_vars= File.dirname(__FILE__) + "/my_vars.rb"
if FileTest.exist?( my_vars ) then require my_vars end
#==================== Make a connection to Rally ====================
config = {:base_url => $my_base_url}
config[:username] = $my_username
config[:password] = $my_password
config[:workspace] = $my_workspace
config[:project] = $my_project
config[:version] = $wsapi_version
#rally = RallyAPI::RallyRestJson.new(config)
begin
# Lookup source Test Folder
source_test_folder_query = RallyAPI::RallyQuery.new()
source_test_folder_query.type = :testfolder
source_test_folder_query.fetch = true
source_test_folder_query.query_string = "(FormattedID = \"" + $source_test_folder_formatted_id + "\")"
source_test_folder_result = #rally.find(source_test_folder_query)
# Lookup Target Test Folder
target_test_folder_query = RallyAPI::RallyQuery.new()
target_test_folder_query.type = :testfolder
target_test_folder_query.fetch = true
target_test_folder_query.query_string = "(FormattedID = \"" + $target_test_folder_formatted_id + "\")"
target_test_folder_result = #rally.find(target_test_folder_query)
if source_test_folder_result.total_result_count == 0
puts "Source Test Folder: " + $source_test_folder_formatted_id + "not found. Exiting."
exit
end
if target_test_folder_result.total_result_count == 0
puts "Target Test Folder: " + $target_test_folder_formatted_id + "not found. Target must exist before copying."
exit
end
source_test_folder = source_test_folder_result.first()
target_test_folder = target_test_folder_result.first()
# Populate full object for Target Test Folder
full_target_test_folder = target_test_folder.read
# Get Target Project
target_project = full_target_test_folder["Project"]
# Grab collection of Source Test Cases
source_test_cases = source_test_folder["TestCases"]
# Loop through Source Test Cases and Copy to Target
source_test_cases.each do |source_test_case|
# Get full object for Source Test Case
full_source_test_case = source_test_case.read
# Check if there's an Owner
if !full_source_test_case["Owner"].nil?
source_owner = full_source_test_case["Owner"]
else
source_owner = nil
end
# Populate field data from Source to Target
target_test_case_fields = {}
target_test_case_fields["Package"] = full_source_test_case["Package"]
target_test_case_fields["Description"] = full_source_test_case["Description"]
target_test_case_fields["Method"] = full_source_test_case["Method"]
target_test_case_fields["Name"] = full_source_test_case["Name"]
target_test_case_fields["Objective"] = full_source_test_case["Objective"]
target_test_case_fields["Owner"] = source_owner
target_test_case_fields["PostConditions"] = full_source_test_case["PostConditions"]
target_test_case_fields["PreConditions"] = full_source_test_case["PreConditions"]
target_test_case_fields["Priority"] = full_source_test_case["Priority"]
target_test_case_fields["Project"] = target_project
target_test_case_fields["Risk"] = full_source_test_case["Risk"]
target_test_case_fields["ValidationInput"] = full_source_test_case["ValidationInput"]
target_test_case_fields["ValidationExpectedResult"] = full_source_test_case["ValidationExpectedResult"]
target_test_case_fields["Tags"] = full_source_test_case["Tags"]
target_test_case_fields["TestFolder"] = target_test_folder
# Create the Target Test Case
begin
target_test_case = #rally.create(:testcase, target_test_case_fields)
puts "Test Case: #{full_source_test_case["FormattedID"]} successfully copied to #{full_target_test_folder["FormattedID"]}"
rescue => ex
puts "Test Case: #{full_source_test_case["FormattedID"]} not copied due to error"
puts ex
end
# Now Copy Test Steps
# Add Test Case Steps
source_test_case_steps = full_source_test_case["Steps"]
source_test_case_steps.each do |source_test_case_step|
full_source_step = source_test_case_step.read
target_step_fields = {}
target_step_fields["TestCase"] = target_test_case
target_step_fields["StepIndex"] = full_source_step["StepIndex"]
target_step_fields["Input"] = full_source_step["Input"]
target_step_fields["ExpectedResult"] = full_source_step["ExpectedResult"]
begin
target_test_case_step = #rally.create(:testcasestep, target_step_fields)
puts "===> Copied TestCaseStep: #{target_test_case_step["_ref"]}"
rescue => ex
puts "Test Case Step not copied due to error:"
puts ex
end
end
# Now Copy Attachments
source_attachments = full_source_test_case["Attachments"]
source_attachments.each do |source_attachment|
full_source_attachment = source_attachment.read
source_attachment_content = full_source_attachment["Content"]
full_source_attachment_content = source_attachment_content.read
# Create AttachmentContent Object for Target
target_attachment_content_fields = {}
target_attachment_content_fields["Content"] = full_source_attachment_content["Content"]
begin
target_attachment_content = #rally.create(:attachmentcontent, target_attachment_content_fields)
puts "===> Copied AttachmentContent: #{target_attachment_content["_ref"]}"
rescue => ex
puts "AttachmentContent not copied due to error:"
puts ex
end
# Now Create Attachment Container
target_attachment_fields = {}
target_attachment_fields["Name"] = full_source_attachment["Name"]
target_attachment_fields["Description"] = full_source_attachment["Description"]
target_attachment_fields["Content"] = target_attachment_content
target_attachment_fields["ContentType"] = full_source_attachment["ContentType"]
target_attachment_fields["Size"] = full_source_attachment["Size"]
target_attachment_fields["Artifact"] = target_test_case
target_attachment_fields["User"] = full_source_attachment["User"]
begin
target_attachment = #rally.create(:attachment, target_attachment_fields)
puts "===> Copied Attachment: #{target_attachment["_ref"]}"
rescue => ex
puts "Attachment not copied due to error:"
puts ex
end
end
end
end
An improvement of the same Python script that adds the following features
Test Folders (source and destination) are passed in arguments instead of hard coded
Creation is done recursively (i.e. copy Test Folders and Test Cases in it)
Test Cases are replaced if they already exist (based on the Name)
Usage of API Key to connect rather than password
Try 5 times to connect to Rally before giving up
To use it to copy TF10 to TF99 (which already exists): python copy_test_folder TF10 TF99
#!/usr/bin/env python
#################################################################################################
#
# copy_test_folder.py -- Copy all Test Cases in Source Test Folder to Target. Includes Test Steps
# and attachments. Target Test Folder must exist (i.e. the script will not
# create a new targeet Test Folder for you)
#
USAGE = """
Usage: copy_test_folder.py TF_src TF_dest
"""
#################################################################################################
# import needed python libs
import sys, os
import re
import string
import base64
from pprint import pprint
# import needed pyral libs
from pyral import Rally, rallySettings, RallyRESTAPIError
errout = sys.stderr.write
my_server = "rally1.rallydev.com"
my_user = "name#domain.com"
my_password = "<PASSWORD>"
my_workspace = "<WORKSPACE>"
my_project = "<PROJECT>"
my_key = "<API KEY>"
def connect(nb_attempts=5):
'''Connect to Rally'''
global is_connected
global rally
#Connect
if not is_connected and nb_attempts>0:
print "...Attempting to connect to Rally for project %s..." % my_project
try:
# rally = Rally(my_server, my_user, my_password, workspace=my_workspace, project=my_project)
rally = Rally(my_server, apikey=my_key, workspace=my_workspace, project=my_project)
print "Connected to Rally for project %s (%s)" % (my_project, my_workspace)
is_connected=True
rally.enableLogging('copy_test_folder.log')
#Errors during connection (attempting to connect again)
# except Exception, details:
except AttributeError:
if nb_attempts>1:
connect(nb_attempts-1)
else:
errout('Error during connection to Rally (%s)\n' % details)
exit(4)
else: pass
def copyTF(src_TF, dest_TF):
'''Copy Test Cases from one folder into another (including children Test Folders)'''
# List names and FormattedID of existing Test Cases in destination
dest_TCs = dest_TF.TestCases
existing_dest_TC = {tc.Name:tc.FormattedID for tc in dest_TCs}
# Copy Test Cases to destination folder (replace if Test Case with same name exists)
src_TCs = src_TF.TestCases
for src_TC in src_TCs:
# Create update fields for target Test Case
# Does NOT associate new Test Case to original Test Case's WorkProduct (i.e. Defect, User Story)
# Does NOT copy Discussion items - as the old Discussions are likely not desired on new Test Case
# Does NOT copy Last Build, Last Run, Last Update Date, Last Verdict as new Test Case will effectively
# be "blank" and not have any results associated to it
tcName = src_TC.Name
dest_TC_fields = {
"Package": src_TC.Package,
"Description": src_TC.Description,
"Method": src_TC.Method,
"Name": tcName,
"Objective": src_TC.Objective,
"Owner": getattr(src_TC.Owner, 'ref', None),
"PostConditions": src_TC.PostConditions,
"PreConditions": src_TC.PreConditions,
"Priority": src_TC.Priority,
"Project": src_TC.Project.ref,
"Risk": src_TC.Risk,
"ValidationInput": src_TC.ValidationInput,
"ValidationExpectedResult": src_TC.ValidationExpectedResult,
"TestFolder": dest_TF.ref,
}
# Create/Update the target test case
try:
if existing_dest_TC.has_key(tcName):
operation = "Update"
dest_TC_fields['FormattedID'] = existing_dest_TC[tcName]
dest_TC = rally.update("TestCase", dest_TC_fields)
else:
#Create
operation = "Create"
dest_TC = rally.create("TestCase", dest_TC_fields)
message = operation + "d Source Test Case: " + src_TC.FormattedID + \
" To: " + dest_TF.FormattedID + ": " + dest_TF.Name + \
": " + dest_TC.FormattedID
print message
except RallyRESTAPIError, details:
sys.stderr.write('ERROR: %s \n' % details)
sys.exit(2)
# Copy Test Steps
#Cleared-up all Test Steps in destination if Test Case is updated
if operation == "Update":
dest_TC_steps = dest_TC.Steps
for dest_step in dest_TC_steps:
rally.delete('TestCaseStep', dest_step.oid)
print "===> Cleared all Test Steps"
# Add Test Case Steps
src_TC_steps = src_TC.Steps
for src_step in src_TC_steps:
target_step_fields = {
"TestCase" : dest_TC.ref,
"StepIndex" : src_step.StepIndex,
"Input" : src_step.Input,
"ExpectedResult" : src_step.ExpectedResult
}
dest_TC_step = rally.put('TestCaseStep', target_step_fields)
print "===> Copied TestCaseStep: %s OID: %s" % (dest_TC_step.StepIndex, dest_TC_step.oid)
# Copy Attachments
source_attachments = rally.getAttachments(src_TC)
for source_attachment in source_attachments:
# First copy the content
source_attachment_content = source_attachment.Content
target_attachment_content_fields = {
"Content": base64.encodestring(source_attachment_content)
}
try:
target_attachment_content = rally.put('AttachmentContent', target_attachment_content_fields)
print "===> Copied AttachmentContent: %s" % target_attachment_content.ref
except RallyRESTAPIError, details:
sys.stderr.write('ERROR: %s \n' % details)
sys.exit(2)
# Next copy the attachment object
target_attachment_fields = {
"Name": source_attachment.Name,
"Description": source_attachment.Description,
"Content": target_attachment_content.ref,
"ContentType": source_attachment.ContentType,
"Size": source_attachment.Size,
"Artifact": dest_TC.ref,
"User": source_attachment.User.ref
}
try:
target_attachment = rally.put('Attachment', target_attachment_fields)
print "===> Copied Attachment: %s" % target_attachment.ref
except RallyRESTAPIError, details:
sys.stderr.write('ERROR: %s \n' % details)
sys.exit(2)
# Copy Tags
source_tags = src_TC.Tags;
target_tags = list()
for source_tag in source_tags:
target_tags.append({"_ref":source_tag.ref})
dest_TC_fields = {
"FormattedID": dest_TC.FormattedID,
"Tags": target_tags
}
try:
update_response = rally.update('TestCase', dest_TC_fields)
except RallyRESTAPIError, details:
sys.stderr.write('ERROR: %s \n' % details)
sys.exit(2)
# Recursive call for each child Test Folder (after creating it)
src_children_TFs = src_TF.Children
dest_children_TFs = dest_TF.Children
existing_dest_TF = {tf.Name:tf for tf in dest_children_TFs}
for src_child_TF in src_children_TFs:
tfName = src_child_TF.Name
# Create Test Folder if needed
if existing_dest_TF.has_key(tfName):
dest_child_TF = existing_dest_TF[tfName]
else:
target_TF_fields = {
'Name': tfName,
'Parent': dest_TF.ref
}
dest_child_TF = rally.put('TestFolder', target_TF_fields)
print "Created Test folder %s (%s)" % (tfName, dest_child_TF.FormattedID)
# Copy Test Cases of this folder
copyTF(src_child_TF, dest_child_TF)
if '__main__' in __name__:
# Get source and destination test folders
src_TF_formatted_id = sys.argv[1]
dest_TF_formatted_id = sys.argv[2]
# Connect to Rally
global is_connected
is_connected = False
connect(5)
# Query for source and target test folders
global rally
src_TF_response = rally.get('TestFolder', fetch=True, query='FormattedID = %s' % src_TF_formatted_id)
dest_TF_response = rally.get('TestFolder', fetch=True, query='FormattedID = %s' % dest_TF_formatted_id)
# Check to make sure folders exist
if src_TF_response.resultCount == 0:
errout('No Source Test Folder Found matching Formatted ID: %s\n' % (src_TF_formatted_id))
sys.exit(4)
if dest_TF_response.resultCount == 0:
errout('No Target Test Folder Found matching Formatted ID: %s\n. Target Test Folder must be created before copying.' % (dest_TF_formatted_id))
sys.exit(4)
# Get Objects of source and target Test Folders
src_TF = src_TF_response.next()
dest_TF = dest_TF_response.next()
# Copy file
copyTF(src_TF, dest_TF)
Related
I have used pyral api
rally = Rally(server, apikey=api_key, workspace=workspace, project=project)
to connect to rally
Than ,
testfolders = rally.get('TestFolder', fetch=True, query=query_criteria)
I need to extract all the test cases defined in the rally as:
TF*****
-TC1
-TC2
-TC3
I need to get all the test cases from the formattedID returned from
testfolders.
for tc in testfolders:
print(tc.Name)
print(tc.FormattedID)# this represents the TF***
tc_link=tc._ref#url for TC's https://rally1.rallydev.com/slm/webservice
query_criteria = 'TestSets = "%s"' % tp_name
testfolders = rally.get('TestFolder', fetch=True, query=query_criteria)
I have tried looking for different combination sets to extract test cases
The tc._ref is actually a
https://rally1.rallydev.com/slm/webservice/v2.0/TestFolder/XXXXX/TestCases
when I tried to open it in browser it gave the entire Test cases list.
I need to extract those test case list .
I tried accessing using urllib to acess the data using python ,but said unauthorized access, I think if I am on the same session authorization shouldnt be an issue since rally object is already instantiated.
Any help on this will be much appreciated!!
Thanks in advance
rally = Rally(server, apikey=api_key, workspace=workspace, project=project)
tp_name = "specific test case "
query_criteria = 'FormattedID = "%s"' % tp_name
testfolders = rally.get('TestFolder', fetch=True, query=query_criteria)
for tc in testfolders:
print(tc.Name)
print(tc.FormattedID)
query_criteria = 'TestSets = "%s"' % tc._ref
response = rally.get('TestCase', fetch=True, query=query_criteria)
print(response)
422 Could not read: could not read all instances of class com.f4tech.slm.domain.TestCase for class TestCase
It's not clear what you are trying to achieve but please take a look at the code below. Probably, it will solve your issue:
query = 'FormattedID = %s'
test_folder_req = rally.get('TestFolder', fetch=True, projectScopeDown=True,
query=query % folder_id) # folder_id == "TF111"
if test_folder_req.resultCount == 0:
print('Rally returned nothing for folder: %s', folder_id)
sys.exit(1)
test_folder = test_folder_req.next()
test_cases = test_folder.TestCases
print('Start working with %s' % folder_id)
print('Test Folder %s contains %s TestCases' % (folder_id, len(test_cases)))
for test_case in test_cases:
print(test_case.FormattedID)
print(test_case.Name)
I am trying to import the snmpSessionBaseClass python module in a script I am running, but I do not have the module installed and I can't seem to find where to download it. Does anyone know the pip or yum command to download and install this module? Thanks!
import netsnmp
sys.path.insert(1, os.path.join(sys.path[0], os.pardir))
from snmpSessionBaseClass import add_common_options, get_common_options, verify_host, get_data
from pynag.Plugins import PluginHelper,ok,critical
The following code needs to be added to a file called snmpSessionBaseClass.py and that file needs to be placed in a directory that is in pythons path.
#!/usr/bin/env python
# Copyright (C) 2016 rsmuc <rsmuc#mailbox.org>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with health_monitoring_plugins. If not, see <http://www.gnu.org/licenses/>.
import pynag
import netsnmp
import os
import sys
dev_null = os.open(os.devnull, os.O_WRONLY)
tmp_stdout = os.dup(sys.stdout.fileno())
def dev_null_wrapper(func, *a, **kwargs):
"""
Temporarily swap stdout with /dev/null, and execute given function while stdout goes to /dev/null.
This is useful because netsnmp writes to stdout and disturbes Icinga result in some cases.
"""
os.dup2(dev_null, sys.stdout.fileno())
return_object = func(*a, **kwargs)
sys.stdout.flush()
os.dup2(tmp_stdout, sys.stdout.fileno())
return return_object
def add_common_options(helper):
# Define the common command line parameters
helper.parser.add_option('-H', help="Hostname or ip address", dest="hostname")
helper.parser.add_option('-C', '--community', dest='community', help='SNMP community of the SNMP service on target host.', default='public')
helper.parser.add_option('-V', '--snmpversion', dest='version', help='SNMP version. (1 or 2)', default=2, type='int')
def get_common_options(helper):
# get the common options
host = helper.options.hostname
version = helper.options.version
community = helper.options.community
return host, version, community
def verify_host(host, helper):
if host == "" or host is None:
helper.exit(summary="Hostname must be specified"
, exit_code=pynag.Plugins.unknown
, perfdata='')
netsnmp_session = dev_null_wrapper(netsnmp.Session,
DestHost=helper.options.hostname,
Community=helper.options.community,
Version=helper.options.version)
try:
# Works around lacking error handling in netsnmp package.
if netsnmp_session.sess_ptr == 0:
helper.exit(summary="SNMP connection failed"
, exit_code=pynag.Plugins.unknown
, perfdata='')
except ValueError as error:
helper.exit(summary=str(error)
, exit_code=pynag.Plugins.unknown
, perfdata='')
# make a snmp get, if it fails (or returns nothing) exit the plugin
def get_data(session, oid, helper, empty_allowed=False):
var = netsnmp.Varbind(oid)
varl = netsnmp.VarList(var)
data = session.get(varl)
value = data[0]
if value is None:
helper.exit(summary="snmpget failed - no data for host "
+ session.DestHost + " OID: " +oid
, exit_code=pynag.Plugins.unknown
, perfdata='')
if not empty_allowed and not value:
helper.exit(summary="snmpget failed - no data for host "
+ session.DestHost + " OID: " +oid
, exit_code=pynag.Plugins.unknown
, perfdata='')
return value
# make a snmp get, but do not exit the plugin, if it returns nothing
# be careful! This funciton does not exit the plugin, if snmp get fails!
def attempt_get_data(session, oid):
var = netsnmp.Varbind(oid)
varl = netsnmp.VarList(var)
data = session.get(varl)
value = data[0]
return value
# make a snmp walk, if it fails (or returns nothing) exit the plugin
def walk_data(session, oid, helper):
tag = []
var = netsnmp.Varbind(oid)
varl = netsnmp.VarList(var)
data = list(session.walk(varl))
if len(data) == 0:
helper.exit(summary="snmpwalk failed - no data for host " + session.DestHost
+ " OID: " +oid
, exit_code=pynag.Plugins.unknown
, perfdata='')
for x in range(0, len(data)):
tag.append(varl[x].tag)
return data, tag
# make a snmp walk, but do not exit the plugin, if it returns nothing
# be careful! This function does not exit the plugin, if snmp walk fails!
def attempt_walk_data(session, oid):
tag = []
var = netsnmp.Varbind(oid)
varl = netsnmp.VarList(var)
data = list(session.walk(varl))
for x in range(0, len(data)):
tag.append(varl[x].tag)
return data, tag
def state_summary(value, name, state_list, helper, ok_value = 'ok', info = None):
"""
Always add the status to the long output, and if the status is not ok (or ok_value),
we show it in the summary and set the status to critical
"""
# translate the value (integer) we receive to a human readable value (e.g. ok, critical etc.) with the given state_list
state_value = state_list[int(value)]
summary_output = ''
long_output = ''
if not info:
info = ''
if state_value != ok_value:
summary_output += ('%s status: %s %s ' % (name, state_value, info))
helper.status(pynag.Plugins.critical)
long_output += ('%s status: %s %s\n' % (name, state_value, info))
return (summary_output, long_output)
def add_output(summary_output, long_output, helper):
"""
if the summary output is empty, we don't add it as summary, otherwise we would have empty spaces (e.g.: '. . . . .') in our summary report
"""
if summary_output != '':
helper.add_summary(summary_output)
helper.add_long_output(long_output)
So I am getting the issue using gitpython:
No handlers could be found for logger "git.remote"
My code
print repo_object.remote() # origin
print repo_object.active_branch # master
print repo_object.active_branch.name # master
refspec = repo_object.active_branch.name + ":refs/for/" + repo_object.active_branch.name
print refspec # master:/refs/for/master
print "Push " + refspec # push master:refs/for/master
print remote.push(refspec) # [<git.remote.PushInfo object at 0x....>]
remote.push(refspec)
pushed_repos.append(repo_name)
print pushed_repos # my project repo
My goal is to push a submodule newly added (created/updated) files to gerrit.
Edit: Request from #Arount
Ok, so I have a function called
del_proj_gerrit(pushed_repos, commit_message, repo_path, repo_name, push)
The arguments has following values:
pushed_repos # []
commit_message # just a commit message
repo_name_path # path to my local repo
repo_name # name of the project repo
push # A value of True is set here
Inside my del_proj_gerrit function I have:
add_all_files("./")
if push == True:
commit_and_push(pushed_repos, commit_message, repo_path, repo_name)
Inside my commit_and_push function I have:
repo_path_new = repo_path+repo_name
repo_object = Repo(repo_path_new) # <git.Repo "C\localpath\.git\modules\repo-project">
if commit_command_line(commit_message, repo_object, repo_name):
# Inside the if-statement you have the code I posted before
Inside the commit_command_line function I have:
cmd = "git commit -m \"%s\"" % commit_message
errmsg = "Failed command:\n" + cmd
success = True
try:
execute_shell_process(cmd, errmsg, True, True)
except CommonProcessError as e:
print "Error during commit for repo '" + repo_name + "' (ret code " + \
str(e.returncode) + ")."
print "Assuming that there was no changes to last commit => continue"
success = False
return success
GitPython uses python logging so you just have to configure it. As per docs the minimal configuration is:
import logging
logging.basicConfig(level=logging.INFO)
I have this python script that basically selects a point by it's ID, then selects all points within a distance and returns only a subset of those that match the type field. i.e. find all hospitals within 3 miles of this location..
My python script works, does what it's supposed to. So I create a GP service from it. Add the service back into the map and run it. Now I notice no matter what distance I use, the data doesn't change. If I delete the created Featureclass to see if it's really working. It does not create a new featureclass but it says it completed successfully.
Now the weird part, if I hit the GP service at the rest endpoint with the parameters it says it works but returns no records. I've been careful to avoid schema locks when using the Rest endpoint ArcMap and ArcCatalog are closed.
It's like the GP service doesn't have permission to write to the sde database, However my sde connection works fine on my PC.
Any ideas?
import arcpy, os, string
from arcpy import env
db = r"Connection to racdev1.sde"
theworkspace = r"Connection to racdev1.sde"
arcpy.env.workspace = theworkspace
arcpy.env.overwriteOutput = True
#facilityID = '1249'
facilityID = arcpy.GetParameterAsText(0)
#facilityIDType= 'PFI'
facilityIDType = arcpy.GetParameterAsText(1)
thedistance = arcpy.GetParameterAsText(2)
#thedistance = '3 miles'
#withindistance = "3 Miles"
withindistance = thedistance + ' Miles'
sql_query = "\"%s\" = '%s'" % ("ID", facilityID)
sql_query2 = "\"%s\" = '%s'" % ("IDTYPE", facilityIDType)
# Local variables:
Facilities = "DOHGIS.NYSDOH_CI_DATA"
featLayer = "thePts"
arcpy.MakeFeatureLayer_management(Facilities, featLayer)
# Process: Select Layer By Attribute
arcpy.SelectLayerByAttribute_management(featLayer, "NEW_SELECTION", sql_query)
# Process: Select Layer By Location 311
arcpy.SelectLayerByLocation_management(featLayer, "WITHIN_A_DISTANCE",featLayer, withindistance, "NEW_SELECTION")
#print " now for the subset"
arcpy.SelectLayerByAttribute_management("thePts", "SUBSET_SELECTION", sql_query2 )
# creaate the new featureclss..
arcpy.CopyFeatures_management("thePts",'DOHGIS.NYSDOH_FacilitiesQuery')
#print "Done"
I'd like to be able to query Rally for an existing defect and then copy that defect changing only a couple of fields while maintaining all attachments. Is there a simple way to do this? I tried calling rally.create and passing the existing defect object, but it failed to serialize all members into JSON. Ultimately, it would be nice if pyral was extended to include this kind of functionality.
Instead, I've written some code to copy each python-native attribute of the existing defect and then use .ref for everything else. It seems to be working quite well. I've leveraged Mark W's code for copying attachments and that's working great also. One remaining frustration is that copying the iteration isn't working. When I call .ref on the Iteration attribute, I get this:
>>> s
<pyral.entity.Defect object at 0x029A74F0>
>>> s.Iteration
<pyral.entity.Iteration object at 0x029A7710>
>>> s.Iteration.ref
No classFor item for |UserIterationCapacity|
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "c:\python27\lib\site-packages\pyral\entity.py", line 119, in __getattr__
hydrateAnInstance(self._context, item, existingInstance=self)
File "c:\python27\lib\site-packages\pyral\restapi.py", line 77, in hydrateAnInstance
return hydrator.hydrateInstance(item, existingInstance=existingInstance)
File "c:\python27\lib\site-packages\pyral\hydrate.py", line 62, in hydrateInstance
self._setAppropriateAttrValueForType(instance, attrName, attrValue, 1)
File "c:\python27\lib\site-packages\pyral\hydrate.py", line 128, in _setAppropriateAttrValueForType
elements = [self._unravel(element) for element in attrValue]
File "c:\python27\lib\site-packages\pyral\hydrate.py", line 162, in _unravel
return self._basicInstance(thing)
File "c:\python27\lib\site-packages\pyral\hydrate.py", line 110, in _basicInstance
raise KeyError(itemType)
KeyError: u'UserIterationCapacity'
>>>
Does this look like an issue with Rally or perhaps an issue with a custom field that our project admin might have caused? I was able to work around it by building the ref from the oid:
newArtifact["Iteration"] = { "_ref": "iteration/" + currentArtifact.Iteration.oid }
This feels kludgy to me though.
Check out the Python answer (there's 2 answers for it, the other one is for Ruby) to this question:
Rally APIs: How to copy Test Folder and member Test Cases
The answer contains a python script that copies Test Cases, with attachments. Although the script is for Test Cases, the logic should be quite readily adaptable to Defects, as the operations will be fundamentally the same - only the field attributes will differ. The script copies with Attachments, Tags, etc, pretty much the whole artifact.
Final solution including Mark W's code for copying attachments
def getDataCopy( data ):
""" Given a piece of data, figure out how to copy it. If it's a native python type
like a string or numeric, just return the value. If it's a rally object, return
the ref to it. If it's a list, iterate and call ourself recursively for the
list members. """
if isinstance( data, types.ListType ):
copyData = []
for entry in data:
copyData.append( getDataCopy(entry) )
elif hasattr( data, "ref" ):
copyData = { "_ref": data.ref }
else:
copyData = data
return copyData
def getArtifactCopy( artifact ):
""" Build a dictionary based on the values in the specified artifact. This dictionary
can then be passed to a rallyConn.put() call to actually create the new entry in
Rally. Attachments and Tasks must be copied seperately, since they require creation
of additional artifacts """
newArtifact = {}
for attrName in artifact.attributes():
# Skip the attributes that we can't or shouldn't handle directly
if attrName.startswith("_") or attrName == "oid" or attrName == "Iteration" or attrName == "Attachments":
continue
attrValue = getattr( artifact, attrName )
newArtifact[attrName] = getDataCopy( attrValue )
if getattr( artifact, "Iteration", None ) != None:
newArtifact["Iteration"] = { "_ref": "iteration/" + artifact.Iteration.oid }
return newArtifact
def copyAttachments( rallyConn, oldArtifact, newArtifact ):
""" For each attachment in the old artifact, create new attachments and attach them to the new artifact"""
# Copy Attachments
source_attachments = rallyConn.getAttachments(oldArtifact)
for source_attachment in source_attachments:
# First copy the content
source_attachment_content = source_attachment.Content
target_attachment_content_fields = { "Content": base64.encodestring(source_attachment_content) }
try:
target_attachment_content = rallyConn.put( 'AttachmentContent', target_attachment_content_fields )
print "\t===> Copied AttachmentContent: %s" % target_attachment_content.ref
except pyral.RallyRESTAPIError, details:
sys.stderr.write('ERROR: %s \n' % details)
sys.exit(2)
# Next copy the attachment object
target_attachment_fields = {
"Name": source_attachment.Name,
"Description": source_attachment.Description,
"Content": target_attachment_content.ref,
"ContentType": source_attachment.ContentType,
"Size": source_attachment.Size,
"User": source_attachment.User.ref
}
# Attach it to the new artifact
target_attachment_fields["Artifact"] = newArtifact.ref
try:
target_attachment = rallyConn.put( source_attachment._type, target_attachment_fields)
print "\t===> Copied Attachment: '%s'" % target_attachment.Name
except pyral.RallyRESTAPIError, details:
sys.stderr.write('ERROR: %s \n' % details)
sys.exit(2)
def copyTasks( rallyConn, oldArtifact, newArtifact ):
""" Iterate over the old artifacts tasks and create new ones, attaching them to the new artifact """
for currentTask in oldArtifact.Tasks:
newTask = getArtifactCopy( currentTask )
# Assign the new task to the new artifact
newTask["WorkProduct"] = newArtifact.ref
# Push the new task into rally
newTaskObj = rallyConn.put( currentTask._type, newTask )
# Copy any attachments the task had
copyAttachments( rallyConn, currentTask, newTaskObj )
def copyDefect( rallyConn, currentDefect, addlUpdates = {} ):
""" Copy a defect including its attachments and tasks. Add the new defect as a
duplicate to the original """
newArtifact = getArtifactCopy( currentDefect )
# Add the current defect as a duplicate for the new one
newArtifact["Duplicates"].append( { "_ref": currentDefect.ref } )
# Copy in any updates that might be needed
for (attrName, attrValue) in addlUpdates.items():
newArtifact[attrName] = attrValue
print "Copying %s: %s..." % (currentDefect.Project.Name, currentDefect.FormattedID),
newDefect = rallyConn.create( currentDefect._type, newArtifact )
print "done, new item", newDefect.FormattedID
print "\tCopying attachments"
copyAttachments( rallyConn, currentDefect, newDefect )
print "\tCopying tasks"
copyTasks( rallyConn, currentDefect, newDefect )