mirror of
https://github.com/unraid/api.git
synced 2026-02-15 20:48:30 -06:00
fix: container port duplication
This commit is contained in:
@@ -10,7 +10,11 @@ import { pubsub, PUBSUB_CHANNEL } from '@app/core/pubsub.js';
|
||||
import { DockerConfigService } from '@app/unraid-api/graph/resolvers/docker/docker-config.service.js';
|
||||
import { DockerManifestService } from '@app/unraid-api/graph/resolvers/docker/docker-manifest.service.js';
|
||||
import { DockerTemplateScannerService } from '@app/unraid-api/graph/resolvers/docker/docker-template-scanner.service.js';
|
||||
import { ContainerState, DockerContainer } from '@app/unraid-api/graph/resolvers/docker/docker.model.js';
|
||||
import {
|
||||
ContainerPortType,
|
||||
ContainerState,
|
||||
DockerContainer,
|
||||
} from '@app/unraid-api/graph/resolvers/docker/docker.model.js';
|
||||
import { DockerService } from '@app/unraid-api/graph/resolvers/docker/docker.service.js';
|
||||
import { NotificationsService } from '@app/unraid-api/graph/resolvers/notifications/notifications.service.js';
|
||||
|
||||
@@ -647,6 +651,53 @@ describe('DockerService', () => {
|
||||
expect(mockCacheManager.set).not.toHaveBeenCalled(); // Ensure cache is NOT set on error
|
||||
});
|
||||
|
||||
describe('transformContainer', () => {
|
||||
it('deduplicates ports that only differ by bound IP addresses', () => {
|
||||
mockEmhttpGetter.mockReturnValue({
|
||||
networks: [{ ipaddr: ['192.168.0.10'] }],
|
||||
var: {},
|
||||
});
|
||||
|
||||
const container = {
|
||||
Id: 'duplicate-ports',
|
||||
Names: ['/duplicate-ports'],
|
||||
Image: 'test-image',
|
||||
ImageID: 'sha256:123',
|
||||
Command: 'test',
|
||||
Created: 1700000000,
|
||||
State: 'running',
|
||||
Status: 'Up 2 hours',
|
||||
Ports: [
|
||||
{ IP: '0.0.0.0', PrivatePort: 8080, PublicPort: 8080, Type: 'tcp' },
|
||||
{ IP: '::', PrivatePort: 8080, PublicPort: 8080, Type: 'tcp' },
|
||||
{ IP: '0.0.0.0', PrivatePort: 5000, PublicPort: 5000, Type: 'udp' },
|
||||
],
|
||||
Labels: {},
|
||||
HostConfig: { NetworkMode: 'bridge' },
|
||||
NetworkSettings: { Networks: {} },
|
||||
Mounts: [],
|
||||
} as Docker.ContainerInfo;
|
||||
|
||||
const transformed = service.transformContainer(container);
|
||||
|
||||
expect(transformed.ports).toEqual([
|
||||
{
|
||||
ip: '0.0.0.0',
|
||||
privatePort: 8080,
|
||||
publicPort: 8080,
|
||||
type: ContainerPortType.TCP,
|
||||
},
|
||||
{
|
||||
ip: '0.0.0.0',
|
||||
privatePort: 5000,
|
||||
publicPort: 5000,
|
||||
type: ContainerPortType.UDP,
|
||||
},
|
||||
]);
|
||||
expect(transformed.lanIpPorts).toBe('192.168.0.10:8080, 192.168.0.10:5000');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getAppInfo', () => {
|
||||
// Common mock containers for these tests
|
||||
const mockContainersForMethods = [
|
||||
|
||||
@@ -115,6 +115,28 @@ export class DockerService {
|
||||
return firstName ? firstName.replace(/^\//, '') : null;
|
||||
}
|
||||
|
||||
private deduplicateContainerPorts(
|
||||
ports: Docker.ContainerInfo['Ports'] | undefined
|
||||
): Docker.ContainerInfo['Ports'] {
|
||||
if (!Array.isArray(ports)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const seen = new Set<string>();
|
||||
const uniquePorts: Docker.ContainerInfo['Ports'] = [];
|
||||
|
||||
for (const port of ports) {
|
||||
const key = `${port.PrivatePort ?? ''}-${port.PublicPort ?? ''}-${(port.Type ?? '').toLowerCase()}`;
|
||||
if (seen.has(key)) {
|
||||
continue;
|
||||
}
|
||||
seen.add(key);
|
||||
uniquePorts.push(port);
|
||||
}
|
||||
|
||||
return uniquePorts;
|
||||
}
|
||||
|
||||
public getDockerClient() {
|
||||
return new Docker({
|
||||
socketPath: '/var/run/docker.sock',
|
||||
@@ -151,8 +173,9 @@ export class DockerService {
|
||||
const autoStartEntry = primaryName ? this.autoStartEntryByName.get(primaryName) : undefined;
|
||||
const lanIp = getLanIp();
|
||||
const lanPortStrings: string[] = [];
|
||||
const uniquePorts = this.deduplicateContainerPorts(container.Ports);
|
||||
|
||||
const transformedPorts = container.Ports.map((port) => {
|
||||
const transformedPorts = uniquePorts.map((port) => {
|
||||
if (port.PublicPort) {
|
||||
const lanPort = lanIp ? `${lanIp}:${port.PublicPort}` : `${port.PublicPort}`;
|
||||
if (lanPort) {
|
||||
|
||||
Reference in New Issue
Block a user