Adding a node should immediately provision it.
This commit is contained in:
@@ -106,7 +106,7 @@ describe('NodeForm Integration Tests', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('auto-fills currentIp from detection', async () => {
|
it('auto-fills targetIp from detection', async () => {
|
||||||
const config = createMockConfig();
|
const config = createMockConfig();
|
||||||
vi.mocked(useInstanceConfig).mockReturnValue(mockUseInstanceConfig(config));
|
vi.mocked(useInstanceConfig).mockReturnValue(mockUseInstanceConfig(config));
|
||||||
vi.mocked(useNodes).mockReturnValue(mockUseNodes([]));
|
vi.mocked(useNodes).mockReturnValue(mockUseNodes([]));
|
||||||
@@ -122,8 +122,8 @@ describe('NodeForm Integration Tests', () => {
|
|||||||
{ wrapper: createWrapper(createTestQueryClient()) }
|
{ wrapper: createWrapper(createTestQueryClient()) }
|
||||||
);
|
);
|
||||||
|
|
||||||
const currentIpInput = screen.getByLabelText(/current ip/i) as HTMLInputElement;
|
const targetIpInput = screen.getByLabelText(/target ip/i) as HTMLInputElement;
|
||||||
expect(currentIpInput.value).toBe('192.168.1.75');
|
expect(targetIpInput.value).toBe('192.168.1.75');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('submits form with correct data', async () => {
|
it('submits form with correct data', async () => {
|
||||||
@@ -132,7 +132,8 @@ describe('NodeForm Integration Tests', () => {
|
|||||||
vi.mocked(useInstanceConfig).mockReturnValue(mockUseInstanceConfig(config));
|
vi.mocked(useInstanceConfig).mockReturnValue(mockUseInstanceConfig(config));
|
||||||
vi.mocked(useNodes).mockReturnValue(mockUseNodes([]));
|
vi.mocked(useNodes).mockReturnValue(mockUseNodes([]));
|
||||||
|
|
||||||
const detection = createMockHardwareInfo();
|
// Don't provide detection.ip so VIP-based auto-calculation happens
|
||||||
|
const detection = createMockHardwareInfo({ ip: undefined });
|
||||||
|
|
||||||
render(
|
render(
|
||||||
<NodeForm
|
<NodeForm
|
||||||
@@ -154,7 +155,6 @@ describe('NodeForm Integration Tests', () => {
|
|||||||
role: 'controlplane',
|
role: 'controlplane',
|
||||||
disk: '/dev/sda',
|
disk: '/dev/sda',
|
||||||
interface: 'eth0',
|
interface: 'eth0',
|
||||||
currentIp: '192.168.1.50',
|
|
||||||
maintenance: true,
|
maintenance: true,
|
||||||
schematicId: 'default-schematic-123',
|
schematicId: 'default-schematic-123',
|
||||||
targetIp: '192.168.1.101',
|
targetIp: '192.168.1.101',
|
||||||
@@ -201,7 +201,8 @@ describe('NodeForm Integration Tests', () => {
|
|||||||
vi.mocked(useInstanceConfig).mockReturnValue(mockUseInstanceConfig(config));
|
vi.mocked(useInstanceConfig).mockReturnValue(mockUseInstanceConfig(config));
|
||||||
vi.mocked(useNodes).mockReturnValue(mockUseNodes([]));
|
vi.mocked(useNodes).mockReturnValue(mockUseNodes([]));
|
||||||
|
|
||||||
const detection = createMockHardwareInfo();
|
// Don't provide detection.ip so VIP-based auto-calculation happens
|
||||||
|
const detection = createMockHardwareInfo({ ip: undefined });
|
||||||
|
|
||||||
render(
|
render(
|
||||||
<NodeForm
|
<NodeForm
|
||||||
@@ -239,7 +240,8 @@ describe('NodeForm Integration Tests', () => {
|
|||||||
vi.mocked(useInstanceConfig).mockReturnValue(mockUseInstanceConfig(config));
|
vi.mocked(useInstanceConfig).mockReturnValue(mockUseInstanceConfig(config));
|
||||||
vi.mocked(useNodes).mockReturnValue(mockUseNodes(existingNodes));
|
vi.mocked(useNodes).mockReturnValue(mockUseNodes(existingNodes));
|
||||||
|
|
||||||
const detection = createMockHardwareInfo();
|
// Don't provide detection.ip so VIP-based auto-calculation happens
|
||||||
|
const detection = createMockHardwareInfo({ ip: undefined });
|
||||||
|
|
||||||
render(
|
render(
|
||||||
<NodeForm
|
<NodeForm
|
||||||
@@ -275,7 +277,8 @@ describe('NodeForm Integration Tests', () => {
|
|||||||
vi.mocked(useInstanceConfig).mockReturnValue(mockUseInstanceConfig(config));
|
vi.mocked(useInstanceConfig).mockReturnValue(mockUseInstanceConfig(config));
|
||||||
vi.mocked(useNodes).mockReturnValue(mockUseNodes(existingNodes));
|
vi.mocked(useNodes).mockReturnValue(mockUseNodes(existingNodes));
|
||||||
|
|
||||||
const detection = createMockHardwareInfo();
|
// Don't provide detection.ip so VIP-based auto-calculation happens
|
||||||
|
const detection = createMockHardwareInfo({ ip: undefined });
|
||||||
|
|
||||||
render(
|
render(
|
||||||
<NodeForm
|
<NodeForm
|
||||||
@@ -306,7 +309,6 @@ describe('NodeForm Integration Tests', () => {
|
|||||||
role: 'controlplane',
|
role: 'controlplane',
|
||||||
disk: '/dev/nvme0n1',
|
disk: '/dev/nvme0n1',
|
||||||
targetIp: '192.168.1.105',
|
targetIp: '192.168.1.105',
|
||||||
currentIp: '192.168.1.60',
|
|
||||||
interface: 'eth1',
|
interface: 'eth1',
|
||||||
schematicId: 'existing-schematic-456',
|
schematicId: 'existing-schematic-456',
|
||||||
maintenance: false,
|
maintenance: false,
|
||||||
@@ -327,14 +329,8 @@ describe('NodeForm Integration Tests', () => {
|
|||||||
const targetIpInput = screen.getByLabelText(/target ip/i) as HTMLInputElement;
|
const targetIpInput = screen.getByLabelText(/target ip/i) as HTMLInputElement;
|
||||||
expect(targetIpInput.value).toBe('192.168.1.105');
|
expect(targetIpInput.value).toBe('192.168.1.105');
|
||||||
|
|
||||||
const currentIpInput = screen.getByLabelText(/current ip/i) as HTMLInputElement;
|
|
||||||
expect(currentIpInput.value).toBe('192.168.1.60');
|
|
||||||
|
|
||||||
const schematicInput = screen.getByLabelText(/schematic id/i) as HTMLInputElement;
|
const schematicInput = screen.getByLabelText(/schematic id/i) as HTMLInputElement;
|
||||||
expect(schematicInput.value).toBe('existing-schematic-456');
|
expect(schematicInput.value).toBe('existing-schematic-456');
|
||||||
|
|
||||||
const maintenanceCheckbox = screen.getByLabelText(/maintenance/i) as HTMLInputElement;
|
|
||||||
expect(maintenanceCheckbox.checked).toBe(false);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('does NOT auto-generate hostname', async () => {
|
it('does NOT auto-generate hostname', async () => {
|
||||||
@@ -418,7 +414,6 @@ describe('NodeForm Integration Tests', () => {
|
|||||||
role: 'controlplane',
|
role: 'controlplane',
|
||||||
disk: '/dev/nvme0n1',
|
disk: '/dev/nvme0n1',
|
||||||
targetIp: '192.168.1.105',
|
targetIp: '192.168.1.105',
|
||||||
currentIp: '192.168.1.60',
|
|
||||||
interface: 'eth0',
|
interface: 'eth0',
|
||||||
schematicId: 'existing-schematic-456',
|
schematicId: 'existing-schematic-456',
|
||||||
maintenance: false,
|
maintenance: false,
|
||||||
@@ -553,7 +548,6 @@ describe('NodeForm Integration Tests', () => {
|
|||||||
disk: '/dev/nvme0n1',
|
disk: '/dev/nvme0n1',
|
||||||
interface: 'eth1',
|
interface: 'eth1',
|
||||||
targetIp: '192.168.1.105',
|
targetIp: '192.168.1.105',
|
||||||
currentIp: '192.168.1.60',
|
|
||||||
schematicId: 'existing-schematic',
|
schematicId: 'existing-schematic',
|
||||||
maintenance: false,
|
maintenance: false,
|
||||||
};
|
};
|
||||||
@@ -589,7 +583,6 @@ describe('NodeForm Integration Tests', () => {
|
|||||||
disk: '/dev/nvme0n1', // NOT /dev/sda from detection
|
disk: '/dev/nvme0n1', // NOT /dev/sda from detection
|
||||||
interface: 'eth1', // NOT eth0 from detection
|
interface: 'eth1', // NOT eth0 from detection
|
||||||
targetIp: '192.168.1.105',
|
targetIp: '192.168.1.105',
|
||||||
currentIp: '192.168.1.60',
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -881,8 +874,9 @@ describe('NodeForm Integration Tests', () => {
|
|||||||
const hostnameInput = screen.getByLabelText(/hostname/i) as HTMLInputElement;
|
const hostnameInput = screen.getByLabelText(/hostname/i) as HTMLInputElement;
|
||||||
expect(hostnameInput.value).toBe('test-control-1');
|
expect(hostnameInput.value).toBe('test-control-1');
|
||||||
|
|
||||||
const currentIpInput = screen.getByLabelText(/current ip/i) as HTMLInputElement;
|
// Control plane nodes should auto-calculate targetIp from VIP (192.168.1.100 + 1)
|
||||||
expect(currentIpInput.value).toBe('');
|
const targetIpInput = screen.getByLabelText(/target ip/i) as HTMLInputElement;
|
||||||
|
expect(targetIpInput.value).toBe('192.168.1.101');
|
||||||
|
|
||||||
const diskInput = screen.getByLabelText(/disk/i) as HTMLInputElement;
|
const diskInput = screen.getByLabelText(/disk/i) as HTMLInputElement;
|
||||||
expect(diskInput.value).toBe('');
|
expect(diskInput.value).toBe('');
|
||||||
@@ -906,8 +900,8 @@ describe('NodeForm Integration Tests', () => {
|
|||||||
{ wrapper: createWrapper(createTestQueryClient()) }
|
{ wrapper: createWrapper(createTestQueryClient()) }
|
||||||
);
|
);
|
||||||
|
|
||||||
const currentIpInput = screen.getByLabelText(/current ip/i) as HTMLInputElement;
|
const targetIpInput = screen.getByLabelText(/target ip/i) as HTMLInputElement;
|
||||||
expect(currentIpInput.value).toBe('192.168.1.75');
|
expect(targetIpInput.value).toBe('192.168.1.75');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('handles detection with no disks', async () => {
|
it('handles detection with no disks', async () => {
|
||||||
@@ -1219,7 +1213,6 @@ describe('NodeForm Integration Tests', () => {
|
|||||||
role: 'worker' as const,
|
role: 'worker' as const,
|
||||||
disk: '/dev/sda',
|
disk: '/dev/sda',
|
||||||
interface: 'eth0',
|
interface: 'eth0',
|
||||||
currentIp: '192.168.1.50',
|
|
||||||
maintenance: true,
|
maintenance: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -54,6 +54,9 @@ export function useNodes(instanceName: string | null | undefined) {
|
|||||||
|
|
||||||
const applyMutation = useMutation({
|
const applyMutation = useMutation({
|
||||||
mutationFn: (nodeName: string) => nodesApi.apply(instanceName!, nodeName),
|
mutationFn: (nodeName: string) => nodesApi.apply(instanceName!, nodeName),
|
||||||
|
onSuccess: () => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: ['instances', instanceName, 'nodes'] });
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const fetchTemplatesMutation = useMutation({
|
const fetchTemplatesMutation = useMutation({
|
||||||
|
|||||||
Reference in New Issue
Block a user