from utils.urlopener import mkurlopener\r
import logging\r
import time\r
+import urllib2\r
+import urllib\r
+import json\r
\r
log = logging.getLogger(__name__)\r
\r
"""\r
Represents a jenkins environment.\r
"""\r
- def __init__(self, baseurl, proxyhost=None, proxyport=None, proxyuser=None, proxypass=None):\r
+ def __init__(self, baseurl, username=None, password=None, proxyhost=None, proxyport=None, proxyuser=None, proxypass=None):\r
+ """\r
+\r
+ :param baseurl: baseurl for jenkins instance including port, str\r
+ :param username: username for jenkins auth, str\r
+ :param password: password for jenkins auth, str\r
+ :param proxyhost: proxyhostname, str\r
+ :param proxyport: proxyport, int\r
+ :param proxyuser: proxyusername for proxy auth, str\r
+ :param proxypass: proxypassword for proxyauth, str\r
+ :return: a Jenkins obj\r
+ """\r
+ self.username = username\r
+ self.password = password\r
self.proxyhost = proxyhost\r
self.proxyport = proxyport\r
self.proxyuser = proxyuser\r
JenkinsBase.__init__( self, baseurl )\r
\r
def get_proxy_auth(self):\r
- return (self.proxyhost, self.proxyport, self.proxyuser, self.proxypass)\r
+ return self.proxyhost, self.proxyport, self.proxyuser, self.proxypass\r
+\r
+ def get_jenkins_auth(self):\r
+ return self.username, self.password, self.baseurl\r
+\r
+ def get_auth(self):\r
+ auth_args = []\r
+ auth_args.extend(self.get_jenkins_auth())\r
+ auth_args.extend(self.get_proxy_auth())\r
+ log.debug("args: %s" % auth_args)\r
+ return auth_args\r
+\r
\r
def get_opener( self ):\r
- return mkurlopener(*self.get_proxy_auth())\r
+ return mkurlopener(*self.get_auth())\r
\r
def validate_fingerprint( self, id ):\r
obj_fingerprint = Fingerprint(self.baseurl, id, jenkins_obj=self)\r
def get_node_dict(self):\r
"""Get registered slave nodes on this instance"""\r
url = self.python_api_url(self.get_node_url())\r
- return dict(self.get_data(url))\r
+ node_dict = dict(self.get_data(url))\r
+ return dict(\r
+ (node['displayName'], self.python_api_url(self.get_node_url(node['displayName'])))\r
+ for node in node_dict['computer'])\r
\r
def get_node(self, nodename):\r
"""Get a node object for a specific node"""\r
"""Return the url for nodes"""\r
url = "%(baseurl)s/computer/%(nodename)s" % {'baseurl': self.baseurl, 'nodename': nodename}\r
return url\r
+\r
+ def has_node(self, nodename):\r
+ """\r
+ Does a node by the name specified exist\r
+ :param nodename: string, hostname\r
+ :return: boolean\r
+ """\r
+ return nodename in self.get_node_dict()\r
+\r
+ def delete_node(self, nodename):\r
+ """\r
+ Remove a node from the managed slave list\r
+ Please note that you cannot remove the master node\r
+\r
+ :param nodename: string holding a hostname\r
+ :return: None\r
+ """\r
+ assert self.has_node(nodename), "This node: %s is not registered as a slave" % nodename\r
+ assert nodename != "master", "you cannot delete the master node"\r
+ url = "%s/doDelete" % self.get_node_url(nodename)\r
+ fn_urlopen = self.get_jenkins_obj().get_opener()\r
+ try:\r
+ stream = fn_urlopen(url)\r
+ html_result = stream.read()\r
+ except urllib2.HTTPError, e:\r
+ log.debug("Error reading %s" % url)\r
+ raise\r
+ return not self.has_node(nodename)\r
+\r
+ def create_node(self, name, num_executors=2, node_description=None,\r
+ remote_fs='/var/lib/jenkins', labels=None, exclusive=False):\r
+ """\r
+ Create a new slave node by name.\r
+\r
+ :param name: fqdn of slave, str\r
+ :param num_executors: number of executors, int\r
+ :param node_description: a freetext field describing the node\r
+ :param remote_fs: jenkins path, str\r
+ :param labels: labels to associate with slave, str\r
+ :param exclusive: tied to specific job, boolean\r
+ :return: node obj\r
+ """\r
+ NODE_TYPE = 'hudson.slaves.DumbSlave$DescriptorImpl'\r
+ MODE = 'NORMAL'\r
+ if self.has_node(name):\r
+ return Node(nodename=name, baseurl=self.get_node_url(nodename=name), jenkins_obj=self)\r
+ if exclusive:\r
+ MODE = 'EXCLUSIVE'\r
+ params = {\r
+ 'name' : name,\r
+ 'type' : NODE_TYPE,\r
+ 'json' : json.dumps ({\r
+ 'name' : name,\r
+ 'nodeDescription' : node_description,\r
+ 'numExecutors' : num_executors,\r
+ 'remoteFS' : remote_fs,\r
+ 'labelString' : labels,\r
+ 'mode' : MODE,\r
+ 'type' : NODE_TYPE,\r
+ 'retentionStrategy' : { 'stapler-class' : 'hudson.slaves.RetentionStrategy$Always' },\r
+ 'nodeProperties' : { 'stapler-class-bag' : 'true' },\r
+ 'launcher' : { 'stapler-class' : 'hudson.slaves.JNLPLauncher' }\r
+ })\r
+ }\r
+ url = "%(nodeurl)s/doCreateItem?%(params)s" % {\r
+ 'nodeurl': self.get_node_url(),\r
+ 'params': urllib.urlencode(params)\r
+ }\r
+ print url\r
+ fn_urlopen = self.get_jenkins_obj().get_opener()\r
+ try:\r
+ stream = fn_urlopen(url)\r
+ html_result = stream.read()\r
+ except urllib2.HTTPError, e:\r
+ log.debug("Error reading %s" % url)\r
+ log.exception(e)\r
+ raise\r
+ return Node(nodename=name, baseurl=self.get_node_url(nodename=name), jenkins_obj=self)\r
def __str__(self):
return self.id()
+ def get_node_data(self):
+ return self._data
+
def is_online(self):
return not self._data['offline']
-#NODES = 'computer/api/json'
-#CREATE_NODE = 'computer/doCreateItem?%s'
-#DELETE_NODE = 'computer/%(name)s/doDelete'
-#NODE_INFO = 'computer/%(name)s/api/json?depth=0'
-#NODE_TYPE = 'hudson.slaves.DumbSlave$DescriptorImpl'
-#
-#def get_nodes(self):
-# '''
-# Get a list of nodes registered on the jenkins instance
-# returns a list of node dictionaries
-# '''
-# try:
-# response = self.jenkins_open(urllib2.Request(self.server + NODES%locals()))
-# if response:
-# return json.loads(response)['computer']
-# else:
-# raise JenkinsException('Cannot get nodes information')
-# except urllib2.HTTPError:
-# raise JenkinsException('Cannot get nodes information')
-# except ValueError:
-# raise JenkinsException("Could not parse JSON info for nodes information")
-#
-#def get_node_info(self, name):
-# '''
-# Get node information dictionary
-#
-# :param name: Node name, ``str``
-# :returns: Dictionary of node info, ``dict``
-# '''
-# try:
-# response = self.jenkins_open(urllib2.Request(self.server + NODE_INFO%locals()))
-# if response:
-# return json.loads(response)
-# else:
-# raise JenkinsException('node[%s] does not exist'%name)
-# except urllib2.HTTPError:
-# raise JenkinsException('node[%s] does not exist'%name)
-# except ValueError:
-# raise JenkinsException("Could not parse JSON info for node[%s]"%name)
-#
-#def node_exists(self, name):
-# '''
-# :param name: Name of Jenkins node, ``str``
-# :returns: ``True`` if Jenkins node exists
-# '''
-# try:
-# self.get_node_info(name)
-# return True
-# except JenkinsException:
-# return False
-#
-#def delete_node(self, name):
-# '''
-# Delete Jenkins node permanently.
-#
-# :param name: Name of Jenkins node, ``str``
-# '''
-# self.get_node_info(name)
-# self.jenkins_open(urllib2.Request(self.server + DELETE_NODE%locals(), ''))
-# if self.node_exists(name):
-# raise JenkinsException('delete[%s] failed'%(name))
-#
-#def create_node(self, name, numExecutors=2, nodeDescription=None,
-# remoteFS='/var/lib/jenkins', labels=None, exclusive=False):
-# '''
-# :param name: name of node to create, ``str``
-# :param numExecutors: number of executors for node, ``int``
-# :param nodeDescription: Description of node, ``str``
-# :param remoteFS: Remote filesystem location to use, ``str``
-# :param labels: Labels to associate with node, ``str``
-# :param exclusive: Use this node for tied jobs only, ``bool``
-# '''
-# if self.node_exists(name):
-# raise JenkinsException('node[%s] already exists'%(name))
-#
-# mode = 'NORMAL'
-# if exclusive:
-# mode = 'EXCLUSIVE'
-#
-# params = {
-# 'name' : name,
-# 'type' : NODE_TYPE,
-# 'json' : json.dumps ({
-# 'name' : name,
-# 'nodeDescription' : nodeDescription,
-# 'numExecutors' : numExecutors,
-# 'remoteFS' : remoteFS,
-# 'labelString' : labels,
-# 'mode' : mode,
-# 'type' : NODE_TYPE,
-# 'retentionStrategy' : { 'stapler-class' : 'hudson.slaves.RetentionStrategy$Always' },
-# 'nodeProperties' : { 'stapler-class-bag' : 'true' },
-# 'launcher' : { 'stapler-class' : 'hudson.slaves.JNLPLauncher' }
-# })
-# }
-#
-# self.jenkins_open(urllib2.Request(self.server + CREATE_NODE%urllib.urlencode(params)))
-# if not self.node_exists(name):
-# raise JenkinsException('create[%s] failed'%(name))
+ def is_jnlpagent(self):
+ return self._data['jnlpAgent']
+
+ def is_idle(self):
+ return self._data['idle']
+
import urllib2\r
+import urlparse\r
+import base64\r
\r
import logging\r
\r
log = logging.getLogger( __name__ )\r
\r
-DEFAULT_PROXYPORT = 80\r
-DEFAULT_PROXY_PASS = "Research123"\r
-DEFAULT_PROXY_USER = "wsa_oblicqs_dev"\r
+class PreemptiveBasicAuthHandler(urllib2.BaseHandler):\r
\r
-def mkurlopener( proxyhost, proxyport, proxyuser, proxypass ):\r
- if not proxyhost:\r
- return urllib2.urlopen\r
- else:\r
- if proxyport is None:\r
- proxyport = DEFAULT_PROXYPORT\r
+ def __init__(self, password_mgr=None):\r
+ if password_mgr is None:\r
+ password_mgr = urllib2.HTTPPasswordMgrWithDefaultRealm()\r
+ self.passwd = password_mgr\r
+ self.add_password = self.passwd.add_password\r
\r
- if proxypass is None:\r
- proxypass = DEFAULT_PROXY_PASS\r
+ def http_request(self,req):\r
+ uri = req.get_full_url()\r
+ user, pw = self.passwd.find_user_password(None,uri)\r
+ log.debug('ADDING REQUEST HEADER for uri (%s): %s:%s' % (uri,user,pw))\r
+ if pw is None: return req\r
+ raw = "%s:%s" % (user, pw)\r
+ auth = 'Basic %s' % base64.b64encode(raw).strip()\r
+ req.add_unredirected_header('Authorization', auth)\r
+ return req\r
\r
- if proxyuser is None:\r
- proxyuser = DEFAULT_PROXY_USER\r
+def mkurlopener( jenkinsuser, jenkinspass, jenkinsurl, proxyhost, proxyport, proxyuser, proxypass ):\r
+ handlers = []\r
+ for handler in get_jenkins_auth_handler(jenkinsuser=jenkinsuser, jenkinspass=jenkinspass, jenkinsurl=jenkinsurl):\r
+ handlers.append(handler)\r
+ for handler in get_proxy_handler(proxyhost, proxyport, proxyuser, proxypass):\r
+ handlers.append(handler)\r
+ opener = urllib2.build_opener(*handlers)\r
+ return opener.open\r
\r
- assert type( proxyport ) == int, "Proxy port should be an int, got %s" % repr( proxyport )\r
- assert type( proxypass ) == str, "Proxy password should be a sting, got %s" % repr( proxypass )\r
- assert type( proxyuser ) == str, "Proxy username should be a string, got %s" % repr( proxyuser )\r
+def get_jenkins_auth_handler(jenkinsuser, jenkinspass, jenkinsurl):\r
+ """\r
+ Get a basic authentification handler for jenkins\r
+ :param jenkinsuser: jenkins username, str\r
+ :param jenkinspass: jenkins password, str\r
+ :param jenkinsurl: jenkins base url, str\r
+ :return: a list of handlers\r
+ """\r
+ for param in jenkinsuser, jenkinspass, jenkinsurl:\r
+ if param is None:\r
+ return []\r
+ assert type(jenkinsuser) == str, "Jenkins username should be a string, got %s" % repr(jenkinsuser)\r
+ assert type(jenkinspass) == str, "Jenkins password should be a string, git %s" % repr(jenkinspass)\r
+# hostname = urlparse.urlsplit(jenkinsurl).hostname\r
+ handler = PreemptiveBasicAuthHandler()\r
+ handler.add_password(None, jenkinsurl, jenkinsuser, jenkinspass)\r
+ log.debug('Adding BasicAuthHandler: url:%s, user:%s,' % (jenkinsurl, jenkinsuser))\r
+ return [ handler ]\r
\r
- proxy_spec = { 'http': 'http://%s:%i/' % (proxyhost, proxyport),\r
- 'https': 'http://%s:%i/' % (proxyhost, proxyport) }\r
+def get_proxy_handler(proxyhost, proxyport, proxyuser, proxypass):\r
+ """\r
+ Get a configured handler for a proxy\r
\r
- proxy_handler = urllib2.ProxyHandler( proxy_spec )\r
- proxy_auth_handler = urllib2.HTTPBasicAuthHandler()\r
- proxy_auth_handler.add_password( None, proxyhost, proxyuser, proxypass )\r
+ :param proxyhost: proxy hostname, str\r
+ :param proxyport: proxy port, int\r
+ :param proxyuser: proxy username, str\r
+ :param proxypass: proxy password, str\r
+ :return: list of handlers\r
+ """\r
+ for param in proxyhost, proxyport, proxyuser, proxypass:\r
+ if param is None:\r
+ return []\r
+ assert type( proxyport ) == int, "Proxy port should be an int, got %s" % repr( proxyport )\r
+ assert type( proxypass ) == str, "Proxy password should be a sting, got %s" % repr( proxypass )\r
+ assert type( proxyuser ) == str, "Proxy username should be a string, got %s" % repr( proxyuser )\r
\r
- opener = urllib2.build_opener(proxy_handler, proxy_auth_handler)\r
+ proxy_spec = { 'http': 'http://%s:%i/' % (proxyhost, proxyport),\r
+ 'https': 'http://%s:%i/' % (proxyhost, proxyport) }\r
+\r
+ proxy_handler = urllib2.ProxyHandler( proxy_spec )\r
+ proxy_auth_handler = urllib2.HTTPBasicAuthHandler()\r
+ proxy_auth_handler.add_password( None, proxyhost, proxyuser, proxypass )\r
+ return [proxy_handler, proxy_auth_handler]\r
\r
- return opener.open\r