from __future__ import annotations from datetime import datetime from typing import Any, List, Optional from pydantic import BaseModel, ConfigDict, EmailStr, Field from .models import ( AuditAction, AuditResourceType, CredentialType, InstanceDesiredStatus, InstanceStatus, JobItemAction, JobItemResourceType, JobItemStatus, JobStatus, JobType, ) class RoleOut(BaseModel): model_config = ConfigDict(from_attributes=True) id: int name: str description: Optional[str] = None class CustomerBase(BaseModel): name: str contact_email: Optional[EmailStr] = None is_active: int = 1 quota_instances: Optional[int] = None notes: Optional[str] = None class CustomerCreate(CustomerBase): pass class CustomerUpdate(BaseModel): name: Optional[str] = None contact_email: Optional[EmailStr] = None is_active: Optional[int] = None quota_instances: Optional[int] = None notes: Optional[str] = None class CustomerOut(CustomerBase): model_config = ConfigDict(from_attributes=True) id: int created_at: datetime updated_at: datetime class UserBase(BaseModel): username: str email: Optional[EmailStr] = None role_id: int customer_id: Optional[int] = None is_active: int = 1 class UserCreate(UserBase): password: str class UserUpdate(BaseModel): email: Optional[EmailStr] = None password: Optional[str] = None role_id: Optional[int] = None customer_id: Optional[int] = None is_active: Optional[int] = None class UserOut(BaseModel): model_config = ConfigDict(from_attributes=True) id: int username: str email: Optional[EmailStr] = None role_id: int customer_id: Optional[int] = None is_active: int last_login_at: Optional[datetime] = None created_at: datetime updated_at: datetime role: Optional[RoleOut] = None customer: Optional[CustomerOut] = None class LoginRequest(BaseModel): username: str password: str class TokenResponse(BaseModel): access_token: str token_type: str = "bearer" user: UserOut class AWSCredentialBase(BaseModel): name: str account_id: str credential_type: CredentialType = CredentialType.ACCESS_KEY access_key_id: Optional[str] = None secret_access_key: Optional[str] = None role_arn: Optional[str] = None external_id: Optional[str] = None default_region: str = "ap-northeast-1" is_active: int = 1 class AWSCredentialCreate(AWSCredentialBase): pass class AWSCredentialUpdate(BaseModel): name: Optional[str] = None account_id: Optional[str] = None credential_type: Optional[CredentialType] = None access_key_id: Optional[str] = None secret_access_key: Optional[str] = None role_arn: Optional[str] = None external_id: Optional[str] = None default_region: Optional[str] = None is_active: Optional[int] = None class AWSCredentialOut(AWSCredentialBase): model_config = ConfigDict(from_attributes=True) id: int created_at: datetime updated_at: datetime class CustomerCredentialBase(BaseModel): customer_id: int credential_id: int is_allowed: int = 1 class CustomerCredentialCreate(CustomerCredentialBase): pass class CustomerCredentialOut(CustomerCredentialBase): model_config = ConfigDict(from_attributes=True) id: int created_at: datetime updated_at: datetime class InstanceFilterParams(BaseModel): customer_id: Optional[int] = None credential_id: Optional[int] = None account_id: Optional[str] = None region: Optional[str] = None status: Optional[InstanceStatus] = None keyword: Optional[str] = Field(default=None, description="Match name_tag/instance_id/ip") offset: int = 0 limit: int = 20 class InstanceCreateRequest(BaseModel): credential_id: int account_id: str region: str ami_id: str instance_type: str key_name: Optional[str] = None security_groups: List[str] = Field(default_factory=list) subnet_id: Optional[str] = None name_tag: Optional[str] = None customer_id: Optional[int] = None class InstanceOut(BaseModel): model_config = ConfigDict(from_attributes=True) id: int customer_id: int credential_id: Optional[int] credential_name: Optional[str] = None credential_label: Optional[str] = None owner_name: Optional[str] = None customer_name: Optional[str] = None account_id: str region: str az: Optional[str] = None instance_id: str name_tag: Optional[str] = None instance_type: str instance_vcpus: Optional[int] = None instance_memory_gib: Optional[float] = None instance_network_perf: Optional[str] = None ami_id: Optional[str] = None key_name: Optional[str] = None os_pretty_name: Optional[str] = None public_ip: Optional[str] = None private_ip: Optional[str] = None status: InstanceStatus desired_status: Optional[InstanceDesiredStatus] = None security_groups: Optional[List[str]] = None subnet_id: Optional[str] = None vpc_id: Optional[str] = None launched_at: Optional[datetime] = None terminated_at: Optional[datetime] = None last_sync: Optional[datetime] = None last_cloud_state: Optional[Any] = None created_at: datetime updated_at: datetime class InstanceListResponse(BaseModel): items: List[InstanceOut] total: int class InstanceSyncRequest(BaseModel): customer_id: Optional[int] = None credential_id: Optional[int] = None region: Optional[str] = None class JobCreateRequest(BaseModel): job_type: JobType payload: Optional[Any] = None class JobOut(BaseModel): model_config = ConfigDict(from_attributes=True) id: int job_uuid: str job_type: JobType status: JobStatus progress: int total_count: Optional[int] = None success_count: Optional[int] = None fail_count: Optional[int] = None skipped_count: Optional[int] = None payload: Optional[Any] = None error_message: Optional[str] = None created_by_user_id: Optional[int] = None created_for_customer: Optional[int] = None created_at: datetime started_at: Optional[datetime] = None finished_at: Optional[datetime] = None updated_at: datetime class JobListResponse(BaseModel): items: List[JobOut] total: int class JobItemOut(BaseModel): model_config = ConfigDict(from_attributes=True) id: int job_id: int resource_type: JobItemResourceType resource_id: Optional[int] = None account_id: Optional[str] = None region: Optional[str] = None instance_id: Optional[str] = None action: JobItemAction status: JobItemStatus error_message: Optional[str] = None extra: Optional[Any] = None created_at: datetime updated_at: datetime class AuditLogOut(BaseModel): model_config = ConfigDict(from_attributes=True) id: int user_id: Optional[int] = None customer_id: Optional[int] = None action: AuditAction resource_type: AuditResourceType resource_id: Optional[int] = None description: Optional[str] = None payload: Optional[Any] = None ip_address: Optional[str] = None user_agent: Optional[str] = None created_at: datetime class MenuItem(BaseModel): label: str key: str icon: Optional[str] = None path: Optional[str] = None children: List["MenuItem"] = Field(default_factory=list) MenuItem.model_rebuild()