From patchwork Tue Dec 11 03:45:58 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Russell Currey X-Patchwork-Id: 1010831 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [203.11.71.2]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 43DQy62JJYz9s3Z for ; Tue, 11 Dec 2018 14:52:46 +1100 (AEDT) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=russell.cc Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=messagingengine.com header.i=@messagingengine.com header.b="FHT2JPXh"; dkim-atps=neutral Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 43DQy60XZVzDqQy for ; Tue, 11 Dec 2018 14:52:46 +1100 (AEDT) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=russell.cc Authentication-Results: lists.ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=messagingengine.com header.i=@messagingengine.com header.b="FHT2JPXh"; dkim-atps=neutral X-Original-To: snowpatch@lists.ozlabs.org Delivered-To: snowpatch@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=pass (helo) smtp.helo=out1-smtp.messagingengine.com (client-ip=66.111.4.25; helo=out1-smtp.messagingengine.com; envelope-from=ruscur@russell.cc; receiver=) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=russell.cc Authentication-Results: lists.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=messagingengine.com header.i=@messagingengine.com header.b="FHT2JPXh"; dkim-atps=neutral Received: from out1-smtp.messagingengine.com (out1-smtp.messagingengine.com [66.111.4.25]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 43DQxx4nR9zDqNF for ; Tue, 11 Dec 2018 14:52:37 +1100 (AEDT) Received: from compute6.internal (compute6.nyi.internal [10.202.2.46]) by mailout.nyi.internal (Postfix) with ESMTP id 758AA21C82; Mon, 10 Dec 2018 22:45:40 -0500 (EST) Received: from mailfrontend1 ([10.202.2.162]) by compute6.internal (MEProxy); Mon, 10 Dec 2018 22:45:40 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-transfer-encoding:date:from :in-reply-to:message-id:mime-version:references:subject:to :x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm1; bh=aBJhC9dusXpmfzXBEMEasxHjFUOLYwqGcwpGM1DfSPA=; b=FHT2JPXh lRuc7gKyRxoCM8tVPqdp9Bhq3Z88XUZ19Km15YqLIbqEnz9Eri8jJFfC8RYi61Np Y15kcHxjlJMGen4DZoRcpjVZeEimbj7i7gnUayfmJLZoJQOkXMipyx/lLOhau2sW tMglJSmTnl3UK9NQva0CvENJEo3NkyKT3DPb02KEX1GwKQuEz7KmCZ4SZTAU+9B9 rlSXiHjIHkwdaEXQTQRBmuZY6QS/ZQiXVeOShTEX70WP0+KZJFGIq2/hivdyQFiZ 8i8FlcxYb3LxfY7mrSZoT+dnjKMcSO0u1bvU9gj9wMM6pFvVDSfC9O1S5cqgEFRW qiPgC2ud0tb1yw== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedtkedrudegiedgieegucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfquhhtnecuuegrihhlohhuthemucef tddtnecufghrlhcuvffnffculdeftddmnecujfgurhephffvufffkffojghfggfgsedtke ertdertddtnecuhfhrohhmpeftuhhsshgvlhhlucevuhhrrhgvhicuoehruhhstghurhes rhhushhsvghllhdrtggtqeenucfkphepvddtvddrkedurddukedrfedtnecurfgrrhgrmh epmhgrihhlfhhrohhmpehruhhstghurhesrhhushhsvghllhdrtggtnecuvehluhhsthgv rhfuihiivgeptd X-ME-Proxy: Received: from crackle.ozlabs.ibm.com.au.ibm.com (bh02i525f01.au.ibm.com [202.81.18.30]) by mail.messagingengine.com (Postfix) with ESMTPA id AB557E462B; Mon, 10 Dec 2018 22:45:38 -0500 (EST) From: Russell Currey To: snowpatch@lists.ozlabs.org Date: Tue, 11 Dec 2018 14:45:58 +1100 Message-Id: <20181211034601.29061-2-ruscur@russell.cc> X-Mailer: git-send-email 2.19.2 In-Reply-To: <20181211034601.29061-1-ruscur@russell.cc> References: <20181211034601.29061-1-ruscur@russell.cc> MIME-Version: 1.0 Subject: [snowpatch] [PATCH v2 2/5] Update to reqwest 0.9 and temporarily disable pagination X-BeenThere: snowpatch@lists.ozlabs.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Continuous Integration for patch-based workflows List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Russell Currey Errors-To: snowpatch-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "snowpatch" reqwest 0.8 uses an older version of hyper which uses an older version of the openssl crate, which means that snowpatch can't build on any particularly modern distribution. Updating reqwest to 0.9 however is quite the ordeal, because it now uses hyper 0.12 which no longer has stringly typed header values, which isn't too much hassle... except for the following: - authorization, which we now have to do manually, which is particularly annoying for the Basic Auth case - pagination using the Link header, which is now a significant undertaking to parse I am opting on the side of disabling pagination until some kind of helper is released, or we put in the effort to write one ourselves. Signed-off-by: Russell Currey --- Cargo.toml | 3 ++- src/jenkins.rs | 47 +++++++++++++++++++++++------------------ src/main.rs | 1 + src/patchwork.rs | 54 ++++++++++++++++++++++++------------------------ 4 files changed, 57 insertions(+), 48 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 494c663..d17b0cf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,7 +28,7 @@ license = "GPL-2.0+" keywords = ["CI", "patch", "patchwork", "jenkins", "git"] [dependencies] -reqwest = "0.8" +reqwest = "0.9" git2 = "0.7" url = "1.7" serde = "1.0" @@ -39,3 +39,4 @@ tempdir = "0.3" docopt = "1.0" log = "0.4" env_logger = "0.5" +base64 = "0.9" diff --git a/src/jenkins.rs b/src/jenkins.rs index 0aa5212..4906139 100644 --- a/src/jenkins.rs +++ b/src/jenkins.rs @@ -20,6 +20,7 @@ // * get artifacts + console log from completed build (do we make this configurable?) // * integrate into snowpatch worker thread +extern crate base64; extern crate reqwest; extern crate url; @@ -29,7 +30,7 @@ use std::sync::Arc; use std::thread::sleep; use std::time::Duration; -use reqwest::header::{Authorization, Basic, Headers, Location}; +use reqwest::header::{HeaderMap, AUTHORIZATION, LOCATION}; use reqwest::{Client, IntoUrl, Response}; use serde_json::{self, Value}; @@ -68,14 +69,15 @@ impl CIBackend for JenkinsBackend { .extend_pairs(params) .finish(); - let resp = - self.post_url(&format!( + let resp = self + .post_url(&format!( "{}/job/{}/buildWithParameters?{}", self.base_url, job_name, params )).expect("HTTP request error"); // TODO don't panic here - match resp.headers().get::() { - Some(loc) => Ok(loc.to_string()), + match resp.headers().get(LOCATION) { + // TODO do we actually have to return a string, coud we change the API? + Some(loc) => Ok(loc.to_str().unwrap().to_string()), None => Err("No Location header returned"), } } @@ -88,14 +90,20 @@ pub enum JenkinsBuildStatus { } impl JenkinsBackend { - fn headers(&self) -> Headers { - let mut headers = Headers::new(); + fn headers(&self) -> HeaderMap { + let mut headers = HeaderMap::new(); if let Some(ref username) = self.username { - headers.set(Authorization(Basic { - username: username.clone(), - password: self.token.clone(), - })); - } + if let Some(ref token) = self.token { + headers.insert( + AUTHORIZATION, + format!( + "Basic {}", + base64::encode(&format!("{}:{}", username, token)) + ).parse() + .unwrap(), + ); + } + }; headers } @@ -139,14 +147,13 @@ impl JenkinsBackend { match entry.get("executable") { Some(exec) => { return Some( - exec - .as_object() // Option - .unwrap() // BTreeMap - .get("url") // Option<&str> - .unwrap() // &str ? - .as_str() - .unwrap() - .to_string(), + exec.as_object() // Option + .unwrap() // BTreeMap + .get("url") // Option<&str> + .unwrap() // &str ? + .as_str() + .unwrap() + .to_string(), ); } None => sleep(Duration::from_millis(JENKINS_POLLING_INTERVAL)), diff --git a/src/main.rs b/src/main.rs index 7a0deba..6fe0bdb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -30,6 +30,7 @@ extern crate env_logger; extern crate serde; #[macro_use] extern crate serde_derive; +extern crate base64; extern crate serde_json; extern crate toml; diff --git a/src/patchwork.rs b/src/patchwork.rs index a0722c7..f7c908f 100644 --- a/src/patchwork.rs +++ b/src/patchwork.rs @@ -25,9 +25,7 @@ use std::result::Result; use tempdir::TempDir; use reqwest; -use reqwest::header::{ - qitem, Accept, Authorization, Basic, Connection, ContentType, Headers, Link, RelationType, -}; +use reqwest::header::{HeaderMap, ACCEPT, AUTHORIZATION, CONTENT_TYPE}; use reqwest::Client; use reqwest::Response; use reqwest::StatusCode; @@ -35,6 +33,8 @@ use reqwest::StatusCode; use serde::{self, Serializer}; use serde_json; +use base64; + use utils; // TODO: more constants. constants for format strings of URLs and such. @@ -205,16 +205,19 @@ impl TestResult { pub struct PatchworkServer { pub url: String, - headers: Headers, + headers: HeaderMap, pub client: std::sync::Arc, } impl PatchworkServer { #[cfg_attr(feature = "cargo-clippy", allow(ptr_arg))] pub fn new(url: &String, client: &std::sync::Arc) -> PatchworkServer { - let mut headers = Headers::new(); - headers.set(Accept(vec![qitem(reqwest::mime::APPLICATION_JSON)])); - headers.set(ContentType(reqwest::mime::APPLICATION_JSON)); + let mut headers = HeaderMap::new(); + // These .parse().unwrap() blocks are making sure it's a valid ASCII + // header value. They don't need to be refactored and hopefully in + // future won't be necessary with newer reqwest versions. + headers.insert(ACCEPT, "application/json".parse().unwrap()); + headers.insert(CONTENT_TYPE, "application/json".parse().unwrap()); PatchworkServer { url: url.clone(), client: client.clone(), @@ -231,34 +234,29 @@ impl PatchworkServer { ) { match (username, password, token) { (&None, &None, &Some(ref token)) => { - self.headers.set(Authorization(format!("Token {}", token))); + self.headers + .insert(AUTHORIZATION, format!("Token {}", token).parse().unwrap()); } (&Some(ref username), &Some(ref password), &None) => { - self.headers.set(Authorization(Basic { - username: username.clone(), - password: Some(password.clone()), - })); + self.headers.insert( + AUTHORIZATION, + format!( + "Basic {}", + base64::encode(&format!("{}:{}", username, password)) + ).parse() + .unwrap(), + ); } _ => panic!("Invalid patchwork authentication details"), } } pub fn get_url(&self, url: &str) -> std::result::Result { - self.client - .get(&*url) - .headers(self.headers.clone()) - .header(Connection::close()) - .send() + self.client.get(&*url).headers(self.headers.clone()).send() } pub fn get_url_string(&self, url: &str) -> std::result::Result { - let mut resp = try!( - self.client - .get(&*url) - .headers(self.headers.clone()) - .header(Connection::close()) - .send() - ); + let mut resp = try!(self.client.get(&*url).headers(self.headers.clone()).send()); let mut body: Vec = vec![]; io::copy(&mut resp, &mut body).unwrap(); Ok(String::from_utf8(body).unwrap()) @@ -282,7 +280,7 @@ impl PatchworkServer { let mut body: Vec = vec![]; io::copy(&mut resp, &mut body).unwrap(); trace!("{}", String::from_utf8(body).unwrap()); - assert_eq!(resp.status(), StatusCode::Created); + assert_eq!(resp.status(), StatusCode::CREATED); Ok(resp.status()) } @@ -311,8 +309,9 @@ impl PatchworkServer { ) } - fn get_next_link(&self, resp: &Response) -> Option { - let next = resp.headers().get::()?; + fn get_next_link(&self, _resp: &Response) -> Option { + /* + let next = resp.headers().get(LINK)?; for val in next.values() { if let Some(rel) = val.rel() { if rel.iter().any(|reltype| reltype == &RelationType::Next) { @@ -320,6 +319,7 @@ impl PatchworkServer { } } } +*/ None }