2 * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package org.akraino.validation.ui.client.jenkins;
18 import java.net.MalformedURLException;
20 import java.security.KeyManagementException;
21 import java.security.NoSuchAlgorithmException;
22 import java.security.cert.X509Certificate;
23 import java.util.ArrayList;
24 import java.util.Iterator;
25 import java.util.List;
28 import javax.annotation.Nonnull;
29 import javax.net.ssl.HostnameVerifier;
30 import javax.net.ssl.HttpsURLConnection;
31 import javax.net.ssl.SSLContext;
32 import javax.net.ssl.SSLSession;
33 import javax.net.ssl.TrustManager;
34 import javax.net.ssl.X509TrustManager;
35 import javax.ws.rs.core.MultivaluedMap;
37 import org.akraino.validation.ui.client.jenkins.resources.CrumbResponse;
38 import org.akraino.validation.ui.client.jenkins.resources.Parameter;
39 import org.akraino.validation.ui.client.jenkins.resources.Parameters;
40 import org.akraino.validation.ui.client.jenkins.resources.QueueJobItem;
41 import org.apache.commons.httpclient.HttpException;
42 import org.apache.log4j.Logger;
44 import com.sun.jersey.api.client.Client;
45 import com.sun.jersey.api.client.ClientHandlerException;
46 import com.sun.jersey.api.client.ClientResponse;
47 import com.sun.jersey.api.client.UniformInterfaceException;
48 import com.sun.jersey.api.client.WebResource;
49 import com.sun.jersey.api.client.config.ClientConfig;
50 import com.sun.jersey.api.client.config.DefaultClientConfig;
51 import com.sun.jersey.api.client.filter.HTTPBasicAuthFilter;
52 import com.sun.jersey.api.json.JSONConfiguration;
53 import com.sun.jersey.client.urlconnection.HTTPSProperties;
55 public final class JenkinsExecutorClient {
57 private static final Logger LOGGER = Logger.getLogger(JenkinsExecutorClient.class);
59 private static final List<JenkinsExecutorClient> JENKINS_CLIENTS = new ArrayList<>();
60 private static final Object LOCK = new Object();
61 private final Client client;
63 private final String user;
64 private final String password;
65 private final String baseurl;
67 private final HostnameVerifier hostnameVerifier;
68 private final TrustManager[] trustAll;
70 private JenkinsExecutorClient(String newUser, String newPassword, String newBaseurl) {
72 this.password = newPassword;
73 this.baseurl = newBaseurl;
74 ClientConfig clientConfig = new DefaultClientConfig();
75 clientConfig.getFeatures().put(JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);
76 this.client = Client.create(clientConfig);
77 this.client.addFilter(new HTTPBasicAuthFilter(user, password));
78 // Create all-trusting host name verifier
79 hostnameVerifier = new HostnameVerifier() {
81 public boolean verify(String hostname, SSLSession session) {
85 // Create a trust manager that does not validate certificate chains
86 trustAll = new TrustManager[] {new X509TrustManager() {
88 public X509Certificate[] getAcceptedIssuers() {
89 return null; // Not relevant.
93 public void checkClientTrusted(X509Certificate[] certs, String authType) {
94 // Do nothing. Just allow them all.
98 public void checkServerTrusted(X509Certificate[] certs, String authType) {
99 // Do nothing. Just allow them all.
104 public static synchronized JenkinsExecutorClient getInstance(@Nonnull String newUser, @Nonnull String newPassword,
105 @Nonnull String newBaseurl) throws MalformedURLException {
107 for (JenkinsExecutorClient client : JENKINS_CLIENTS) {
108 if (client.getBaseUrl().equals(newBaseurl) && client.getUser().equals(newUser)
109 && client.getPassword().equals(newPassword)) {
113 JenkinsExecutorClient client = new JenkinsExecutorClient(newUser, newPassword, newBaseurl);
114 JENKINS_CLIENTS.add(client);
118 public String getUser() {
122 public String getPassword() {
123 return this.password;
126 public String getBaseUrl() {
130 public QueueJobItem getQueueJobItem(URL queueJobItemUrl) throws HttpException, ClientHandlerException,
131 UniformInterfaceException, KeyManagementException, NoSuchAlgorithmException {
132 synchronized (LOCK) {
133 LOGGER.info("Trying to get a Jenkins resource");
134 String crumb = this.getCrumb();
135 LOGGER.debug("Jenkins crumb is: " + crumb);
136 WebResource webResource = this.client.resource(queueJobItemUrl + "/api/json");
137 LOGGER.debug("Request URI of get: " + webResource.getURI().toString());
138 WebResource.Builder builder = webResource.getRequestBuilder();
139 builder.header("Jenkins-Crumb", crumb);
140 ClientResponse response =
141 builder.accept("application/json").type("application/json").get(ClientResponse.class);
142 if (response.getStatus() != 200) {
143 throw new HttpException("Get on Jenkins failed. HTTP error code : " + response.getStatus()
144 + " and message: " + response.getEntity(String.class));
146 LOGGER.info("Get of Jenkins resource succeeded");
147 return response.getEntity(QueueJobItem.class);
155 * @return The URL of the corresponding Jenkins queue job item
156 * @throws UniformInterfaceException
157 * @throws ClientHandlerException
158 * @throws HttpException
159 * @throws MalformedURLException
160 * @throws NoSuchAlgorithmException
161 * @throws KeyManagementException
163 public URL postJobWithQueryParams(@Nonnull String jobName, @Nonnull Parameters parameters)
164 throws HttpException, ClientHandlerException, UniformInterfaceException, MalformedURLException,
165 KeyManagementException, NoSuchAlgorithmException {
166 synchronized (LOCK) {
167 LOGGER.info("Trying to trigger a job to Jenkins");
168 String crumb = this.getCrumb();
169 LOGGER.debug("Jenkins crumb is: " + crumb);
170 String queryParams = "?";
171 for (Parameter parameter : parameters.getParameter()) {
172 queryParams = queryParams + parameter.getName() + "=" + parameter.getValue() + "&";
174 queryParams = queryParams.substring(0, queryParams.length() - 1);
175 WebResource webResource =
176 this.client.resource(this.getBaseUrl() + "/job/" + jobName + "/buildWithParameters" + queryParams);
177 LOGGER.debug("Request URI of post: " + webResource.getURI().toString());
178 WebResource.Builder builder = webResource.getRequestBuilder();
179 builder.header("Jenkins-Crumb", crumb);
180 ClientResponse response = builder.type("application/json").post(ClientResponse.class, String.class);
181 if (response.getStatus() != 200 && response.getStatus() != 201) {
182 throw new HttpException("Post of Jenkins job failed. HTTP error code : " + response.getStatus()
183 + " and message: " + response.getEntity(String.class));
185 LOGGER.info("Jenkins job has been successfully triggered");
186 URL buildQueueUrl = null;
187 MultivaluedMap<String, String> responseValues = response.getHeaders();
188 Iterator<String> iter = responseValues.keySet().iterator();
189 while (iter.hasNext()) {
190 String key = iter.next();
191 if (key.equals("Location")) {
192 buildQueueUrl = new URL(responseValues.getFirst(key));
195 return buildQueueUrl;
199 private String getCrumb() throws HttpException, ClientHandlerException, UniformInterfaceException,
200 KeyManagementException, NoSuchAlgorithmException {
201 LOGGER.info("Get crumb attempt");
203 String crumbUri = baseurl + "/crumbIssuer/api/json";
204 WebResource webResource = this.client.resource(crumbUri);
205 ClientResponse response =
206 webResource.accept("application/json").type("application/json").get(ClientResponse.class);
207 if (response.getStatus() == 201 || response.getStatus() == 200) {
208 CrumbResponse crumbResponse = response.getEntity(CrumbResponse.class);
209 LOGGER.info("Successful crumb retrieval.");
210 return crumbResponse.getCrumb();
212 throw new HttpException("Get crumb attempt towards Jenkins failed. HTTP error code: " + response.getStatus()
213 + " and message: " + response.getEntity(String.class));
216 private void setProperties() throws NoSuchAlgorithmException, KeyManagementException {
217 SSLContext sslContext = SSLContext.getInstance("SSL");
218 sslContext.init(null, this.trustAll, new java.security.SecureRandom());
219 HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
220 // Install the all-trusting host verifier
221 HttpsURLConnection.setDefaultHostnameVerifier(this.hostnameVerifier);
222 DefaultClientConfig config = new DefaultClientConfig();
223 Map<String, Object> properties = config.getProperties();
224 HTTPSProperties httpsProperties = new HTTPSProperties((str, sslSession) -> true, sslContext);
225 properties.put(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES, httpsProperties);