Skip to content

Commit c3eb23c

Browse files
committed
feat(app): integrate fleet endpoint to delete the hosts
1 parent f64e0a1 commit c3eb23c

File tree

3 files changed

+93
-2
lines changed

3 files changed

+93
-2
lines changed

apps/api/src/lib/fleet.service.ts

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,4 +77,61 @@ export class FleetService {
7777
throw new Error('Failed to fetch multiple hosts');
7878
}
7979
}
80+
81+
/**
82+
* Remove all hosts from FleetDM that belong to a specific label
83+
* @param fleetDmLabelId - The FleetDM label ID
84+
* @returns Promise with deletion results
85+
*/
86+
async removeHostsByLabel(fleetDmLabelId: number): Promise<{
87+
deletedCount: number;
88+
failedCount: number;
89+
hostIds: number[];
90+
}> {
91+
try {
92+
// Get all hosts for this label
93+
const labelHosts = await this.getHostsByLabel(fleetDmLabelId);
94+
95+
if (!labelHosts.hosts || labelHosts.hosts.length === 0) {
96+
this.logger.log(`No hosts found for label ${fleetDmLabelId}`);
97+
return {
98+
deletedCount: 0,
99+
failedCount: 0,
100+
hostIds: [],
101+
};
102+
}
103+
104+
// Extract host IDs
105+
const hostIds = labelHosts.hosts.map((host: { id: number }) => host.id);
106+
107+
// Delete each host
108+
const deletePromises = hostIds.map(async (hostId: number) => {
109+
try {
110+
await this.fleetInstance.delete(`/hosts/${hostId}`);
111+
this.logger.debug(`Deleted host ${hostId} from FleetDM`);
112+
return { success: true, hostId };
113+
} catch (error) {
114+
this.logger.error(`Failed to delete host ${hostId}:`, error);
115+
return { success: false, hostId };
116+
}
117+
});
118+
119+
const results = await Promise.all(deletePromises);
120+
const deletedCount = results.filter((r) => r.success).length;
121+
const failedCount = results.filter((r) => !r.success).length;
122+
123+
this.logger.log(
124+
`Removed hosts from FleetDM for label ${fleetDmLabelId}: ${deletedCount} deleted, ${failedCount} failed`,
125+
);
126+
127+
return {
128+
deletedCount,
129+
failedCount,
130+
hostIds,
131+
};
132+
} catch (error) {
133+
this.logger.error(`Failed to remove hosts for label ${fleetDmLabelId}:`, error);
134+
throw new Error(`Failed to remove hosts for label ${fleetDmLabelId}: ${error.message}`);
135+
}
136+
}
80137
}
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import { Module } from '@nestjs/common';
22
import { AuthModule } from '../auth/auth.module';
3+
import { FleetService } from '../lib/fleet.service';
34
import { PeopleController } from './people.controller';
45
import { PeopleService } from './people.service';
56

67
@Module({
78
imports: [AuthModule],
89
controllers: [PeopleController],
9-
providers: [PeopleService],
10+
providers: [PeopleService, FleetService],
1011
exports: [PeopleService],
1112
})
1213
export class PeopleModule {}

apps/api/src/people/people.service.ts

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
Logger,
55
BadRequestException,
66
} from '@nestjs/common';
7+
import { FleetService } from '../lib/fleet.service';
78
import type { PeopleResponseDto } from './dto/people-responses.dto';
89
import type { CreatePeopleDto } from './dto/create-people.dto';
910
import type { UpdatePeopleDto } from './dto/update-people.dto';
@@ -15,6 +16,8 @@ import { MemberQueries } from './utils/member-queries';
1516
export class PeopleService {
1617
private readonly logger = new Logger(PeopleService.name);
1718

19+
constructor(private readonly fleetService: FleetService) {}
20+
1821
async findAllByOrganization(
1922
organizationId: string,
2023
): Promise<PeopleResponseDto[]> {
@@ -280,11 +283,41 @@ export class PeopleService {
280283
): Promise<PeopleResponseDto> {
281284
try {
282285
await MemberValidator.validateOrganization(organizationId);
283-
await MemberValidator.validateMemberExists(
286+
const existingMember = await MemberQueries.findByIdInOrganization(
284287
memberId,
285288
organizationId,
286289
);
287290

291+
if (!existingMember) {
292+
throw new NotFoundException(
293+
`Member with ID ${memberId} not found in organization ${organizationId}`,
294+
);
295+
}
296+
297+
// Remove hosts from FleetDM before unlinking the device
298+
if (existingMember.fleetDmLabelId) {
299+
try {
300+
const removalResult = await this.fleetService.removeHostsByLabel(
301+
existingMember.fleetDmLabelId,
302+
);
303+
this.logger.log(
304+
`Removed ${removalResult.deletedCount} host(s) from FleetDM for label ${existingMember.fleetDmLabelId}`,
305+
);
306+
if (removalResult.failedCount > 0) {
307+
this.logger.warn(
308+
`Failed to remove ${removalResult.failedCount} host(s) from FleetDM`,
309+
);
310+
}
311+
} catch (fleetError) {
312+
// Log FleetDM error but don't fail the entire operation
313+
this.logger.error(
314+
`Failed to remove hosts from FleetDM for label ${existingMember.fleetDmLabelId}:`,
315+
fleetError,
316+
);
317+
// Continue with unlinking the device even if FleetDM removal fails
318+
}
319+
}
320+
288321
const updatedMember = await MemberQueries.unlinkDevice(memberId);
289322

290323
this.logger.log(

0 commit comments

Comments
 (0)