UI adaptation for supporting ONAP portal SDK
[validation.git] / ui / src / main / java / org / akraino / validation / ui / client / jenkins / JenkinsExecutorClient.java
1 /*
2  * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may
5  * not use this file except in compliance with the License. You may obtain
6  * a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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
13  * implied. See the License for the specific language governing
14  * permissions and limitations under the License.
15  */
16 package org.akraino.validation.ui.client.jenkins;
17
18 import java.io.IOException;
19 import java.net.HttpURLConnection;
20 import java.net.InetSocketAddress;
21 import java.net.MalformedURLException;
22 import java.net.Proxy;
23 import java.net.URL;
24 import java.security.KeyManagementException;
25 import java.security.NoSuchAlgorithmException;
26 import java.security.cert.X509Certificate;
27 import java.util.ArrayList;
28 import java.util.Iterator;
29 import java.util.List;
30 import java.util.Map;
31
32 import javax.annotation.Nonnull;
33 import javax.net.ssl.HostnameVerifier;
34 import javax.net.ssl.HttpsURLConnection;
35 import javax.net.ssl.SSLContext;
36 import javax.net.ssl.SSLSession;
37 import javax.net.ssl.TrustManager;
38 import javax.net.ssl.X509TrustManager;
39 import javax.ws.rs.core.MultivaluedMap;
40
41 import org.akraino.validation.ui.client.jenkins.resources.CrumbResponse;
42 import org.akraino.validation.ui.client.jenkins.resources.Parameter;
43 import org.akraino.validation.ui.client.jenkins.resources.Parameters;
44 import org.akraino.validation.ui.client.jenkins.resources.QueueJobItem;
45 import org.apache.commons.httpclient.HttpException;
46 import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate;
47
48 import com.sun.jersey.api.client.Client;
49 import com.sun.jersey.api.client.ClientHandlerException;
50 import com.sun.jersey.api.client.ClientResponse;
51 import com.sun.jersey.api.client.UniformInterfaceException;
52 import com.sun.jersey.api.client.WebResource;
53 import com.sun.jersey.api.client.config.ClientConfig;
54 import com.sun.jersey.api.client.config.DefaultClientConfig;
55 import com.sun.jersey.api.client.filter.HTTPBasicAuthFilter;
56 import com.sun.jersey.api.json.JSONConfiguration;
57 import com.sun.jersey.client.urlconnection.HTTPSProperties;
58 import com.sun.jersey.client.urlconnection.HttpURLConnectionFactory;
59 import com.sun.jersey.client.urlconnection.URLConnectionClientHandler;
60
61 public final class JenkinsExecutorClient {
62
63     private static final EELFLoggerDelegate LOGGER = EELFLoggerDelegate.getLogger(JenkinsExecutorClient.class);
64
65     private static final List<JenkinsExecutorClient> JENKINS_CLIENTS = new ArrayList<>();
66     private static final Object LOCK = new Object();
67     private final Client client;
68
69     private final String user;
70     private final String password;
71     private final String baseurl;
72
73     private final HostnameVerifier hostnameVerifier;
74     private final TrustManager[] trustAll;
75
76     private JenkinsExecutorClient(String newUser, String newPassword, String newBaseurl) {
77         this.user = newUser;
78         this.password = newPassword;
79         this.baseurl = newBaseurl;
80         ClientConfig clientConfig = new DefaultClientConfig();
81         clientConfig.getFeatures().put(JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);
82         this.client = new Client(new URLConnectionClientHandler(new HttpURLConnectionFactory() {
83             Proxy proxy = null;
84
85             @Override
86             public HttpURLConnection getHttpURLConnection(URL url) throws IOException {
87                 try {
88                     String proxyIp = System.getenv("JENKINS_PROXY").substring(0,
89                             System.getenv("JENKINS_PROXY").lastIndexOf(":"));
90                     String proxyPort = System.getenv("JENKINS_PROXY")
91                             .substring(System.getenv("JENKINS_PROXY").lastIndexOf(":") + 1);
92                     proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyIp, Integer.parseInt(proxyPort)));
93                     return (HttpURLConnection) url.openConnection(proxy);
94                 } catch (Exception ex) {
95                     return (HttpURLConnection) url.openConnection();
96                 }
97             }
98         }), clientConfig);
99         this.client.addFilter(new HTTPBasicAuthFilter(user, password));
100         // Create all-trusting host name verifier
101         hostnameVerifier = new HostnameVerifier() {
102             @Override
103             public boolean verify(String hostname, SSLSession session) {
104                 return true;
105             }
106         };
107         // Create a trust manager that does not validate certificate chains
108         trustAll = new TrustManager[] {new X509TrustManager() {
109             @Override
110             public X509Certificate[] getAcceptedIssuers() {
111                 return null; // Not relevant.
112             }
113
114             @Override
115             public void checkClientTrusted(X509Certificate[] certs, String authType) {
116                 // Do nothing. Just allow them all.
117             }
118
119             @Override
120             public void checkServerTrusted(X509Certificate[] certs, String authType) {
121                 // Do nothing. Just allow them all.
122             }
123         }};
124     }
125
126     public static synchronized JenkinsExecutorClient getInstance(@Nonnull String newUser, @Nonnull String newPassword,
127             @Nonnull String newBaseurl) throws MalformedURLException {
128         new URL(newBaseurl);
129         for (JenkinsExecutorClient client : JENKINS_CLIENTS) {
130             if (client.getBaseUrl().equals(newBaseurl) && client.getUser().equals(newUser)
131                     && client.getPassword().equals(newPassword)) {
132                 return client;
133             }
134         }
135         JenkinsExecutorClient client = new JenkinsExecutorClient(newUser, newPassword, newBaseurl);
136         JENKINS_CLIENTS.add(client);
137         return client;
138     }
139
140     public String getUser() {
141         return this.user;
142     }
143
144     public String getPassword() {
145         return this.password;
146     }
147
148     public String getBaseUrl() {
149         return this.baseurl;
150     }
151
152     public QueueJobItem getQueueJobItem(URL queueJobItemUrl) throws HttpException, ClientHandlerException,
153             UniformInterfaceException, KeyManagementException, NoSuchAlgorithmException {
154         synchronized (LOCK) {
155             LOGGER.info(EELFLoggerDelegate.applicationLogger, "Trying to get a Jenkins resource");
156             String crumb = this.getCrumb();
157             LOGGER.debug(EELFLoggerDelegate.debugLogger, "Jenkins crumb is: " + crumb);
158             WebResource webResource = this.client.resource(queueJobItemUrl + "/api/json");
159             LOGGER.debug(EELFLoggerDelegate.debugLogger, "Request URI of get: " + webResource.getURI().toString());
160             WebResource.Builder builder = webResource.getRequestBuilder();
161             builder.header("Jenkins-Crumb", crumb);
162             ClientResponse response =
163                     builder.accept("application/json").type("application/json").get(ClientResponse.class);
164             if (response.getStatus() != 200) {
165                 throw new HttpException("Get on Jenkins failed. HTTP error code : " + response.getStatus()
166                         + " and message: " + response.getEntity(String.class));
167             }
168             LOGGER.info(EELFLoggerDelegate.applicationLogger, "Get of Jenkins resource succeeded");
169             return response.getEntity(QueueJobItem.class);
170         }
171     }
172
173     /**
174      *
175      * @param jobName
176      * @param parameters
177      * @return The URL of the corresponding Jenkins queue job item
178      * @throws UniformInterfaceException
179      * @throws ClientHandlerException
180      * @throws HttpException
181      * @throws MalformedURLException
182      * @throws NoSuchAlgorithmException
183      * @throws KeyManagementException
184      */
185     public URL postJobWithQueryParams(@Nonnull String jobName, @Nonnull Parameters parameters)
186             throws HttpException, ClientHandlerException, UniformInterfaceException, MalformedURLException,
187             KeyManagementException, NoSuchAlgorithmException {
188         synchronized (LOCK) {
189             LOGGER.info(EELFLoggerDelegate.applicationLogger, "Trying to trigger a job in Jenkins");
190             String crumb = this.getCrumb();
191             LOGGER.debug(EELFLoggerDelegate.debugLogger, "Jenkins crumb is: " + crumb);
192             String queryParams = "?";
193             for (Parameter parameter : parameters.getParameter()) {
194                 queryParams = queryParams + parameter.getName() + "=" + parameter.getValue() + "&";
195             }
196             queryParams = queryParams.substring(0, queryParams.length() - 1);
197             WebResource webResource =
198                     this.client.resource(this.getBaseUrl() + "/job/" + jobName + "/buildWithParameters" + queryParams);
199             LOGGER.debug(EELFLoggerDelegate.debugLogger, "Request URI of post: " + webResource.getURI().toString());
200             WebResource.Builder builder = webResource.getRequestBuilder();
201             builder.header("Jenkins-Crumb", crumb);
202             ClientResponse response = builder.type("application/json").post(ClientResponse.class, String.class);
203             if (response.getStatus() != 200 && response.getStatus() != 201) {
204                 throw new HttpException("Post of Jenkins job failed. HTTP error code : " + response.getStatus()
205                         + " and message: " + response.getEntity(String.class));
206             }
207             LOGGER.info(EELFLoggerDelegate.applicationLogger, "Jenkins job has been successfully triggered");
208             URL buildQueueUrl = null;
209             MultivaluedMap<String, String> responseValues = response.getHeaders();
210             Iterator<String> iter = responseValues.keySet().iterator();
211             while (iter.hasNext()) {
212                 String key = iter.next();
213                 if (key.equals("Location")) {
214                     buildQueueUrl = new URL(responseValues.getFirst(key));
215                 }
216             }
217             return buildQueueUrl;
218         }
219     }
220
221     private String getCrumb() throws HttpException, ClientHandlerException, UniformInterfaceException,
222             KeyManagementException, NoSuchAlgorithmException {
223         LOGGER.info(EELFLoggerDelegate.applicationLogger, "Attempting to get the crumb");
224         setProperties();
225         String crumbUri = baseurl + "/crumbIssuer/api/json";
226         WebResource webResource = this.client.resource(crumbUri);
227         ClientResponse response =
228                 webResource.accept("application/json").type("application/json").get(ClientResponse.class);
229         if (response.getStatus() == 201 || response.getStatus() == 200) {
230             CrumbResponse crumbResponse = response.getEntity(CrumbResponse.class);
231             LOGGER.info(EELFLoggerDelegate.applicationLogger, "Successful crumb retrieval");
232             return crumbResponse.getCrumb();
233         }
234         throw new HttpException("Get crumb attempt towards Jenkins failed. HTTP error code: " + response.getStatus()
235                 + " and message: " + response.getEntity(String.class));
236     }
237
238     private void setProperties() throws NoSuchAlgorithmException, KeyManagementException {
239         SSLContext sslContext = SSLContext.getInstance("SSL");
240         sslContext.init(null, this.trustAll, new java.security.SecureRandom());
241         HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
242         // Install the all-trusting host verifier
243         HttpsURLConnection.setDefaultHostnameVerifier(this.hostnameVerifier);
244         DefaultClientConfig config = new DefaultClientConfig();
245         Map<String, Object> properties = config.getProperties();
246         HTTPSProperties httpsProperties = new HTTPSProperties((str, sslSession) -> true, sslContext);
247         properties.put(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES, httpsProperties);
248     }
249
250 }