package api import ( "net/http" "github.com/gin-gonic/gin" "oci-portal/internal/oci" ) // ---- 实例 IP ---- // @Summary ---- 实例 IP ---- // @Tags 计算 // @Param id path int true "配置 ID" // @Param instanceId path string true "instanceId" // @Param body body object true "请求体(见接口说明)" // @Success 200 {object} publicIpResponse // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/instances/{instanceId}/change-public-ip [post] func (h *ociConfigHandler) changePublicIP(c *gin.Context) { id, ok := pathID(c) if !ok { return } var req struct { Region string `json:"region"` } _ = c.ShouldBindJSON(&req) ip, err := h.svc.ChangeInstancePublicIP(c.Request.Context(), id, req.Region, c.Param("instanceId")) if err != nil { respondError(c, err) return } c.JSON(http.StatusOK, gin.H{"publicIp": ip}) } // @Summary 实例添加 IPv6 地址 // @Tags 计算 // @Param id path int true "配置 ID" // @Param instanceId path string true "instanceId" // @Param body body object true "请求体(见接口说明)" // @Success 201 {object} ipv6AddressResponse // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/instances/{instanceId}/ipv6-addresses [post] func (h *ociConfigHandler) addInstanceIpv6(c *gin.Context) { id, ok := pathID(c) if !ok { return } var req struct { Region string `json:"region"` Address string `json:"address"` } _ = c.ShouldBindJSON(&req) address, err := h.svc.AddInstanceIpv6(c.Request.Context(), id, req.Region, c.Param("instanceId"), req.Address) if err != nil { respondError(c, err) return } c.JSON(http.StatusCreated, gin.H{"ipv6Address": address}) } // @Summary 移除实例 IPv6 地址 // @Tags 计算 // @Param id path int true "配置 ID" // @Param instanceId path string true "instanceId" // @Success 204 "无内容" // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/instances/{instanceId}/ipv6-addresses [delete] func (h *ociConfigHandler) deleteInstanceIpv6(c *gin.Context) { id, ok := pathID(c) if !ok { return } err := h.svc.DeleteInstanceIpv6(c.Request.Context(), id, c.Query("region"), c.Param("instanceId"), c.Query("address")) if err != nil { respondError(c, err) return } c.Status(http.StatusNoContent) } // ---- VNIC 管理 ---- type attachVnicRequest struct { Region string `json:"region"` oci.AttachVnicInput } // @Summary 实例 VNIC 列表 // @Tags 计算 // @Param id path int true "配置 ID" // @Param instanceId path string true "instanceId" // @Success 200 {array} oci.Vnic // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/instances/{instanceId}/vnics [get] func (h *ociConfigHandler) listInstanceVnics(c *gin.Context) { id, ok := pathID(c) if !ok { return } vnics, err := h.svc.InstanceVnics(c.Request.Context(), id, c.Query("region"), c.Param("instanceId")) if err != nil { respondError(c, err) return } c.JSON(http.StatusOK, vnics) } // @Summary 附加 VNIC // @Tags 计算 // @Param id path int true "配置 ID" // @Param instanceId path string true "instanceId" // @Param body body attachVnicRequest true "请求体" // @Success 201 {object} oci.Vnic // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/instances/{instanceId}/vnics [post] func (h *ociConfigHandler) attachVnic(c *gin.Context) { id, ok := pathID(c) if !ok { return } var req attachVnicRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } vnic, err := h.svc.AttachVnic(c.Request.Context(), id, req.Region, c.Param("instanceId"), req.AttachVnicInput) if err != nil { respondError(c, err) return } c.JSON(http.StatusCreated, vnic) } // @Summary 分离 VNIC // @Tags 计算 // @Param id path int true "配置 ID" // @Param attachmentId path string true "attachmentId" // @Success 204 "无内容" // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/vnic-attachments/{attachmentId} [delete] func (h *ociConfigHandler) detachVnic(c *gin.Context) { id, ok := pathID(c) if !ok { return } if err := h.svc.DetachVnic(c.Request.Context(), id, c.Query("region"), c.Param("attachmentId")); err != nil { respondError(c, err) return } c.Status(http.StatusNoContent) } // addVnicIpv6 为指定 VNIC 添加 IPv6;body.address 留空自动分配。 // // @Summary 为指定 VNIC 添加 IPv6 // @Tags 计算 // @Param id path int true "配置 ID" // @Param vnicId path string true "vnicId" // @Param body body object true "请求体(见接口说明)" // @Success 201 {object} addressResponse // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/vnics/{vnicId}/ipv6-addresses [post] func (h *ociConfigHandler) addVnicIpv6(c *gin.Context) { id, ok := pathID(c) if !ok { return } var req struct { Region string `json:"region"` Address string `json:"address"` } if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } addr, err := h.svc.AddVnicIpv6(c.Request.Context(), id, req.Region, c.Param("vnicId"), req.Address) if err != nil { respondError(c, err) return } c.JSON(http.StatusCreated, gin.H{"address": addr}) } // ---- 引导卷挂载 ---- type attachBootVolumeRequest struct { Region string `json:"region"` BootVolumeID string `json:"bootVolumeId" binding:"required"` } // @Summary 引导卷附件列表 // @Tags 存储 // @Param id path int true "配置 ID" // @Param instanceId path string true "instanceId" // @Success 200 {array} oci.BootVolumeAttachment // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/instances/{instanceId}/boot-volume-attachments [get] func (h *ociConfigHandler) listBootVolumeAttachments(c *gin.Context) { id, ok := pathID(c) if !ok { return } atts, err := h.svc.BootVolumeAttachments(c.Request.Context(), id, c.Query("region"), c.Param("instanceId")) if err != nil { respondError(c, err) return } c.JSON(http.StatusOK, atts) } // @Summary 附加引导卷 // @Tags 存储 // @Param id path int true "配置 ID" // @Param instanceId path string true "instanceId" // @Param body body attachBootVolumeRequest true "请求体" // @Success 201 {object} oci.BootVolumeAttachment // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/instances/{instanceId}/boot-volume-attachments [post] func (h *ociConfigHandler) attachBootVolume(c *gin.Context) { id, ok := pathID(c) if !ok { return } var req attachBootVolumeRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } att, err := h.svc.AttachBootVolume(c.Request.Context(), id, req.Region, c.Param("instanceId"), req.BootVolumeID) if err != nil { respondError(c, err) return } c.JSON(http.StatusCreated, att) } // @Summary 更换实例引导卷 // @Tags 存储 // @Param id path int true "配置 ID" // @Param instanceId path string true "instanceId" // @Param body body attachBootVolumeRequest true "请求体" // @Success 200 {object} oci.BootVolumeAttachment // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/instances/{instanceId}/replace-boot-volume [post] func (h *ociConfigHandler) replaceBootVolume(c *gin.Context) { id, ok := pathID(c) if !ok { return } var req attachBootVolumeRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } att, err := h.svc.ReplaceBootVolume(c.Request.Context(), id, req.Region, c.Param("instanceId"), req.BootVolumeID) if err != nil { respondError(c, err) return } c.JSON(http.StatusOK, att) } // @Summary 分离引导卷 // @Tags 存储 // @Param id path int true "配置 ID" // @Param attachmentId path string true "attachmentId" // @Success 204 "无内容" // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/boot-volume-attachments/{attachmentId} [delete] func (h *ociConfigHandler) detachBootVolume(c *gin.Context) { id, ok := pathID(c) if !ok { return } if err := h.svc.DetachBootVolume(c.Request.Context(), id, c.Query("region"), c.Param("attachmentId")); err != nil { respondError(c, err) return } c.Status(http.StatusNoContent) } // ---- 块卷挂载 ---- type attachVolumeRequest struct { Region string `json:"region"` VolumeID string `json:"volumeId" binding:"required"` ReadOnly bool `json:"readOnly"` } // @Summary 块存储卷列表 // @Tags 存储 // @Param id path int true "配置 ID" // @Success 200 {array} oci.BlockVolume // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/volumes [get] func (h *ociConfigHandler) listBlockVolumes(c *gin.Context) { id, ok := pathID(c) if !ok { return } volumes, err := h.svc.BlockVolumes(c.Request.Context(), id, c.Query("region"), c.Query("availabilityDomain"), c.Query("compartmentId")) if err != nil { respondError(c, err) return } c.JSON(http.StatusOK, volumes) } // @Summary 卷附件列表 // @Tags 存储 // @Param id path int true "配置 ID" // @Param instanceId path string true "instanceId" // @Success 200 {array} oci.VolumeAttachment // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/instances/{instanceId}/volume-attachments [get] func (h *ociConfigHandler) listVolumeAttachments(c *gin.Context) { id, ok := pathID(c) if !ok { return } atts, err := h.svc.VolumeAttachments(c.Request.Context(), id, c.Query("region"), c.Param("instanceId")) if err != nil { respondError(c, err) return } c.JSON(http.StatusOK, atts) } // @Summary 附加块存储卷 // @Tags 存储 // @Param id path int true "配置 ID" // @Param instanceId path string true "instanceId" // @Param body body attachVolumeRequest true "请求体" // @Success 201 {object} oci.VolumeAttachment // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/instances/{instanceId}/volume-attachments [post] func (h *ociConfigHandler) attachVolume(c *gin.Context) { id, ok := pathID(c) if !ok { return } var req attachVolumeRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } att, err := h.svc.AttachVolume(c.Request.Context(), id, req.Region, c.Param("instanceId"), req.VolumeID, req.ReadOnly) if err != nil { respondError(c, err) return } c.JSON(http.StatusCreated, att) } // @Summary 分离块存储卷 // @Tags 存储 // @Param id path int true "配置 ID" // @Param attachmentId path string true "attachmentId" // @Success 204 "无内容" // @Security BearerAuth // @Router /api/v1/oci-configs/{id}/volume-attachments/{attachmentId} [delete] func (h *ociConfigHandler) detachVolume(c *gin.Context) { id, ok := pathID(c) if !ok { return } if err := h.svc.DetachVolume(c.Request.Context(), id, c.Query("region"), c.Param("attachmentId")); err != nil { respondError(c, err) return } c.Status(http.StatusNoContent) }