jenkins: support token authentication
diff mbox

Message ID 20161121084115.14902-1-andrew.donnellan@au1.ibm.com
State Accepted
Headers show

Commit Message

Andrew Donnellan Nov. 21, 2016, 8:41 a.m. UTC
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@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(-)

Comments

Andrew Donnellan Nov. 21, 2016, 8:47 a.m. UTC | #1
On 21/11/16 19:41, Andrew Donnellan wrote:
> 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@au1.ibm.com>

Closes: #33 ("Jenkins authentication")
Andrew Donnellan Nov. 22, 2016, 12:57 a.m. UTC | #2
On 21/11/16 19:41, Andrew Donnellan wrote:
> 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@au1.ibm.com>

Applied to master: 31ec3a041c9dbfe288ae6bc975c217e9f17c0ddb
Russell Currey Nov. 22, 2016, 1:42 a.m. UTC | #3
On Mon, 2016-11-21 at 19:41 +1100, Andrew Donnellan wrote:
> 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@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

these should be in quotes

>  
>  [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 Nov. 22, 2016, 1:51 a.m. UTC | #4
On 22/11/16 12:42, Russell Currey wrote:
>> +username = patchwork
>> +token = 33333333333333333333333333333333
>
> these should be in quotes

derp, I even had to fix this in my own config... will fix.

Patch
diff mbox

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>
 }