Skip to content

Commit

Permalink
feat: working
Browse files Browse the repository at this point in the history
  • Loading branch information
talboren committed Feb 19, 2024
1 parent 7ff1ad7 commit 3b32fe0
Show file tree
Hide file tree
Showing 8 changed files with 87 additions and 68 deletions.
15 changes: 11 additions & 4 deletions keep-ui/app/mapping/create-new-mapping.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@ import { ChangeEvent, FormEvent, useMemo, useState } from "react";
import { usePapaParse } from "react-papaparse";
import { toast } from "react-toastify";
import { getApiURL } from "utils/apiUrl";
import { useMappings } from "utils/hooks/useMappingRules";

export default function CreateNewMapping({ mutate }: { mutate: () => void }) {
export default function CreateNewMapping() {
const { data: session } = useSession();
const { mutate } = useMappings();
const [mapName, setMapName] = useState<string>("");
const [fileName, setFileName] = useState<string>("");
const [mapDescription, setMapDescription] = useState<string>("");
Expand Down Expand Up @@ -64,8 +66,10 @@ export default function CreateNewMapping({ mutate }: { mutate: () => void }) {
e.preventDefault();
const apiUrl = getApiURL();
const response = await fetch(`${apiUrl}/mapping`, {
method: "POST",
headers: {
Authorization: `Bearer ${session?.accessToken}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
name: mapName,
Expand All @@ -77,6 +81,7 @@ export default function CreateNewMapping({ mutate }: { mutate: () => void }) {
});
if (response.ok) {
clearForm();
mutate();
toast.success("Mapping created successfully");
} else {
toast.error(
Expand Down Expand Up @@ -126,9 +131,11 @@ export default function CreateNewMapping({ mutate }: { mutate: () => void }) {
onChange={readFile}
required={true}
/>
<Text className="text-xs text-orange-400">
* Upload a CSV file to start creating a new mapping
</Text>
{!parsedData && (
<Text className="text-xs text-red-500">
* Upload a CSV file to begin with creating a new mapping
</Text>
)}
</div>
<Subtitle className="mt-2.5">Mapping Schema</Subtitle>
<div className="mt-2.5">
Expand Down
27 changes: 27 additions & 0 deletions keep-ui/app/mapping/mapping.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
"use client";
import { Badge, Card } from "@tremor/react";
import CreateNewMapping from "./create-new-mapping";
import { useMappings } from "utils/hooks/useMappingRules";
export default function Mapping() {
const { data: mappings, mutate } = useMappings();

return (
<Card className="p-4 md:p-10 mx-auto">
<Badge color="orange" size="xs" tooltip="Slack us if something isn't working properly :)" className="absolute top-[-10px] left-[-10px]">Beta</Badge>
<div className="flex divide-x p-2">
<div className="w-1/3 pr-2.5">
<h2 className="text-lg">Configure</h2>
<p className="text-slate-400">
Add dynamic context to your alerts with mapping rules
</p>
<CreateNewMapping />
</div>

<div className="w-2/3 pl-2.5">
<h2 className="text-lg">Rules</h2>
{mappings && mappings.length > 0 ? <>Rules!</> : <>No Rules!</>}
</div>
</div>
</Card>
);
}
25 changes: 2 additions & 23 deletions keep-ui/app/mapping/page.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,7 @@
import { Card } from "@tremor/react";
import CreateNewMapping from "./create-new-mapping";
import { useMappings } from "utils/hooks/useMappingRules";
import Mapping from "./mapping";

export default function Page() {
const { data: mappings, mutate } = useMappings();

return (
<Card className="p-4 md:p-10 mx-auto">
<div className="flex divide-x p-2">
<div className="w-1/3 pr-2.5">
<h2 className="text-lg">Configure</h2>
<p className="text-slate-400">
Add dynamic context to your alerts with mapping rules
</p>
<CreateNewMapping mutate={mutate} />
</div>

<div className="w-2/3 pl-2.5">
<h2 className="text-lg">Rules</h2>
{mappings && mappings.length > 0 ? <>Rules!</> : <>No Rules!</>}
</div>
</div>
</Card>
);
return <Mapping />;
}

export const metadata = {
Expand Down
7 changes: 3 additions & 4 deletions keep-ui/utils/hooks/useMappingRules.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import { MappingRule } from "app/mapping/models";
import { getServerSession } from "next-auth";
import { authOptions } from "pages/api/auth/[...nextauth]";
import { useSession } from "next-auth/react";
import useSWR, { SWRConfiguration } from "swr";
import { getApiURL } from "utils/apiUrl";
import { fetcher } from "utils/fetcher";

export const useMappings = async (options: SWRConfiguration = {}) => {
export const useMappings = (options: SWRConfiguration = {}) => {
const apiUrl = getApiURL();
const session = await getServerSession(authOptions);
const { data: session } = useSession();

return useSWR<MappingRule[]>(
() => (session ? `${apiUrl}/mapping` : null),
Expand Down
4 changes: 3 additions & 1 deletion keep/api/bl/enrichments.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,9 @@ def run_mapping_rules(self, alert: AlertDto):
for key, value in row.items()
if key not in rule.matchers
}
enrich_alert(self.tenant_id, alert.fingerprint, enrichments)
enrich_alert(
self.tenant_id, alert.fingerprint, enrichments, self.db_session
)
self.logger.info(
"Alert enriched", extra={"fingerprint": alert.fingerprint}
)
Expand Down
58 changes: 32 additions & 26 deletions keep/api/core/db.py
Original file line number Diff line number Diff line change
Expand Up @@ -602,33 +602,39 @@ def get_last_workflow_executions(tenant_id: str, limit=20):
return execution_with_logs


def enrich_alert(tenant_id, fingerprint, enrichments):
def _enrich_alert(session, tenant_id, fingerprint, enrichments):
enrichment = get_enrichment_with_session(session, tenant_id, fingerprint)
if enrichment:
# SQLAlchemy doesn't support updating JSON fields, so we need to do it manually
# https://github.com/sqlalchemy/sqlalchemy/discussions/8396#discussion-4308891
new_enrichment_data = {**enrichment.enrichments, **enrichments}
stmt = (
update(AlertEnrichment)
.where(AlertEnrichment.id == enrichment.id)
.values(enrichments=new_enrichment_data)
)
session.execute(stmt)
session.commit()
# Refresh the instance to get updated data from the database
session.refresh(enrichment)
return enrichment
else:
alert_enrichment = AlertEnrichment(
tenant_id=tenant_id,
alert_fingerprint=fingerprint,
enrichments=enrichments,
)
session.add(alert_enrichment)
session.commit()
return alert_enrichment


def enrich_alert(tenant_id, fingerprint, enrichments, session=None):
# else, the enrichment doesn't exist, create it
with Session(engine) as session:
enrichment = get_enrichment_with_session(session, tenant_id, fingerprint)
if enrichment:
# SQLAlchemy doesn't support updating JSON fields, so we need to do it manually
# https://github.com/sqlalchemy/sqlalchemy/discussions/8396#discussion-4308891
new_enrichment_data = {**enrichment.enrichments, **enrichments}
stmt = (
update(AlertEnrichment)
.where(AlertEnrichment.id == enrichment.id)
.values(enrichments=new_enrichment_data)
)
session.execute(stmt)
session.commit()
# Refresh the instance to get updated data from the database
session.refresh(enrichment)
return enrichment
else:
alert_enrichment = AlertEnrichment(
tenant_id=tenant_id,
alert_fingerprint=fingerprint,
enrichments=enrichments,
)
session.add(alert_enrichment)
session.commit()
return alert_enrichment
if not session:
with Session(engine) as session:
return _enrich_alert(session, tenant_id, fingerprint, enrichments)
return _enrich_alert(session, tenant_id, fingerprint, enrichments)


def get_enrichment(tenant_id, fingerprint):
Expand Down
10 changes: 5 additions & 5 deletions keep/api/models/db/mapping.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,18 @@ class MappingRule(SQLModel, table=True):
override: bool = Field(default=True)
condition: Optional[str] = Field(max_length=2000)
# The attributes to match against (e.g. ["service","region"])
matchers: list = Field(sa_column=Column(JSON), nullable=False)
matchers: list[str] = Field(sa_column=Column(JSON), nullable=False)
# The rows of the CSV file [{service: "service1", region: "region1", ...}, ...]
rows: dict = Field(
rows: list[dict] = Field(
sa_column=Column(JSON),
nullable=False,
) # max_length=204800)


class MappingRuleDto(BaseModel):
name: str
description: Optional[str]
file_name: Optional[str]
description: Optional[str] = None
file_name: Optional[str] = None
priority: int = 0
matchers: list[str]
rows: dict
rows: list[dict]
9 changes: 4 additions & 5 deletions keep/api/routes/mapping.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@
logger = logging.getLogger(__name__)


@router.get("", description="Get all mapping rules", response_class=list[MappingRule])
@router.get("", description="Get all mapping rules")
def get_rules(
authenticated_entity: AuthenticatedEntity = Depends(AuthVerifier(["read:rules"])),
session: Session = Depends(get_session),
):
) -> list[MappingRule]:
logger.info("Getting mapping rules")
rules: list[MappingRule] = (
session.query(MappingRule)
Expand All @@ -27,18 +27,17 @@ def get_rules(
return rules


@router.post("", description="Create a new mapping rule", response_class=MappingRule)
@router.post("", description="Create a new mapping rule")
def create_rule(
rule: MappingRuleDto,
authenticated_entity: AuthenticatedEntity = Depends(AuthVerifier(["write:rules"])),
session: Session = Depends(get_session),
):
) -> MappingRule:
logger.info("Creating a new mapping rule")
new_rule = MappingRule(
**rule.dict(),
tenant_id=authenticated_entity.tenant_id,
created_by=authenticated_entity.email,
priority=rule.priority,
)
session.add(new_rule)
session.commit()
Expand Down

0 comments on commit 3b32fe0

Please sign in to comment.