@Test public void testCreateYamlAlert() throws IOException { String detectionPayload = IOUtils.toString(this.getClass().getResourceAsStream("detection/detection-config-3.yaml")); String subscriptionPayload = IOUtils.toString(this.getClass().getResourceAsStream("subscription/subscription-config-6.yaml")); Map<String, String> config = new HashMap<>(); config.put("detection", detectionPayload); config.put("subscription", subscriptionPayload); try { Response response = this.yamlResource.createYamlAlert(user, new ObjectMapper().writeValueAsString(config), 0, 0); Assert.assertEquals(response.getStatus(), 200); Assert.assertEquals(ConfigUtils.getMap(response.getEntity()).get(PROP_DETECTION_ID), "6"); Assert.assertEquals(ConfigUtils.getMap(response.getEntity()).get(PROP_SUBSCRIPTION_ID), "7"); Assert.assertEquals(ConfigUtils.getMap(response.getEntity()).get("message"), "Alert was created successfully."); DetectionConfigDTO detection = this.daoRegistry.getDetectionConfigManager().findById(6l); Assert.assertNotNull(detection); DetectionAlertConfigDTO subscription = this.daoRegistry.getDetectionAlertConfigManager().findById(7l); Assert.assertNotNull(subscription); List<TaskDTO> taskId = this.daoRegistry.getTaskDAO().findAll(); Assert.assertEquals(taskId.size(), 1); } catch (Exception e) { Assert.fail("No exception should be thrown for valid payload"); } }
@POST @Path("/create-alert") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) @PermitAll @ApiOperation("Use yaml to create both subscription and detection yaml. ") public Response createYamlAlert( @Auth ThirdEyePrincipal user, @ApiParam(value = "a json contains both subscription and detection yaml as string") String payload, @ApiParam("tuning window start time for tunable components") @QueryParam("startTime") long tuningStartTime, @ApiParam("tuning window end time for tunable components") @QueryParam("endTime") long tuningEndTime) { Map<String, String> responseMessage = new HashMap<>(); Long detectionConfigId = null; Long subscriptionConfigId = null; boolean isAlertCreationSuccess = false; Map<String, String> yamls; try { validatePayload(payload); yamls = OBJECT_MAPPER.readValue(payload, Map.class); validateCreateAlertYaml(yamls); String detectionYaml = yamls.get(PROP_DETECTION); ConfigValidationUtils.checkArgument(StringUtils.isNotBlank(detectionYaml), String.format(MISSING_YAML_MSG, "Detection")); detectionConfigId = createDetectionConfig(detectionYaml, tuningStartTime, tuningEndTime); String subscriptionYaml = yamls.get(PROP_SUBSCRIPTION); ConfigValidationUtils.checkArgument(StringUtils.isNotBlank(subscriptionYaml), String.format(MISSING_YAML_MSG, "Subscription group")); Map<String, Object> subscriptionYamlConfig = ConfigUtils.getMap(this.yaml.load(subscriptionYaml)); String groupName = MapUtils.getString(subscriptionYamlConfig, PROP_SUBS_GROUP_NAME); List<DetectionAlertConfigDTO> alertConfigDTOS = subscriptionConfigDAO.findByPredicate(Predicate.EQ("name", groupName)); if (!alertConfigDTOS.isEmpty()) { subscriptionConfigId = alertConfigDTOS.get(0).getId(); updateSubscriptionGroup(user, subscriptionConfigId, subscriptionYaml); } else { subscriptionConfigId = createSubscriptionConfig(subscriptionYaml); } isAlertCreationSuccess = true; createYamlOnboardingTask(detectionConfigId, tuningStartTime, tuningEndTime); } catch (ConfigValidationException e) { return processValidationErrorResponse(PROP_ALERT, YamlOperations.CREATING.name(), payload, e); } catch (NotAuthorizedException e) { return processBadAuthorizationResponse(PROP_ALERT, YamlOperations.UPDATING.name(), payload, e); } catch (Exception e) { return processServerErrorResponse(PROP_ALERT, YamlOperations.CREATING.name() + "/" + YamlOperations.UPDATING.name(), payload, e); } finally { if (!isAlertCreationSuccess) { rollbackAlert(detectionConfigId, subscriptionConfigId); } } responseMessage.put("message", "Alert was created successfully."); responseMessage.put("more-info", "Record saved with detection id " + detectionConfigId + " and subscription id " + subscriptionConfigId); responseMessage.put(PROP_DETECTION_ID, String.valueOf(detectionConfigId)); responseMessage.put(PROP_SUBSCRIPTION_ID, String.valueOf(subscriptionConfigId)); return Response.ok().entity(responseMessage).build(); }
YamlResource { @POST @Path("/create-alert") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) @PermitAll @ApiOperation("Use yaml to create both subscription and detection yaml. ") public Response createYamlAlert( @Auth ThirdEyePrincipal user, @ApiParam(value = "a json contains both subscription and detection yaml as string") String payload, @ApiParam("tuning window start time for tunable components") @QueryParam("startTime") long tuningStartTime, @ApiParam("tuning window end time for tunable components") @QueryParam("endTime") long tuningEndTime) { Map<String, String> responseMessage = new HashMap<>(); Long detectionConfigId = null; Long subscriptionConfigId = null; boolean isAlertCreationSuccess = false; Map<String, String> yamls; try { validatePayload(payload); yamls = OBJECT_MAPPER.readValue(payload, Map.class); validateCreateAlertYaml(yamls); String detectionYaml = yamls.get(PROP_DETECTION); ConfigValidationUtils.checkArgument(StringUtils.isNotBlank(detectionYaml), String.format(MISSING_YAML_MSG, "Detection")); detectionConfigId = createDetectionConfig(detectionYaml, tuningStartTime, tuningEndTime); String subscriptionYaml = yamls.get(PROP_SUBSCRIPTION); ConfigValidationUtils.checkArgument(StringUtils.isNotBlank(subscriptionYaml), String.format(MISSING_YAML_MSG, "Subscription group")); Map<String, Object> subscriptionYamlConfig = ConfigUtils.getMap(this.yaml.load(subscriptionYaml)); String groupName = MapUtils.getString(subscriptionYamlConfig, PROP_SUBS_GROUP_NAME); List<DetectionAlertConfigDTO> alertConfigDTOS = subscriptionConfigDAO.findByPredicate(Predicate.EQ("name", groupName)); if (!alertConfigDTOS.isEmpty()) { subscriptionConfigId = alertConfigDTOS.get(0).getId(); updateSubscriptionGroup(user, subscriptionConfigId, subscriptionYaml); } else { subscriptionConfigId = createSubscriptionConfig(subscriptionYaml); } isAlertCreationSuccess = true; createYamlOnboardingTask(detectionConfigId, tuningStartTime, tuningEndTime); } catch (ConfigValidationException e) { return processValidationErrorResponse(PROP_ALERT, YamlOperations.CREATING.name(), payload, e); } catch (NotAuthorizedException e) { return processBadAuthorizationResponse(PROP_ALERT, YamlOperations.UPDATING.name(), payload, e); } catch (Exception e) { return processServerErrorResponse(PROP_ALERT, YamlOperations.CREATING.name() + "/" + YamlOperations.UPDATING.name(), payload, e); } finally { if (!isAlertCreationSuccess) { rollbackAlert(detectionConfigId, subscriptionConfigId); } } responseMessage.put("message", "Alert was created successfully."); responseMessage.put("more-info", "Record saved with detection id " + detectionConfigId + " and subscription id " + subscriptionConfigId); responseMessage.put(PROP_DETECTION_ID, String.valueOf(detectionConfigId)); responseMessage.put(PROP_SUBSCRIPTION_ID, String.valueOf(subscriptionConfigId)); return Response.ok().entity(responseMessage).build(); } }
YamlResource { @POST @Path("/create-alert") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) @PermitAll @ApiOperation("Use yaml to create both subscription and detection yaml. ") public Response createYamlAlert( @Auth ThirdEyePrincipal user, @ApiParam(value = "a json contains both subscription and detection yaml as string") String payload, @ApiParam("tuning window start time for tunable components") @QueryParam("startTime") long tuningStartTime, @ApiParam("tuning window end time for tunable components") @QueryParam("endTime") long tuningEndTime) { Map<String, String> responseMessage = new HashMap<>(); Long detectionConfigId = null; Long subscriptionConfigId = null; boolean isAlertCreationSuccess = false; Map<String, String> yamls; try { validatePayload(payload); yamls = OBJECT_MAPPER.readValue(payload, Map.class); validateCreateAlertYaml(yamls); String detectionYaml = yamls.get(PROP_DETECTION); ConfigValidationUtils.checkArgument(StringUtils.isNotBlank(detectionYaml), String.format(MISSING_YAML_MSG, "Detection")); detectionConfigId = createDetectionConfig(detectionYaml, tuningStartTime, tuningEndTime); String subscriptionYaml = yamls.get(PROP_SUBSCRIPTION); ConfigValidationUtils.checkArgument(StringUtils.isNotBlank(subscriptionYaml), String.format(MISSING_YAML_MSG, "Subscription group")); Map<String, Object> subscriptionYamlConfig = ConfigUtils.getMap(this.yaml.load(subscriptionYaml)); String groupName = MapUtils.getString(subscriptionYamlConfig, PROP_SUBS_GROUP_NAME); List<DetectionAlertConfigDTO> alertConfigDTOS = subscriptionConfigDAO.findByPredicate(Predicate.EQ("name", groupName)); if (!alertConfigDTOS.isEmpty()) { subscriptionConfigId = alertConfigDTOS.get(0).getId(); updateSubscriptionGroup(user, subscriptionConfigId, subscriptionYaml); } else { subscriptionConfigId = createSubscriptionConfig(subscriptionYaml); } isAlertCreationSuccess = true; createYamlOnboardingTask(detectionConfigId, tuningStartTime, tuningEndTime); } catch (ConfigValidationException e) { return processValidationErrorResponse(PROP_ALERT, YamlOperations.CREATING.name(), payload, e); } catch (NotAuthorizedException e) { return processBadAuthorizationResponse(PROP_ALERT, YamlOperations.UPDATING.name(), payload, e); } catch (Exception e) { return processServerErrorResponse(PROP_ALERT, YamlOperations.CREATING.name() + "/" + YamlOperations.UPDATING.name(), payload, e); } finally { if (!isAlertCreationSuccess) { rollbackAlert(detectionConfigId, subscriptionConfigId); } } responseMessage.put("message", "Alert was created successfully."); responseMessage.put("more-info", "Record saved with detection id " + detectionConfigId + " and subscription id " + subscriptionConfigId); responseMessage.put(PROP_DETECTION_ID, String.valueOf(detectionConfigId)); responseMessage.put(PROP_SUBSCRIPTION_ID, String.valueOf(subscriptionConfigId)); return Response.ok().entity(responseMessage).build(); } YamlResource(Map<String, Map<String, Object>> alerterConfig, DetectionPreviewConfiguration previewConfig,
      double alertOnboardingPermitPerSecond);  YamlResource(Map<String, Map<String, Object>> alerterConfig, DetectionPreviewConfiguration previewConfig); }
YamlResource { @POST @Path("/create-alert") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) @PermitAll @ApiOperation("Use yaml to create both subscription and detection yaml. ") public Response createYamlAlert( @Auth ThirdEyePrincipal user, @ApiParam(value = "a json contains both subscription and detection yaml as string") String payload, @ApiParam("tuning window start time for tunable components") @QueryParam("startTime") long tuningStartTime, @ApiParam("tuning window end time for tunable components") @QueryParam("endTime") long tuningEndTime) { Map<String, String> responseMessage = new HashMap<>(); Long detectionConfigId = null; Long subscriptionConfigId = null; boolean isAlertCreationSuccess = false; Map<String, String> yamls; try { validatePayload(payload); yamls = OBJECT_MAPPER.readValue(payload, Map.class); validateCreateAlertYaml(yamls); String detectionYaml = yamls.get(PROP_DETECTION); ConfigValidationUtils.checkArgument(StringUtils.isNotBlank(detectionYaml), String.format(MISSING_YAML_MSG, "Detection")); detectionConfigId = createDetectionConfig(detectionYaml, tuningStartTime, tuningEndTime); String subscriptionYaml = yamls.get(PROP_SUBSCRIPTION); ConfigValidationUtils.checkArgument(StringUtils.isNotBlank(subscriptionYaml), String.format(MISSING_YAML_MSG, "Subscription group")); Map<String, Object> subscriptionYamlConfig = ConfigUtils.getMap(this.yaml.load(subscriptionYaml)); String groupName = MapUtils.getString(subscriptionYamlConfig, PROP_SUBS_GROUP_NAME); List<DetectionAlertConfigDTO> alertConfigDTOS = subscriptionConfigDAO.findByPredicate(Predicate.EQ("name", groupName)); if (!alertConfigDTOS.isEmpty()) { subscriptionConfigId = alertConfigDTOS.get(0).getId(); updateSubscriptionGroup(user, subscriptionConfigId, subscriptionYaml); } else { subscriptionConfigId = createSubscriptionConfig(subscriptionYaml); } isAlertCreationSuccess = true; createYamlOnboardingTask(detectionConfigId, tuningStartTime, tuningEndTime); } catch (ConfigValidationException e) { return processValidationErrorResponse(PROP_ALERT, YamlOperations.CREATING.name(), payload, e); } catch (NotAuthorizedException e) { return processBadAuthorizationResponse(PROP_ALERT, YamlOperations.UPDATING.name(), payload, e); } catch (Exception e) { return processServerErrorResponse(PROP_ALERT, YamlOperations.CREATING.name() + "/" + YamlOperations.UPDATING.name(), payload, e); } finally { if (!isAlertCreationSuccess) { rollbackAlert(detectionConfigId, subscriptionConfigId); } } responseMessage.put("message", "Alert was created successfully."); responseMessage.put("more-info", "Record saved with detection id " + detectionConfigId + " and subscription id " + subscriptionConfigId); responseMessage.put(PROP_DETECTION_ID, String.valueOf(detectionConfigId)); responseMessage.put(PROP_SUBSCRIPTION_ID, String.valueOf(subscriptionConfigId)); return Response.ok().entity(responseMessage).build(); } YamlResource(Map<String, Map<String, Object>> alerterConfig, DetectionPreviewConfiguration previewConfig,
      double alertOnboardingPermitPerSecond);  YamlResource(Map<String, Map<String, Object>> alerterConfig, DetectionPreviewConfiguration previewConfig); void validateCreateAlertYaml(Map<String, String> config); @POST @Path("/create-alert") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) @PermitAll @ApiOperation("Use yaml to create both subscription and detection yaml. ") Response createYamlAlert(
      @Auth ThirdEyePrincipal user,
      @ApiParam(value =  "a json contains both subscription and detection yaml as string")  String payload,
      @ApiParam("tuning window start time for tunable components") @QueryParam("startTime") long tuningStartTime,
      @ApiParam("tuning window end time for tunable components") @QueryParam("endTime") long tuningEndTime); @POST @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.TEXT_PLAIN) @ApiOperation("Set up a detection pipeline using a YAML config") Response createDetectionPipelineApi(
      @ApiParam("yaml config") String payload,
      @ApiParam("tuning window start time for tunable components") @QueryParam("startTime") long startTime,
      @ApiParam("tuning window end time for tunable components") @QueryParam("endTime") long endTime); @PUT @Path("/{id}") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.TEXT_PLAIN) @PermitAll @ApiOperation("Edit a detection pipeline using a YAML config") Response updateDetectionPipelineApi(
      @Auth ThirdEyePrincipal user,
      @ApiParam("yaml config") String payload,
      @ApiParam("the detection config id to edit") @PathParam("id") long id,
      @ApiParam("tuning window start time for tunable components")  @QueryParam("startTime") long startTime,
      @ApiParam("tuning window end time for tunable components") @QueryParam("endTime") long endTime); @POST @Path("/create-or-update") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.TEXT_PLAIN) @PermitAll @ApiOperation("Create a new detection config or update existing if one already exists") Response createOrUpdateDetectionConfigApi(
      @Auth ThirdEyePrincipal user,
      @ApiParam("yaml config") String payload); @POST @Path("/subscription/create-or-update") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.TEXT_PLAIN) @PermitAll @ApiOperation("Create a new subscription config or update existing if one already exists") Response createOrUpdateSubscriptionConfigApi(
      @Auth ThirdEyePrincipal user,
      @ApiParam("yaml config") String payload); long createSubscriptionConfig(@NotNull String payload); @POST @Path("/subscription") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.TEXT_PLAIN) @ApiOperation("Create a subscription group using a YAML config") @SuppressWarnings("unchecked") Response createSubscriptionConfigApi(
      @ApiParam("payload") String payload); @PUT @Path("/subscription/{id}") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.TEXT_PLAIN) @PermitAll @ApiOperation("Edit a subscription group using a YAML config") Response updateSubscriptionGroupApi(
      @Auth ThirdEyePrincipal user,
      @ApiParam("payload") String payload,
      @ApiParam("the detection alert config id to edit") @PathParam("id") long id); @POST @Path("/preview") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.TEXT_PLAIN) @ApiOperation("Preview the anomaly detection result of a YAML configuration") Response yamlPreviewApi(
      @QueryParam("start") long start,
      @QueryParam("end") long end,
      @QueryParam("tuningStart") long tuningStart,
      @QueryParam("tuningEnd") long tuningEnd,
      @ApiParam("jsonPayload") String payload); @POST @Path("/preview/{id}") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.TEXT_PLAIN) @ApiOperation("Preview the anomaly detection result of a YAML configuration, with an existing config and historical anomalies") Response yamlPreviewWithHistoricalAnomalies(
      @PathParam("id") long id,
      @QueryParam("start") long start,
      @QueryParam("end") long end,
      @QueryParam("tuningStart") long tuningStart,
      @QueryParam("tuningEnd") long tuningEnd,
      @ApiParam("jsonPayload") String payload); @POST @Path("/preview/baseline") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.TEXT_PLAIN) @ApiOperation("Get baseline from YAML configuration") /* TODO: Will return baseline from yamlPreviewApi together with detection in the future. */ Response yamlPreviewBaselineApi(
      @QueryParam("start") long start,
      @QueryParam("end") long end,
      @QueryParam("urn") @NotNull String urn,
      @QueryParam("tuningStart") long tuningStart,
      @QueryParam("tuningEnd") long tuningEnd,
      @ApiParam("jsonPayload") @NotNull String payload,
      @QueryParam("ruleName") String ruleName); @PUT @Path("/activation/{id}") @ApiOperation("Make detection active or inactive, given id") @Produces(MediaType.APPLICATION_JSON) Response toggleActivation(
      @ApiParam("Detection configuration id for the alert") @NotNull @PathParam("id") long detectionId,
      @ApiParam("Active status you want to set for the alert") @NotNull @QueryParam("active") boolean active); @GET @Path("/list") @ApiOperation( "Get the list of all detection YAML configurations as JSON enhanced with additional information, optionally filtered." + "IMPORTANT NOTE: This endpoint is deprecated because it is not scalable. Please use the /alerts endpoint instead. " + "For now, it is limited to list and filter the most recent 100 alerts only. ") @Produces(MediaType.APPLICATION_JSON) @Deprecated Response listYamls(
      @ApiParam("Dataset the detection configurations should be filtered by") @QueryParam("dataset") String dataset,
      @ApiParam("Metric the detection configurations should be filtered by") @QueryParam("metric") String metric); @PUT @Path("/notify/{id}") @ApiOperation("Send notification email for detection alert config") Response triggerNotification(
      @ApiParam("Subscription configuration id for the alert") @NotNull @PathParam("id") long subscriptionId); }
YamlResource { @POST @Path("/create-alert") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) @PermitAll @ApiOperation("Use yaml to create both subscription and detection yaml. ") public Response createYamlAlert( @Auth ThirdEyePrincipal user, @ApiParam(value = "a json contains both subscription and detection yaml as string") String payload, @ApiParam("tuning window start time for tunable components") @QueryParam("startTime") long tuningStartTime, @ApiParam("tuning window end time for tunable components") @QueryParam("endTime") long tuningEndTime) { Map<String, String> responseMessage = new HashMap<>(); Long detectionConfigId = null; Long subscriptionConfigId = null; boolean isAlertCreationSuccess = false; Map<String, String> yamls; try { validatePayload(payload); yamls = OBJECT_MAPPER.readValue(payload, Map.class); validateCreateAlertYaml(yamls); String detectionYaml = yamls.get(PROP_DETECTION); ConfigValidationUtils.checkArgument(StringUtils.isNotBlank(detectionYaml), String.format(MISSING_YAML_MSG, "Detection")); detectionConfigId = createDetectionConfig(detectionYaml, tuningStartTime, tuningEndTime); String subscriptionYaml = yamls.get(PROP_SUBSCRIPTION); ConfigValidationUtils.checkArgument(StringUtils.isNotBlank(subscriptionYaml), String.format(MISSING_YAML_MSG, "Subscription group")); Map<String, Object> subscriptionYamlConfig = ConfigUtils.getMap(this.yaml.load(subscriptionYaml)); String groupName = MapUtils.getString(subscriptionYamlConfig, PROP_SUBS_GROUP_NAME); List<DetectionAlertConfigDTO> alertConfigDTOS = subscriptionConfigDAO.findByPredicate(Predicate.EQ("name", groupName)); if (!alertConfigDTOS.isEmpty()) { subscriptionConfigId = alertConfigDTOS.get(0).getId(); updateSubscriptionGroup(user, subscriptionConfigId, subscriptionYaml); } else { subscriptionConfigId = createSubscriptionConfig(subscriptionYaml); } isAlertCreationSuccess = true; createYamlOnboardingTask(detectionConfigId, tuningStartTime, tuningEndTime); } catch (ConfigValidationException e) { return processValidationErrorResponse(PROP_ALERT, YamlOperations.CREATING.name(), payload, e); } catch (NotAuthorizedException e) { return processBadAuthorizationResponse(PROP_ALERT, YamlOperations.UPDATING.name(), payload, e); } catch (Exception e) { return processServerErrorResponse(PROP_ALERT, YamlOperations.CREATING.name() + "/" + YamlOperations.UPDATING.name(), payload, e); } finally { if (!isAlertCreationSuccess) { rollbackAlert(detectionConfigId, subscriptionConfigId); } } responseMessage.put("message", "Alert was created successfully."); responseMessage.put("more-info", "Record saved with detection id " + detectionConfigId + " and subscription id " + subscriptionConfigId); responseMessage.put(PROP_DETECTION_ID, String.valueOf(detectionConfigId)); responseMessage.put(PROP_SUBSCRIPTION_ID, String.valueOf(subscriptionConfigId)); return Response.ok().entity(responseMessage).build(); } YamlResource(Map<String, Map<String, Object>> alerterConfig, DetectionPreviewConfiguration previewConfig,
      double alertOnboardingPermitPerSecond);  YamlResource(Map<String, Map<String, Object>> alerterConfig, DetectionPreviewConfiguration previewConfig); void validateCreateAlertYaml(Map<String, String> config); @POST @Path("/create-alert") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) @PermitAll @ApiOperation("Use yaml to create both subscription and detection yaml. ") Response createYamlAlert(
      @Auth ThirdEyePrincipal user,
      @ApiParam(value =  "a json contains both subscription and detection yaml as string")  String payload,
      @ApiParam("tuning window start time for tunable components") @QueryParam("startTime") long tuningStartTime,
      @ApiParam("tuning window end time for tunable components") @QueryParam("endTime") long tuningEndTime); @POST @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.TEXT_PLAIN) @ApiOperation("Set up a detection pipeline using a YAML config") Response createDetectionPipelineApi(
      @ApiParam("yaml config") String payload,
      @ApiParam("tuning window start time for tunable components") @QueryParam("startTime") long startTime,
      @ApiParam("tuning window end time for tunable components") @QueryParam("endTime") long endTime); @PUT @Path("/{id}") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.TEXT_PLAIN) @PermitAll @ApiOperation("Edit a detection pipeline using a YAML config") Response updateDetectionPipelineApi(
      @Auth ThirdEyePrincipal user,
      @ApiParam("yaml config") String payload,
      @ApiParam("the detection config id to edit") @PathParam("id") long id,
      @ApiParam("tuning window start time for tunable components")  @QueryParam("startTime") long startTime,
      @ApiParam("tuning window end time for tunable components") @QueryParam("endTime") long endTime); @POST @Path("/create-or-update") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.TEXT_PLAIN) @PermitAll @ApiOperation("Create a new detection config or update existing if one already exists") Response createOrUpdateDetectionConfigApi(
      @Auth ThirdEyePrincipal user,
      @ApiParam("yaml config") String payload); @POST @Path("/subscription/create-or-update") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.TEXT_PLAIN) @PermitAll @ApiOperation("Create a new subscription config or update existing if one already exists") Response createOrUpdateSubscriptionConfigApi(
      @Auth ThirdEyePrincipal user,
      @ApiParam("yaml config") String payload); long createSubscriptionConfig(@NotNull String payload); @POST @Path("/subscription") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.TEXT_PLAIN) @ApiOperation("Create a subscription group using a YAML config") @SuppressWarnings("unchecked") Response createSubscriptionConfigApi(
      @ApiParam("payload") String payload); @PUT @Path("/subscription/{id}") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.TEXT_PLAIN) @PermitAll @ApiOperation("Edit a subscription group using a YAML config") Response updateSubscriptionGroupApi(
      @Auth ThirdEyePrincipal user,
      @ApiParam("payload") String payload,
      @ApiParam("the detection alert config id to edit") @PathParam("id") long id); @POST @Path("/preview") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.TEXT_PLAIN) @ApiOperation("Preview the anomaly detection result of a YAML configuration") Response yamlPreviewApi(
      @QueryParam("start") long start,
      @QueryParam("end") long end,
      @QueryParam("tuningStart") long tuningStart,
      @QueryParam("tuningEnd") long tuningEnd,
      @ApiParam("jsonPayload") String payload); @POST @Path("/preview/{id}") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.TEXT_PLAIN) @ApiOperation("Preview the anomaly detection result of a YAML configuration, with an existing config and historical anomalies") Response yamlPreviewWithHistoricalAnomalies(
      @PathParam("id") long id,
      @QueryParam("start") long start,
      @QueryParam("end") long end,
      @QueryParam("tuningStart") long tuningStart,
      @QueryParam("tuningEnd") long tuningEnd,
      @ApiParam("jsonPayload") String payload); @POST @Path("/preview/baseline") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.TEXT_PLAIN) @ApiOperation("Get baseline from YAML configuration") /* TODO: Will return baseline from yamlPreviewApi together with detection in the future. */ Response yamlPreviewBaselineApi(
      @QueryParam("start") long start,
      @QueryParam("end") long end,
      @QueryParam("urn") @NotNull String urn,
      @QueryParam("tuningStart") long tuningStart,
      @QueryParam("tuningEnd") long tuningEnd,
      @ApiParam("jsonPayload") @NotNull String payload,
      @QueryParam("ruleName") String ruleName); @PUT @Path("/activation/{id}") @ApiOperation("Make detection active or inactive, given id") @Produces(MediaType.APPLICATION_JSON) Response toggleActivation(
      @ApiParam("Detection configuration id for the alert") @NotNull @PathParam("id") long detectionId,
      @ApiParam("Active status you want to set for the alert") @NotNull @QueryParam("active") boolean active); @GET @Path("/list") @ApiOperation( "Get the list of all detection YAML configurations as JSON enhanced with additional information, optionally filtered." + "IMPORTANT NOTE: This endpoint is deprecated because it is not scalable. Please use the /alerts endpoint instead. " + "For now, it is limited to list and filter the most recent 100 alerts only. ") @Produces(MediaType.APPLICATION_JSON) @Deprecated Response listYamls(
      @ApiParam("Dataset the detection configurations should be filtered by") @QueryParam("dataset") String dataset,
      @ApiParam("Metric the detection configurations should be filtered by") @QueryParam("metric") String metric); @PUT @Path("/notify/{id}") @ApiOperation("Send notification email for detection alert config") Response triggerNotification(
      @ApiParam("Subscription configuration id for the alert") @NotNull @PathParam("id") long subscriptionId);  }