Java tutorial
/** * Copyright (c) 2015 Intel Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.trustedanalytics.servicebroker.gearpump.service; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpEntity; import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.http.HttpHeaders; import org.springframework.stereotype.Service; import org.springframework.web.client.HttpClientErrorException; import org.springframework.web.client.RestClientException; import org.springframework.web.client.RestTemplate; import org.springframework.web.util.UriTemplate; import org.trustedanalytics.servicebroker.gearpump.config.CfCallerConfiguration; import org.trustedanalytics.servicebroker.gearpump.service.externals.helpers.CfCaller; import javax.annotation.PostConstruct; import java.io.IOException; import java.net.URI; import java.util.Base64; import java.util.HashMap; import java.util.Map; @Service public class CloudFoundryService { public static final String AUTHORIZATION_HEADER = "Authorization"; public static final String CONTENT_TYPE_HEADER = "Content-Type"; @Autowired private CfCallerConfiguration cfCallerConfiguration; @Autowired CfCaller cfCaller; @Value("${api.endpoint}") private String cfApiEndpoint; @Value("${uaa.endpoint}") private String uaaApiEndpoint; @Value("${uaa.token_uri}") private String uaaTokenApiEndpoint; @Value("${uaa.login_uri}") private String loginApiEndpoint; @Value("${uaa.admin_client.id}") private String ssoAdminClientId; @Value("${uaa.admin_client.secret}") private String ssoAdminClientSecret; private static final Logger LOGGER = LoggerFactory.getLogger(CloudFoundryService.class); private static final String RESOURCES_0_METADATA_GUID = "/resources/0/metadata/guid"; private static final String METADATA_GUID = "/metadata/guid"; private static final String UAA_ACCESS_TOKEN = "/access_token"; private static final String UAA_TOKEN_TYPE = "/token_type"; private static final String APP_URL = "/entity/credentials/url"; private static final String APP_STATUS = "/0/state"; private static final String CREATE_SERVICE_BODY_TEMPLATE = "{\"name\":\"%s\",\"space_guid\":\"%s\",\"service_plan_guid\":\"%s\",\"parameters\":{\"push_argument\":\"--no-start\",\"name\":\"%s\",\"USERNAME\":\"%s\",\"PASSWORD\":\"%s\",\"GEARPUMP_MASTER\":\"%s\",\"UAA_CLIENT_ID\":\"%s\",\"UAA_CLIENT_SECRET\":\"%s\",\"UAA_HOST\":\"%s\",\"CF_API_ENDPOINT\":\"%s\",\"ORG_ID\":\"%s\"}}"; private static final String UPDATE_APP_ENV_BODY_TEMPLATE = "{\"environment_json\":{\"USERNAME\":\"%s\",\"PASSWORD\":\"%s\",\"GEARPUMP_MASTER\":\"%s\",\"UAA_CLIENT_ID\":\"%s\",\"UAA_CLIENT_SECRET\":\"%s\",\"UAA_HOST\":\"%s\",\"CF_API_ENDPOINT\":\"%s\",\"ORG_ID\":\"%s\",\"CALLBACK\":\"%s\"}}"; private static final String CREATE_SERVICE_KEY_BODY_TEMPLATE = "{\"service_instance_guid\":\"%s\",\"name\":\"temp_param\"}"; private static final String CREATE_UAA_TOKEN_BODY_TEMPLATE = "grant_type=client_credentials&response_type=token"; private static final String CREATE_UAA_CLIENT_BODY_TEMPLATE = "{\"client_id\":\"%s\",\"name\":\"%s\",\"client_secret\":\"%s\",\"scope\":[\"cloud_controller.read\",\"openid\"],\"resource_ids\":[\"none\"],\"authorities\":[\"cloud_controller.read\",\"cloud_controller.write\",\"openid\"],\"authorized_grant_types\":[\"client_credentials\",\"authorization_code\",\"refresh_token\"],\"autoapprove\":true,\"access_token_validity\":43200,\"redirect_uri\":[\"%s\"]}"; private static final String STATUS_STOPPED_BODY = "{\"state\":\"STOPPED\"}"; private static final String STATUS_STARTED_BODY = "{\"state\":\"STARTED\"}"; private static final String GET_ORG_GUID_URL = "{apiUrl}/v2/organizations?q=name:{orgName}"; private static final String GET_SPACE_GUID_URL = "{apiUrl}/v2/organizations/{orgId}/spaces?q=name:{spaceName}"; private static final String GET_SERVICE_GUID_URL = "{apiUrl}/v2/spaces/{spaceId}/services?q=label:{applicationName}"; private static final String GET_SERVICE_PLAN_GUID_URL = "{apiUrl}/v2/service_plans?q=service_guid:{serviceGuid}"; private static final String CREATE_SERVICE_INSTANCE_URL = "{apiUrl}/v2/service_instances"; private static final String GET_APP_GUID_URL = "{apiUrl}/v2/spaces/{spaceGuid}/apps?q=name:{appName}"; private static final String UPDATE_APP_URL = "{apiUrl}/v2/apps/{appGuid}"; private static final String GET_STATUS_APP_URL = "{apiUrl}/v2/apps/{appGuid}/stats"; private static final String POST_CREATE_SERVICE_KEY_URL = "{apiUrl}/v2/service_keys"; private static final String DELETE_SERVICE_KEY_URL = "{apiUrl}/v2/service_keys/{serviceKeyGuid}"; private static final String DELETE_SERVICE_URL = "{apiUrl}/v2/service_instances/{serviceId}"; private static final String CREATE_UAA_TOKEN_URL = "{uaaTokenUrl}"; private static final String CREATE_UAA_CLIENT_URL = "{uaaUrl}/oauth/clients"; private static final String DELETE_UAA_CLIENT_URL = "{uaaUrl}/oauth/clients/{client_id}"; private static final String REDIRECT_URI_SUFIX = "/login/oauth2/cloudfoundryuaa/callback"; private static final String UI_OK_STATUS = "RUNNING"; private static final int UI_MAX_STATUS_CHECK = 50; private static String uiOrgGuid; private static String uiSpaceGuid; private static String uiServiceGuid; private static String uiServicePlanGuid; @PostConstruct private void init() throws DashboardServiceException { LOGGER.info("Obtaining org, space, service and plan GUIDs."); uiOrgGuid = getUIOrgGuid(); uiSpaceGuid = getUISpaceGuid(uiOrgGuid); uiServiceGuid = getUIServiceGuid(uiSpaceGuid); uiServicePlanGuid = getUIServicePlanGuid(uiServiceGuid); } private String getUIOrgGuid() throws DashboardServiceException { LOGGER.debug("getUIOrgGuid()"); if (uiOrgGuid == null) { LOGGER.info("Getting UI Org GUID from CF"); ResponseEntity<String> response = execute(GET_ORG_GUID_URL, HttpMethod.GET, "", cfApiEndpoint, cfCallerConfiguration.getGearpumpUiOrg()); try { uiOrgGuid = cfCaller.getValueFromJson(response.getBody(), RESOURCES_0_METADATA_GUID); } catch (IOException e) { throw new DashboardServiceException("Cannot obtain org GUID (check GEARPUMP_UI_ORG variable).", e); } LOGGER.debug("UI Org GUID '{}'", uiOrgGuid); if (StringUtils.isEmpty(uiOrgGuid)) { throw new DashboardServiceException("Cannot obtain org GUID (check GEARPUMP_UI_ORG variable)."); } } return uiOrgGuid; } private String getUISpaceGuid(String uiOrgGuid) throws DashboardServiceException { LOGGER.debug("getUISpaceGuid({})", uiOrgGuid); if (uiSpaceGuid == null) { LOGGER.info("Getting UI Space GUID from CF"); ResponseEntity<String> response = execute(GET_SPACE_GUID_URL, HttpMethod.GET, "", cfApiEndpoint, uiOrgGuid, cfCallerConfiguration.getGearpumpUiSpace()); try { uiSpaceGuid = cfCaller.getValueFromJson(response.getBody(), RESOURCES_0_METADATA_GUID); } catch (IOException e) { throw new DashboardServiceException("Cannot obtain space GUID (check GEARPUMP_UI_SPACE variable).", e); } LOGGER.debug("UI Space GUID '{}'", uiSpaceGuid); if (StringUtils.isEmpty(uiSpaceGuid)) { throw new DashboardServiceException("Cannot obtain space GUID (check GEARPUMP_UI_SPACE variable)."); } } return uiSpaceGuid; } private String getUIServiceGuid(String uiSpaceGuid) throws DashboardServiceException { LOGGER.debug("getUIServiceGuid({})", uiSpaceGuid); if (uiServiceGuid == null) { LOGGER.info("Getting UI Service GUID from CF"); ResponseEntity<String> response = execute(GET_SERVICE_GUID_URL, HttpMethod.GET, "", cfApiEndpoint, uiSpaceGuid, cfCallerConfiguration.getGearpumpUiName()); try { uiServiceGuid = cfCaller.getValueFromJson(response.getBody(), RESOURCES_0_METADATA_GUID); } catch (IOException e) { throw new DashboardServiceException( "Cannot obtain dashboard service GUID (check GEARPUMP_UI_NAME variable).", e); } LOGGER.debug("UI Service GUID '{}'", uiServiceGuid); if (StringUtils.isEmpty(uiServiceGuid)) { throw new DashboardServiceException( "Cannot obtain dashboard service GUID (check GEARPUMP_UI_NAME variable)."); } } return uiServiceGuid; } private String getUIServicePlanGuid(String serviceGuid) throws DashboardServiceException { LOGGER.debug("getUIServicePlanGuid({})", serviceGuid); if (uiServicePlanGuid == null) { LOGGER.info("Getting Service Plan GUID from CF"); ResponseEntity<String> response = execute(GET_SERVICE_PLAN_GUID_URL, HttpMethod.GET, "", cfApiEndpoint, serviceGuid); try { uiServicePlanGuid = cfCaller.getValueFromJson(response.getBody(), RESOURCES_0_METADATA_GUID); } catch (IOException e) { throw new DashboardServiceException("Cannot obtain dashboard service plan GUID.", e); } LOGGER.debug("UI Service Plan GUID '{}'", uiServicePlanGuid); if (StringUtils.isEmpty(uiServicePlanGuid)) { throw new DashboardServiceException("Cannot obtain dashboard service plan GUID."); } } return uiServicePlanGuid; } private ResponseEntity<String> execute(String url, HttpMethod method, String body, Object... urlVariables) throws RestClientException { return this.executeWithHeaders(url, method, body, new HttpHeaders(), urlVariables); } private ResponseEntity<String> executeWithHeaders(String url, HttpMethod method, String body, HttpHeaders headers, Object... urlVariables) throws RestClientException { RestTemplate restTemplate = cfCaller.createRestTemplate(); HttpEntity<String> request = cfCaller.createJsonRequest(body, headers); URI expanded = (new UriTemplate(url)).expand(urlVariables); LOGGER.info("Performing call: {}", expanded.toString()); ResponseEntity<String> response = restTemplate.exchange(url, method, request, String.class, urlVariables); LOGGER.debug("Response status: {}", response.getStatusCode()); return response; } private String createUIInstance(String uiInstanceName, String spaceId, String orgId, String uiServicePlanGuid, String username, String password, String gearpumpMaster, String uaaClientName) throws IOException { LOGGER.info("Creating Service Instance"); String body = String.format(CREATE_SERVICE_BODY_TEMPLATE, uiInstanceName, spaceId, uiServicePlanGuid, uiInstanceName, username, password, gearpumpMaster, uaaClientName, password, loginHost(), cfApiEndpoint, orgId); LOGGER.debug("Create app body: {}", body); ResponseEntity<String> response = execute(CREATE_SERVICE_INSTANCE_URL, HttpMethod.POST, body, cfApiEndpoint); String uiServiceInstanceGuid = cfCaller.getValueFromJson(response.getBody(), METADATA_GUID); LOGGER.debug("UI Service Instance Guid '{}'", uiServiceInstanceGuid); return uiServiceInstanceGuid; } private String getUIAppGuid(String uiAppName, String spaceId) throws IOException { LOGGER.info("Getting App guid"); ResponseEntity<String> response = execute(GET_APP_GUID_URL, HttpMethod.GET, "", cfApiEndpoint, spaceId, uiAppName); String uiAppGuid = cfCaller.getValueFromJson(response.getBody(), RESOURCES_0_METADATA_GUID); LOGGER.debug("App guid is: {}", uiAppGuid); return uiAppGuid; } private void updateUIApp(String orgId, String username, String uiCallback, String uiAppGuid, String password, String gearpumpMaster, String uaaClientName) throws IOException { LOGGER.info("Updating App Environments Instance"); String body = String.format(UPDATE_APP_ENV_BODY_TEMPLATE, username, password, gearpumpMaster, uaaClientName, password, loginHost(), cfApiEndpoint, orgId, uiCallback); LOGGER.debug("Update app body: {}", body); execute(UPDATE_APP_URL, HttpMethod.PUT, body, cfApiEndpoint, uiAppGuid); } private void restartUIApp(String uiAppGuid) throws IOException { LOGGER.info("Stopping ui app"); execute(UPDATE_APP_URL, HttpMethod.PUT, STATUS_STOPPED_BODY, cfApiEndpoint, uiAppGuid); LOGGER.info("Starting ui app"); execute(UPDATE_APP_URL, HttpMethod.PUT, STATUS_STARTED_BODY, cfApiEndpoint, uiAppGuid); LOGGER.info("Waiting ui to start"); String status = ""; int statusCheckNr = 0; ResponseEntity<String> response; while (!status.equals(UI_OK_STATUS) && statusCheckNr < UI_MAX_STATUS_CHECK) { response = execute(GET_STATUS_APP_URL, HttpMethod.GET, null, cfApiEndpoint, uiAppGuid); status = cfCaller.getValueFromJson(response.getBody(), APP_STATUS); LOGGER.debug("UI app status check nr {}: {}", statusCheckNr, status); statusCheckNr++; } } public String loginHost() { return loginApiEndpoint.replaceAll("/oauth/authorize", ""); } private String getUIAppUrl(String uiServiceInstanceGuid) throws IOException { LOGGER.info("Getting UI App URL using create service key function"); String body = String.format(CREATE_SERVICE_KEY_BODY_TEMPLATE, uiServiceInstanceGuid); ResponseEntity<String> response = execute(POST_CREATE_SERVICE_KEY_URL, HttpMethod.POST, body, cfApiEndpoint); String uiAppUrl = cfCaller.getValueFromJson(response.getBody(), APP_URL); String serviceKeyGuid = cfCaller.getValueFromJson(response.getBody(), METADATA_GUID); LOGGER.info("Deleting service key"); execute(DELETE_SERVICE_KEY_URL, HttpMethod.DELETE, "", cfApiEndpoint, serviceKeyGuid); LOGGER.debug("UI App url '{}'", uiAppUrl); return uiAppUrl; } public void deleteUIServiceInstance(String uiServiceGuid) { try { execute(DELETE_SERVICE_URL, HttpMethod.DELETE, "", cfApiEndpoint, uiServiceGuid); } catch (HttpClientErrorException e) { if (e.getStatusCode().equals(HttpStatus.NOT_FOUND)) { LOGGER.warn("GearPump UI instance with GUID {} doesn't exist. Skipping.", uiServiceGuid); } else { LOGGER.debug("Cannot delete GearPump UI instance with GUID {} - rethrowing excepiton.", uiServiceGuid); throw e; } } } private String createUaaToken(String clientId, String clientSecret) throws DashboardServiceException { LOGGER.info("Creating new UAA token"); String autorizationString = clientId + ":" + clientSecret; autorizationString = new String(Base64.getEncoder().encode(autorizationString.getBytes())); HttpHeaders headers = new HttpHeaders(); headers.add(AUTHORIZATION_HEADER, "Basic " + autorizationString); headers.add(CONTENT_TYPE_HEADER, "application/x-www-form-urlencoded"); ResponseEntity<String> response = executeWithHeaders(CREATE_UAA_TOKEN_URL, HttpMethod.POST, CREATE_UAA_TOKEN_BODY_TEMPLATE, headers, uaaTokenApiEndpoint); String uaaToken; try { uaaToken = cfCaller.getValueFromJson(response.getBody(), UAA_TOKEN_TYPE) + " " + cfCaller.getValueFromJson(response.getBody(), UAA_ACCESS_TOKEN); } catch (IOException e) { throw new DashboardServiceException("Cannot obtain UAA token.", e); } LOGGER.debug("UAA access token has been obtained."); return uaaToken; } private String createUaaClient(String clientId, String clientName, String clientSecret, String redirectUri, String token) throws DashboardServiceException { LOGGER.info("Creating new UAA client"); String body = String.format(CREATE_UAA_CLIENT_BODY_TEMPLATE, clientId, clientName, clientSecret, "http://" + redirectUri + REDIRECT_URI_SUFIX); HttpHeaders headers = new HttpHeaders(); headers.add(AUTHORIZATION_HEADER, token); headers.add(CONTENT_TYPE_HEADER, "application/json"); ResponseEntity<String> response = executeWithHeaders(CREATE_UAA_CLIENT_URL, HttpMethod.POST, body, headers, uaaApiEndpoint); LOGGER.debug("Created UAA client: {}", response.getBody()); return response.getBody(); } private String deleteUaaClient(String clientId, String token) { HttpHeaders headers = new HttpHeaders(); headers.add(AUTHORIZATION_HEADER, token); headers.add(CONTENT_TYPE_HEADER, "application/json"); try { LOGGER.debug("Deleting UAA client: {}", clientId); return executeWithHeaders(DELETE_UAA_CLIENT_URL, HttpMethod.DELETE, "", headers, uaaApiEndpoint, clientId).getBody(); } catch (HttpClientErrorException e) { if (e.getStatusCode() == HttpStatus.NOT_FOUND) { LOGGER.debug("Cannot delete UAA client: {}. It is not exists.", clientId); } else { LOGGER.debug("Cannot delete UAA client: {} Error: {}", clientId, e.getStatusText()); throw e; } } return null; } public Map<String, String> deployUI(String uiInstanceName, String username, String password, String gearpumpMaster, String spaceId, String orgId, String uaaClientName) throws DashboardServiceException, CloudFoundryServiceException { String uiServiceInstanceGuid; String uiAppUrl; try { uiServiceInstanceGuid = createUIInstance(uiInstanceName, spaceId, orgId, uiServicePlanGuid, username, password, gearpumpMaster, uaaClientName); uiAppUrl = getUIAppUrl(uiServiceInstanceGuid); } catch (IOException e) { throw new CloudFoundryServiceException("Cannot create UI instance.", e); } try { String uiAppGuid = getUIAppGuid(uiAppUrl.replaceAll("\\.(.*)", ""), spaceId); updateUIApp(orgId, username, uiAppUrl, uiAppGuid, password, gearpumpMaster, uaaClientName); restartUIApp(uiAppGuid); } catch (IOException e) { throw new CloudFoundryServiceException("Cannot set environments and restart UI instance", e); } String uaaToken = createUaaToken(ssoAdminClientId, ssoAdminClientSecret); createUaaClient(uaaClientName, uaaClientName, password, uiAppUrl, uaaToken); Map<String, String> dashboardData = new HashMap<>(); dashboardData.put("uiServiceInstanceGuid", uiServiceInstanceGuid); dashboardData.put("uiAppUrl", uiAppUrl); dashboardData.put("username", username); dashboardData.put("password", password); dashboardData.put("uaaClientName", uaaClientName); return dashboardData; } public String undeployUI(String dashboardUri, String clientId) throws DashboardServiceException { deleteUIServiceInstance(dashboardUri); String uaaToken = createUaaToken(ssoAdminClientId, ssoAdminClientSecret); return deleteUaaClient(clientId, uaaToken); } }