public static String getRealClientIpAddr(final ResourceContext context) { // If some upstream device added an X-Forwarded-For header // use it for the client ip // This will support scenarios where load balancers or gateways // front the Azkaban web server and a changing Ip address invalidates // the session final Map<String, String> headers = context.getRequestHeaders(); final WebUtils utils = new WebUtils(); return utils.getRealClientIpAddr(headers, (String) context.getRawRequestContext().getLocalAttr("REMOTE_ADDR")); } }
private Properties getHeaders() { Properties headerProperties = new Properties(); for (Map.Entry<String, String> entry : getContext().getRequestHeaders().entrySet()) { if (ALLOWED_METADATA.contains(entry.getKey())) { headerProperties.put(entry.getKey(), entry.getValue()); } } return headerProperties; } }
@Override protected void startUp() throws Exception { RestLiConfig config = new RestLiConfig(); Set<String> resourceClassNames = Sets.newHashSet(); for (Class<? extends BaseResource> resClass : this.resources) { resourceClassNames.add(resClass.getName()); } config.addResourceClassNames(resourceClassNames); config.setServerNodeUri(this.serverUri); config.setDocumentationRequestHandler(new DefaultDocumentationRequestHandler()); config.addFilter(new RestLiValidationFilter()); ResourceFactory factory = new GuiceInjectResourceFactory(this.injector); TransportDispatcher dispatcher = new DelegatingTransportDispatcher(new RestLiServer(config, factory)); String acceptedFilters = EncodingType.SNAPPY.getHttpName() + "," + EncodingType.GZIP.getHttpName(); FilterChain filterChain = FilterChains.createRestChain(new ServerCompressionFilter(acceptedFilters)); this.httpServer = Optional.of(new HttpNettyServerFactory(filterChain).createServer(this.port, dispatcher)); this.log.info("Starting the {} embedded server at port {}.", this.name, this.port); this.httpServer.get().start(); }
@Override protected void startUp() throws Exception { // Server configuration RestLiConfig config = new RestLiConfig(); config.addResourcePackageNames(JobExecutionInfoResource.class.getPackage().getName()); config.setServerNodeUri(serverUri); config.setDocumentationRequestHandler(new DefaultDocumentationRequestHandler()); // Handle dependency injection Injector injector = Guice.createInjector(new MetaStoreModule(properties)); JobHistoryStore jobHistoryStore = injector.getInstance(JobHistoryStore.class); SimpleBeanProvider beanProvider = new SimpleBeanProvider(); beanProvider.add("jobHistoryStore", jobHistoryStore); // Use InjectMockResourceFactory to keep this Spring free ResourceFactory factory = new InjectMockResourceFactory(beanProvider); // Create and start the HTTP server TransportDispatcher dispatcher = new DelegatingTransportDispatcher(new RestLiServer(config, factory)); String acceptedFilters = EncodingType.SNAPPY.getHttpName() + "," + EncodingType.GZIP.getHttpName(); FilterChain filterChain = FilterChains.createRestChain(new ServerCompressionFilter(acceptedFilters)); this.httpServer = Optional.of(new HttpNettyServerFactory(filterChain).createServer(port, dispatcher)); LOGGER.info("Starting the job execution information server"); this.httpServer.get().start(); }
/** * Delete flowConfig locally and trigger all listeners iff @param triggerListener is set to true */ public UpdateResponse deleteFlowConfig(FlowId flowId, Properties header, boolean triggerListener) throws FlowConfigLoggedException { log.info("[GAAS-REST] Delete called with flowGroup {} flowName {}", flowId.getFlowGroup(), flowId.getFlowName()); URI flowUri = null; try { flowUri = createFlowSpecUri(flowId); this.flowCatalog.remove(flowUri, header, triggerListener); return new UpdateResponse(HttpStatus.S_200_OK); } catch (URISyntaxException e) { throw new FlowConfigLoggedException(HttpStatus.S_400_BAD_REQUEST, "bad URI " + flowUri, e); } }
void checkReports(final Map<String, ValidationReport> reports) throws RestLiServiceException { final StringBuffer errorMsgs = new StringBuffer(); for (final Map.Entry<String, ValidationReport> reportEntry : reports.entrySet()) { final ValidationReport report = reportEntry.getValue(); if (!report.getErrorMsgs().isEmpty()) { errorMsgs.append("Validator " + reportEntry.getKey() + " reports errors: "); for (final String msg : report.getErrorMsgs()) { errorMsgs.append(msg + System.getProperty("line.separator")); } } } if (errorMsgs.length() > 0) { throw new RestLiServiceException(HttpStatus.S_400_BAD_REQUEST, errorMsgs.toString()); } }
@Override /** * Add flowConfig locally and trigger all listeners iff @param triggerListener is set to true */ public CreateResponse createFlowConfig(FlowConfig flowConfig, boolean triggerListener) throws FlowConfigLoggedException { log.info("[GAAS-REST] Create called with flowGroup " + flowConfig.getId().getFlowGroup() + " flowName " + flowConfig.getId().getFlowName()); FlowSpec flowSpec = createFlowSpecForConfig(flowConfig); this.flowCatalog.put(flowSpec, triggerListener); FlowStatusId flowStatusId = new FlowStatusId() .setFlowName(flowSpec.getConfigAsProperties().getProperty(ConfigurationKeys.FLOW_NAME_KEY)) .setFlowGroup(flowSpec.getConfigAsProperties().getProperty(ConfigurationKeys.FLOW_GROUP_KEY)); if (flowSpec.getConfigAsProperties().containsKey(ConfigurationKeys.FLOW_EXECUTION_ID_KEY)) { flowStatusId.setFlowExecutionId(Long.valueOf(flowSpec.getConfigAsProperties().getProperty(ConfigurationKeys.FLOW_EXECUTION_ID_KEY))); } else { flowStatusId.setFlowExecutionId(-1L); } return new CreateResponse(new ComplexResourceKey<>(flowConfig.getId(), flowStatusId), HttpStatus.S_201_CREATED); } }
/** * Test that an error message is attached to the exception on an error */ @Test public void testErrorMessageDeploy() { final ProjectManagerResource resource = new ProjectManagerResource(); final Map<String, ValidationReport> reports = new LinkedHashMap<>(); addMockError(reports, "This should show up."); // We expect that a RestLiServiceException is thrown given a // report with errors. Uncaught exceptions will result in failure try { resource.checkReports(reports); Assert.fail(); } catch (final RestLiServiceException e) { //Ensure we have the right status code and exit assertEquals(e.getStatus(), HttpStatus.S_400_BAD_REQUEST); assertEquals(e.getMessage(), "Validator Error reports errors: This should show up." + System.getProperty("line.separator")); } }
@Override public Map<ComplexResourceKey<JobExecutionQuery, EmptyRecord>, JobExecutionQueryResult> batchGet( Set<ComplexResourceKey<JobExecutionQuery, EmptyRecord>> keys) { Map<ComplexResourceKey<JobExecutionQuery, EmptyRecord>, JobExecutionQueryResult> results = Maps.newHashMap(); for (ComplexResourceKey<JobExecutionQuery, EmptyRecord> key : keys) { JobExecutionQueryResult result = get(key); if (result != null) { results.put(key, get(key)); } } ResourceContext rc = this.getContext(); rc.setResponseHeader("Access-Control-Allow-Origin", "*"); this.setContext(rc); return results; } }
@Test public void testErrorDeploy() { final ProjectManagerResource resource = new ProjectManagerResource(); final Map<String, ValidationReport> reports = new LinkedHashMap<>(); for (int i = 0; i < 3; i++) { addMockError(reports, "Test error level info message."); } // We expect that a RestLiServiceException is thrown given a // report with errors. Uncaught exceptions will result in failure try { resource.checkReports(reports); Assert.fail(); } catch (final RestLiServiceException e) { //Ensure we have the right status code and exit assertEquals(e.getStatus(), HttpStatus.S_400_BAD_REQUEST); } }
@Test public void test() throws Exception { try(Closer closer = Closer.create()) { Map<String, String> configMap = Maps.newHashMap(); TestingServer zkTestingServer = closer.register(new TestingServer(-1)); configMap.put(ThrottlingGuiceServletConfig.ZK_STRING_KEY, zkTestingServer.getConnectString()); configMap.put(ThrottlingGuiceServletConfig.HA_CLUSTER_NAME, TestFailover.class.getSimpleName() + "_cluster"); Config config = ConfigFactory.parseMap(configMap); ThrottlingGuiceServletConfig server2001 = createServerAtPort(config, 2001); PermitAllocation allocation = sendRequestToServer(server2001, 10); Assert.assertTrue(allocation.getPermits() >= 1); ThrottlingGuiceServletConfig server2002 = createServerAtPort(config, 2002); allocation = sendRequestToServer(server2001, 10); Assert.assertTrue(allocation.getPermits() >= 1); try { sendRequestToServer(server2002, 10); Assert.fail(); } catch (RestLiServiceException exc) { Assert.assertTrue(exc.hasErrorDetails()); Assert.assertTrue(exc.getErrorDetails().containsKey(LimiterServerResource.LOCATION_301)); Assert.assertEquals(new URI(exc.getErrorDetails().get(LimiterServerResource.LOCATION_301).toString()).getPort(), 2001); } server2001.close(); allocation = sendRequestToServer(server2002, 10); Assert.assertTrue(allocation.getPermits() >= 1); } }
/** * Update flowConfig locally and trigger all listeners iff @param triggerListener is set to true */ public UpdateResponse updateFlowConfig(FlowId flowId, FlowConfig flowConfig, boolean triggerListener) { log.info("[GAAS-REST] Update called with flowGroup {} flowName {}", flowId.getFlowGroup(), flowId.getFlowName()); if (!flowId.getFlowGroup().equals(flowConfig.getId().getFlowGroup()) || !flowId.getFlowName().equals(flowConfig.getId().getFlowName())) { throw new FlowConfigLoggedException(HttpStatus.S_400_BAD_REQUEST, "flowName and flowGroup cannot be changed in update", null); } this.flowCatalog.put(createFlowSpecForConfig(flowConfig), triggerListener); return new UpdateResponse(HttpStatus.S_200_OK); }
@Override public PermitAllocation computePermitAllocation(PermitRequest request) { long permits = request.getPermits(); long allocated = 0; try { if (limiter.acquirePermits(permits) != null) { allocated = permits; } else { throw new RestLiServiceException(HttpStatus.S_403_FORBIDDEN, "Not enough permits."); } } catch (InterruptedException ie) { // return no permits } PermitAllocation allocation = new PermitAllocation(); allocation.setPermits(allocated); allocation.setExpiration(Long.MAX_VALUE); if (allocated <= 0) { allocation.setMinRetryDelayMillis(60000); } return allocation; }
/** * Add flowConfig locally and trigger all listeners iff @param triggerListener is set to true */ public CreateResponse createFlowConfig(FlowConfig flowConfig, boolean triggerListener) throws FlowConfigLoggedException { log.info("[GAAS-REST] Create called with flowGroup " + flowConfig.getId().getFlowGroup() + " flowName " + flowConfig.getId().getFlowName()); FlowSpec flowSpec = createFlowSpecForConfig(flowConfig); // Existence of a flow spec in the flow catalog implies that the flow is currently running. // If the new flow spec has a schedule we should allow submission of the new flow to accept the new schedule. // However, if the new flow spec does not have a schedule, we should allow submission only if it is not running. if (!flowConfig.hasSchedule() && this.flowCatalog.exists(flowSpec.getUri())) { return new CreateResponse(new ComplexResourceKey<>(flowConfig.getId(), new EmptyRecord()), HttpStatus.S_409_CONFLICT); } else { this.flowCatalog.put(flowSpec, triggerListener); return new CreateResponse(new ComplexResourceKey<>(flowConfig.getId(), new EmptyRecord()), HttpStatus.S_201_CREATED); } }
@Override public JobExecutionQueryResult get(ComplexResourceKey<JobExecutionQuery, EmptyRecord> key) { JobExecutionQuery query = key.getKey(); JobExecutionInfoArray jobExecutionInfos = new JobExecutionInfoArray(); try { for (JobExecutionInfo jobExecutionInfo : this.jobHistoryStore.get(query)) { jobExecutionInfos.add(jobExecutionInfo); } } catch (Throwable t) { LOGGER .error(String.format("Failed to execute query [id = %s, type = %s]", query.getId(), query.getIdType().name()), t); return null; } JobExecutionQueryResult result = new JobExecutionQueryResult(); result.setJobExecutions(jobExecutionInfos); ResourceContext rc = this.getContext(); rc.setResponseHeader("Access-Control-Allow-Origin", "*"); this.setContext(rc); return result; }
private Properties getHeaders() { Properties headerProperties = new Properties(); for (Map.Entry<String, String> entry : getContext().getRequestHeaders().entrySet()) { if (ALLOWED_METADATA.contains(entry.getKey())) { headerProperties.put(entry.getKey(), entry.getValue()); } } return headerProperties; } }
@Test public void testWarnErrorDeploy() { final ProjectManagerResource resource = new ProjectManagerResource(); final Map<String, ValidationReport> reports = new LinkedHashMap<>(); for (int i = 0; i < 7; i++) { // If i is even, make an error report, otherwise make a warning report if (i % 2 == 0) { addMockError(reports, "Test error level info message."); } else { addMockWarning(reports, "Test warn level info message."); } } // We expect that a RestLiServiceException is thrown given a // report with errors. Uncaught exceptions will result in failure try { resource.checkReports(reports); Assert.fail(); } catch (final RestLiServiceException e) { //Ensure we have the right status code and exit assertEquals(e.getStatus(), HttpStatus.S_400_BAD_REQUEST); } }
return new UpdateResponse(HttpStatus.S_200_OK); } else { return this.localHandler.deleteFlowConfig(flowId, header);
return new CreateResponse(new ComplexResourceKey<>(flowConfig.getId(), new EmptyRecord()), HttpStatus.S_201_CREATED); } else { return this.localHandler.createFlowConfig(flowConfig);
return new UpdateResponse(HttpStatus.S_200_OK); } else { return this.localHandler.updateFlowConfig(flowId, flowConfig);