Skip to content

Commit 8c40f21

Browse files
committed
fix: subnet 여러개일경우 핸들
1 parent de640fd commit 8c40f21

3 files changed

Lines changed: 245 additions & 152 deletions

File tree

src/pages/ProjectEditorPage.tsx

Lines changed: 139 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -188,110 +188,117 @@ function ProjectEditorPage() {
188188
forcePosition
189189
);
190190

191-
// 스태킹 가능한 대상 찾기
192-
const potentialTargets = allBlocks
193-
.filter((block) => block.id !== newBlock.id)
194-
.filter((block) => canStack(newBlock.type, block.type))
195-
.filter((block) => validateStacking(newBlock, block));
196-
197-
if (potentialTargets.length > 0) {
198-
// Compute 인스턴스의 경우 물리적으로 가까운 대상과만 스태킹 관계 생성
199-
const isComputeInstance = newBlock.type.includes('ec2') || newBlock.type.includes('compute-engine') || newBlock.type.includes('virtual-machine');
200-
if (isComputeInstance) {
201-
console.log(
202-
"🔗 [NewStacking] EC2 다중 스태킹 처리:",
203-
potentialTargets.map((t) => t.type)
204-
);
191+
const isComputeInstance = newBlock.type.includes('ec2') || newBlock.type.includes('compute-engine') || newBlock.type.includes('virtual-machine');
205192

206-
// 거리 기반으로 필터링하여 정말 가까운 대상만 선택
207-
const closeTargets = potentialTargets.filter((target) => {
208-
const distance = Math.sqrt(
209-
Math.pow(newBlock.position.x - target.position.x, 2) +
210-
Math.pow(newBlock.position.z - target.position.z, 2)
211-
);
193+
if (isComputeInstance) {
194+
// ===== EC2/Compute 전용 로직: 겹침 면적 기반 =====
195+
console.log("🔗 [NewStacking] Compute 인스턴스 스태킹 처리");
196+
console.log("📍 [NewStacking] EC2 현재 위치:", {
197+
x: newBlock.position.x.toFixed(2),
198+
y: newBlock.position.y.toFixed(2),
199+
z: newBlock.position.z.toFixed(2)
200+
});
212201

213-
// 부트볼륨 연결(Compute-Volume/Disk)은 매우 가까워야 함 (거리 1.5 이하)
214-
const isVolumeDisk = target.type.includes('volume') || target.type.includes('ebs') || target.type.includes('disk');
215-
if (isVolumeDisk) {
216-
const isVeryClose = distance <= 1.5;
217-
console.log("🔍 [NewStacking] 부트볼륨 거리 검사:", {
218-
target: target.type,
219-
distance: distance.toFixed(2),
220-
isVeryClose,
221-
});
222-
return isVeryClose;
223-
}
202+
// 1단계: 타입별로 분류
203+
const volumes: DroppedBlock[] = [];
204+
const subnets: DroppedBlock[] = [];
224205

225-
// Subnet 연결은 더 관대하게 (거리 5.0 이하)
226-
if (target.type.includes('subnet')) {
227-
const isClose = distance <= 5.0;
228-
console.log("🔍 [NewStacking] Subnet 거리 검사:", {
229-
distance: distance.toFixed(2),
230-
isClose,
231-
});
232-
return isClose;
233-
}
206+
allBlocks.forEach(block => {
207+
if (block.id === newBlock.id) return;
208+
if (!canStack(newBlock.type, block.type)) return;
234209

235-
return false;
236-
});
210+
const isVolumeDisk = block.type.includes('volume') || block.type.includes('ebs') || block.type.includes('disk');
211+
const isSubnet = block.type.includes('subnet');
237212

238-
console.log(
239-
"🔗 [NewStacking] 거리 필터링 후 대상:",
240-
closeTargets.map((t) => t.type)
241-
);
213+
if (isVolumeDisk) volumes.push(block);
214+
if (isSubnet) subnets.push(block);
215+
});
216+
217+
console.log("[NewStacking] 타입별 분류:", {
218+
volumeCount: volumes.length,
219+
subnetCount: subnets.length,
220+
});
221+
222+
// 2단계: Volume/EBS 검증 (validateStacking 사용)
223+
const validVolumes = volumes.filter(vol => {
224+
const isValid = validateStacking(newBlock, vol);
225+
console.log(`[NewStacking] Volume 검증: ${vol.type.substring(0, 10)} - ${isValid ? '✅' : '❌'}`);
226+
return isValid;
227+
});
242228

243-
// 가까운 대상과만 스태킹 관계 생성
244-
closeTargets.forEach((target) => {
245-
createStackingRelation(newBlock.id, target.id, allBlocks);
246-
console.log("🔗 [NewStacking] EC2 스태킹 관계 생성:", target.type);
229+
// 3단계: Subnet 검증 - 겹침 면적 기반 선택
230+
const subnetOverlapData = subnets.map(subnet => {
231+
const ec2SizeX = newBlock.size?.[0] || 1;
232+
const ec2SizeZ = newBlock.size?.[2] || 1;
233+
const subnetSizeX = subnet.size?.[0] || 3;
234+
const subnetSizeZ = subnet.size?.[2] || 3;
235+
236+
// X축 겹침 계산
237+
const ec2Left = newBlock.position.x - ec2SizeX / 2;
238+
const ec2Right = newBlock.position.x + ec2SizeX / 2;
239+
const subnetLeft = subnet.position.x - subnetSizeX / 2;
240+
const subnetRight = subnet.position.x + subnetSizeX / 2;
241+
242+
const xOverlapStart = Math.max(ec2Left, subnetLeft);
243+
const xOverlapEnd = Math.min(ec2Right, subnetRight);
244+
const xOverlap = Math.max(0, xOverlapEnd - xOverlapStart);
245+
246+
// Z축 겹침 계산
247+
const ec2Front = newBlock.position.z - ec2SizeZ / 2;
248+
const ec2Back = newBlock.position.z + ec2SizeZ / 2;
249+
const subnetFront = subnet.position.z - subnetSizeZ / 2;
250+
const subnetBack = subnet.position.z + subnetSizeZ / 2;
251+
252+
const zOverlapStart = Math.max(ec2Front, subnetFront);
253+
const zOverlapEnd = Math.min(ec2Back, subnetBack);
254+
const zOverlap = Math.max(0, zOverlapEnd - zOverlapStart);
255+
256+
// 겹침 면적
257+
const overlapArea = xOverlap * zOverlap;
258+
const ec2Area = ec2SizeX * ec2SizeZ;
259+
const overlapRatio = ec2Area > 0 ? overlapArea / ec2Area : 0;
260+
261+
// Y축 검증
262+
const yValid = validateStacking(newBlock, subnet);
263+
264+
console.log(`🎯 [NewStacking] Subnet 겹침 분석: ${subnet.type}`, {
265+
subnetId: subnet.id.substring(0, 8),
266+
ec2Pos: `(${newBlock.position.x.toFixed(1)}, ${newBlock.position.z.toFixed(1)})`,
267+
subnetPos: `(${subnet.position.x.toFixed(1)}, ${subnet.position.z.toFixed(1)})`,
268+
xOverlap: xOverlap.toFixed(2),
269+
zOverlap: zOverlap.toFixed(2),
270+
overlapRatio: (overlapRatio * 100).toFixed(1) + '%',
271+
yValid
247272
});
248273

249-
// 위치 조정은 주요 대상(Subnet 우선)으로
250-
const primaryTarget = selectStackingTargetByPriority(
251-
newBlock,
252-
closeTargets
253-
);
254-
if (forcePosition && primaryTarget) {
255-
const stackedPosition = calculateStackedPosition(
256-
newBlock,
257-
primaryTarget
258-
);
259-
moveBlock(newBlock.id, stackedPosition);
260-
console.log(
261-
"📍 [NewStacking] EC2 위치 조정됨 (주요 대상:",
262-
primaryTarget.type,
263-
")"
264-
);
265-
} else {
266-
console.log("🎯 [NewStacking] EC2 사용자 위치 유지");
267-
}
268-
} else {
269-
// 다른 블록 타입은 기존 방식 (단일 대상)
270-
const targetBlock = selectStackingTargetByPriority(
271-
newBlock,
272-
potentialTargets
273-
);
274+
return { subnet, overlapRatio, yValid };
275+
});
274276

275-
if (targetBlock) {
276-
console.log("🔗 [NewStacking] 스태킹 대상 발견:", targetBlock.type);
277+
// 겹침 면적이 30% 이상이고 Y축 검증 통과한 Subnet 필터링
278+
const validSubnets = subnetOverlapData
279+
.filter(data => data.overlapRatio >= 0.3 && data.yValid)
280+
.sort((a, b) => b.overlapRatio - a.overlapRatio);
277281

278-
// 스태킹 관계 생성
279-
createStackingRelation(newBlock.id, targetBlock.id, allBlocks);
282+
console.log("✅ [NewStacking] 최종 스태킹 타겟:", {
283+
volumes: validVolumes.map(v => `${v.type}(${v.id.substring(0, 8)})`),
284+
subnets: validSubnets.map(s => `${s.subnet.type}(${s.subnet.id.substring(0, 8)}) - ${(s.overlapRatio * 100).toFixed(1)}%`)
285+
});
280286

281-
// 위치 조정 (옵션)
282-
if (forcePosition) {
283-
const stackedPosition = calculateStackedPosition(
284-
newBlock,
285-
targetBlock
286-
);
287-
moveBlock(newBlock.id, stackedPosition);
288-
console.log("📍 [NewStacking] 위치 강제 조정됨");
289-
} else {
290-
console.log("🎯 [NewStacking] 사용자 위치 유지");
291-
}
292-
}
287+
// 4단계: 스태킹 관계 생성
288+
validVolumes.forEach(vol => {
289+
createStackingRelation(newBlock.id, vol.id, allBlocks);
290+
console.log("🔗 [NewStacking] 부트볼륨 연결:", vol.type);
291+
});
292+
293+
if (validSubnets.length > 0) {
294+
const bestSubnet = validSubnets[0].subnet;
295+
createStackingRelation(newBlock.id, bestSubnet.id, allBlocks);
296+
console.log("🔗 [NewStacking] Subnet 연결:", bestSubnet.type, `(${(validSubnets[0].overlapRatio * 100).toFixed(1)}%)`);
293297
}
294298

299+
// 위치 조정 없음 (사용자 드래그 위치 유지)
300+
console.log("🎯 [NewStacking] EC2 사용자 위치 유지");
301+
295302
// 즉시 연결 업데이트
296303
const derivedConnections = deriveConnectionsFromStacking(allBlocks);
297304
const nonStackingConnections = connections.filter(
@@ -306,7 +313,47 @@ function ProjectEditorPage() {
306313
"개"
307314
);
308315
} else {
309-
console.log("ℹ️ [NewStacking] 스태킹 대상 없음");
316+
// ===== 일반 블록 로직 =====
317+
const potentialTargets = allBlocks
318+
.filter((block) => block.id !== newBlock.id)
319+
.filter((block) => canStack(newBlock.type, block.type))
320+
.filter((block) => validateStacking(newBlock, block));
321+
322+
if (potentialTargets.length > 0) {
323+
const targetBlock = selectStackingTargetByPriority(
324+
newBlock,
325+
potentialTargets
326+
);
327+
328+
if (targetBlock) {
329+
console.log("🔗 [NewStacking] 스태킹 대상 발견:", targetBlock.type);
330+
createStackingRelation(newBlock.id, targetBlock.id, allBlocks);
331+
332+
if (forcePosition) {
333+
const stackedPosition = calculateStackedPosition(newBlock, targetBlock);
334+
moveBlock(newBlock.id, stackedPosition);
335+
console.log("📍 [NewStacking] 위치 강제 조정됨");
336+
} else {
337+
console.log("🎯 [NewStacking] 사용자 위치 유지");
338+
}
339+
}
340+
341+
// 즉시 연결 업데이트
342+
const derivedConnections = deriveConnectionsFromStacking(allBlocks);
343+
const nonStackingConnections = connections.filter(
344+
(conn) => !conn.properties?.stackConnection
345+
);
346+
const allConnections = [...nonStackingConnections, ...derivedConnections];
347+
setConnections(allConnections);
348+
349+
console.log(
350+
"✅ [NewStacking] 스태킹 완료 + 연결 업데이트:",
351+
derivedConnections.length,
352+
"개"
353+
);
354+
} else {
355+
console.log("ℹ️ [NewStacking] 스태킹 대상 없음");
356+
}
310357
}
311358
};
312359

src/providers/aws/codeGenerator/terraformGenerator.ts

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -245,20 +245,59 @@ resource "aws_ebs_volume" "${this.sanitizeResourceName(volume.id)}" {
245245
const instanceType = ec2.properties.instanceType || "t3.micro";
246246
const ami = ec2.properties.ami || "ami-0c6e5afdd23291f73";
247247

248-
const subnetRef = subnets.length > 0 ?
249-
`aws_subnet.${this.sanitizeResourceName(subnets[0].id)}.id` :
250-
'"subnet-xxxxxx"';
248+
// EC2-Subnet 연결 찾기 (스태킹 관계)
249+
const subnetConnection = connections.find(conn =>
250+
(conn.fromBlockId === ec2.id || conn.toBlockId === ec2.id) &&
251+
conn.properties?.stackConnection === true &&
252+
subnets.some(s => s.id === conn.fromBlockId || s.id === conn.toBlockId)
253+
);
254+
255+
let subnetRef = '"subnet-xxxxxx"';
256+
if (subnetConnection) {
257+
// 연결된 Subnet ID 찾기
258+
const connectedSubnetId = subnetConnection.fromBlockId === ec2.id
259+
? subnetConnection.toBlockId
260+
: subnetConnection.fromBlockId;
261+
const connectedSubnet = subnets.find(s => s.id === connectedSubnetId);
262+
263+
if (connectedSubnet) {
264+
subnetRef = `aws_subnet.${this.sanitizeResourceName(connectedSubnet.id)}.id`;
265+
console.log(`[EC2CodeGen] EC2 ${ec2.id.substring(0, 8)} → Subnet ${connectedSubnet.id.substring(0, 8)}`);
266+
}
267+
} else if (subnets.length > 0) {
268+
// 연결이 없으면 첫 번째 Subnet 사용 (fallback)
269+
subnetRef = `aws_subnet.${this.sanitizeResourceName(subnets[0].id)}.id`;
270+
console.warn(`[EC2CodeGen] No subnet connection found for EC2 ${ec2.id.substring(0, 8)}, using first subnet`);
271+
}
251272

252273
// 부트볼륨 찾기 (스태킹된 Volume)
274+
console.log(`[EC2CodeGen] EC2 ${ec2.id.substring(0, 8)} - 부트볼륨 검색 중...`);
275+
console.log(`[EC2CodeGen] 전체 연결 수: ${connections.length}, Volume 수: ${volumes.length}`);
276+
253277
const bootVolume = volumes.find((volume) => {
254278
const volumeConnection = connections.find(conn =>
255279
(conn.fromBlockId === ec2.id && conn.toBlockId === volume.id) ||
256280
(conn.fromBlockId === volume.id && conn.toBlockId === ec2.id)
257281
);
282+
283+
if (volumeConnection) {
284+
console.log(`[EC2CodeGen] Volume ${volume.id.substring(0, 8)} 연결 발견:`, {
285+
stackConnection: volumeConnection.properties?.stackConnection,
286+
volumeType: volumeConnection.properties?.volumeType,
287+
fromTo: `${volumeConnection.fromBlockId.substring(0, 8)}${volumeConnection.toBlockId.substring(0, 8)}`
288+
});
289+
}
290+
258291
return volumeConnection?.properties?.stackConnection === true &&
259292
volumeConnection?.properties?.volumeType === 'boot';
260293
});
261294

295+
if (bootVolume) {
296+
console.log(`✅ [EC2CodeGen] 부트볼륨 찾음: ${bootVolume.id.substring(0, 8)} (${bootVolume.properties.name})`);
297+
} else {
298+
console.log(`❌ [EC2CodeGen] 부트볼륨 없음`);
299+
}
300+
262301
let code = `# EC2 Instance: ${ec2.properties.name || ec2.name}
263302
resource "aws_instance" "${this.sanitizeResourceName(ec2.id)}" {
264303
ami = "${ami}"

0 commit comments

Comments
 (0)