diff --git a/app/lib/kafka.server.ts b/app/lib/kafka.server.ts
index 831aa0701..dbaa4c5b5 100644
--- a/app/lib/kafka.server.ts
+++ b/app/lib/kafka.server.ts
@@ -9,6 +9,7 @@ import { tables } from '@architect/functions'
import { paginateScan } from '@aws-sdk/lib-dynamodb'
import type { DynamoDBDocument } from '@aws-sdk/lib-dynamodb'
import crypto from 'crypto'
+import type { AclFilter } from 'gcn-kafka'
import { Kafka } from 'gcn-kafka'
import type { AclEntry } from 'kafkajs'
import {
@@ -81,17 +82,6 @@ if (process.env.ARC_SANDBOX) {
}
}
-/**
- * AclEntry already contains definitions for the following:
- *
- * principal: string --> 'User:{cognito_group_name}'
- * host: string --> '*'
- * operation: AclOperationTypes --> Read,Write, etc from enum
- * permissionType: AclPermissionTypes --> Allow, Deny, etc from enum
- * resourceType: AclResourceTypes --> TOPIC, etc
- * resourceName: string --> name of topic: 'gcn.notices.burstcube'
- * resourcePatternType: ResourcePatternTypes --> PREFIXED or LITERAL
- */
export type KafkaACL = AclEntry & {
aclId?: string
}
@@ -139,9 +129,9 @@ export async function createKafkaACL(
resourceName,
principal: `User:${group}`,
host: '*',
- operation, // Read, write, etc
- permissionType, // Allow, deny etc
- resourcePatternType: 3, // LITERAL | PREFIXED
+ operation,
+ permissionType,
+ resourcePatternType: 3,
resourceType,
}
})
@@ -150,9 +140,9 @@ export async function createKafkaACL(
resourceName,
principal: `User:${group}`,
host: '*',
- operation, // Read, write, etc
+ operation,
permissionType,
- resourcePatternType: 3, // LITERAL | PREFIX
+ resourcePatternType: 3,
resourceType,
}
})
@@ -280,13 +270,13 @@ export async function getAclsFromBrokers() {
export async function deleteKafkaACL(user: User, aclIds: string[]) {
validateUser(user)
const db = await tables()
- const acls = await Promise.all(
+ const acls: KafkaACL[] = await Promise.all(
aclIds.map((aclId) => db.kafka_acls.get({ aclId }))
)
const adminClient = adminKafka.admin()
await adminClient.connect()
- await adminClient.deleteAcls({ filters: acls })
+ await adminClient.deleteAcls({ filters: acls as AclFilter[] })
await adminClient.disconnect()
await Promise.all(
diff --git a/app/routes/admin.kafka._index.tsx b/app/routes/admin.kafka._index.tsx
index b2b877679..0685fcd23 100644
--- a/app/routes/admin.kafka._index.tsx
+++ b/app/routes/admin.kafka._index.tsx
@@ -19,6 +19,7 @@ import {
ModalToggleButton,
TextInput,
} from '@trussworks/react-uswds'
+import { groupBy, sortBy } from 'lodash'
import { useEffect, useRef, useState } from 'react'
import { getUser } from './_auth/user.server'
@@ -43,7 +44,13 @@ export async function loader({ request }: LoaderFunctionArgs) {
if (!user || !user.groups.includes(adminGroup))
throw new Response(null, { status: 403 })
const { aclFilter } = Object.fromEntries(new URL(request.url).searchParams)
- const dynamoDbAclData = await getKafkaACLsFromDynamoDB(user, aclFilter)
+ const dynamoDbAclData = groupBy(
+ sortBy(await getKafkaACLsFromDynamoDB(user, aclFilter), [
+ 'resourceName',
+ 'principal',
+ ]),
+ 'resourceName'
+ )
const latestSync = await getLastSyncDate()
return { dynamoDbAclData, latestSync }
}
@@ -54,6 +61,7 @@ export async function action({ request }: ActionFunctionArgs) {
throw new Response(null, { status: 403 })
const data = await request.formData()
const intent = getFormDataString(data, 'intent')
+
if (intent === 'migrateFromBroker') {
await updateDbFromBrokers(user)
return null
@@ -64,11 +72,11 @@ export async function action({ request }: ActionFunctionArgs) {
return null
}
- const aclId = getFormDataString(data, 'aclId')
const promises = []
switch (intent) {
case 'delete':
+ const aclId = getFormDataString(data, 'aclId')
if (!aclId) throw new Response(null, { status: 400 })
promises.push(deleteKafkaACL(user, [aclId]))
break
@@ -78,8 +86,8 @@ export async function action({ request }: ActionFunctionArgs) {
data,
'userClientType'
) as UserClientType
- const permissionTypeString = getFormDataString(data, 'permissionType')
const group = getFormDataString(data, 'group')
+ const permissionTypeString = getFormDataString(data, 'permissionType')
const includePrefixed = getFormDataString(data, 'includePrefixed')
const resourceTypeString = getFormDataString(data, 'resourceType')
@@ -122,6 +130,7 @@ export default function Index() {
const updateFetcher = useFetcher
Last synced by {latestSync.syncedBy}{' '}