[snowpatch] [PATCH] jenkins: support token authentication

Andrew Donnellan andrew.donnellan at au1.ibm.com
Mon Nov 21 19:41:15 AEDT 2016


Allow a username and token to be specified in the Jenkins configuration.

To enable this, add a few helper methods for JenkinsBackend that spit out
Authorization headers and wrap the hyper client's get() and post() methods
to use those headers.

Also, update the example configuration, 'openpower.toml', to include fake
credentials.

Signed-off-by: Andrew Donnellan <andrew.donnellan at au1.ibm.com>
---
 examples/openpower.toml |  3 ++-
 src/jenkins.rs          | 36 ++++++++++++++++++++++++++++++------
 src/main.rs             |  2 ++
 src/settings.rs         |  2 ++
 4 files changed, 36 insertions(+), 7 deletions(-)

diff --git a/examples/openpower.toml b/examples/openpower.toml
index 28671a4..8446865 100644
--- a/examples/openpower.toml
+++ b/examples/openpower.toml
@@ -24,7 +24,8 @@ polling_interval = 10 # polling interval in minutes
 [jenkins]
 url = "https://jenkins.ozlabs.ibm.com"
 port = 443
-# TODO: jenkins auth (our testing jenkins has no auth)
+username = patchwork
+token = 33333333333333333333333333333333
 
 [projects]
 
diff --git a/src/jenkins.rs b/src/jenkins.rs
index f450243..0a0a699 100644
--- a/src/jenkins.rs
+++ b/src/jenkins.rs
@@ -30,7 +30,8 @@ use std::thread::sleep;
 use std::sync::Arc;
 
 use hyper::Client;
-use hyper::header::Location;
+use hyper::client::{IntoUrl, RequestBuilder};
+use hyper::header::{Headers, Basic, Authorization, Location};
 use rustc_serialize::json::Json;
 
 // Constants
@@ -45,7 +46,8 @@ pub trait CIBackend { // TODO: Separate out
 pub struct JenkinsBackend {
     pub base_url: String,
     pub hyper_client: Arc<Client>,
-    // TODO: Authentication
+    pub username: Option<String>,
+    pub token: Option<String>,
 }
 
 impl CIBackend for JenkinsBackend {
@@ -60,9 +62,8 @@ impl CIBackend for JenkinsBackend {
             .extend_pairs(params)
             .finish();
 
-        let res = self.hyper_client
-            .post(&format!("{}/job/{}/buildWithParameters?{}",
-                           self.base_url, job_name, params))
+        let res = self.post(&format!("{}/job/{}/buildWithParameters?{}",
+                                     self.base_url, job_name, params))
             .send().expect("HTTP request error"); // TODO don't panic here
 
         match res.headers.get::<Location>() {
@@ -78,10 +79,33 @@ pub enum JenkinsBuildStatus {
 }
 
 impl JenkinsBackend {
+    fn headers(&self) -> Headers {
+        let mut headers = Headers::new();
+        if let Some(ref username) = self.username {
+            headers.set(
+                Authorization(
+                    Basic {
+                        username: username.clone(),
+                        password: self.token.clone(),
+                    }
+                )
+            );
+        }
+        headers
+    }
+
+    fn get<U: IntoUrl>(&self, url: U) -> RequestBuilder {
+        self.hyper_client.get(url).headers(self.headers())
+    }
+
+    fn post<U: IntoUrl>(&self, url: U) -> RequestBuilder {
+        self.hyper_client.post(url).headers(self.headers())
+    }
+
     fn get_api_json_object(&self, base_url: &str) -> rustc_serialize::json::Object {
         // TODO: Don't panic on failure, fail more gracefully
         let url = format!("{}api/json", base_url);
-        let mut resp = self.hyper_client.get(&url).send().expect("HTTP request error");
+        let mut resp = self.get(&url).send().expect("HTTP request error");
         let mut result_str = String::new();
         resp.read_to_string(&mut result_str)
             .unwrap_or_else(|err| panic!("Couldn't read from server: {}", err));
diff --git a/src/main.rs b/src/main.rs
index e1f1885..17437c4 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -95,6 +95,8 @@ fn run_tests(settings: &Config, client: Arc<Client>, project: &Project, tag: &st
     let jenkins = JenkinsBackend {
         base_url: settings.jenkins.url.clone(),
         hyper_client: client,
+        username: settings.jenkins.username.clone(),
+        token: settings.jenkins.token.clone(),
     };
     let project = project.clone();
     for job_params in project.jobs.iter() {
diff --git a/src/settings.rs b/src/settings.rs
index 80d2759..a4a5614 100644
--- a/src/settings.rs
+++ b/src/settings.rs
@@ -41,6 +41,8 @@ pub struct Patchwork {
 pub struct Jenkins {
     pub url: String,
     pub port: Option<u16>,
+    // TODO: fail if we only get one of username or token
+    pub username: Option<String>,
     pub token: Option<String>
 }
 
-- 
Andrew Donnellan              OzLabs, ADL Canberra
andrew.donnellan at au1.ibm.com  IBM Australia Limited



More information about the snowpatch mailing list