新增对象存储/账单/保留IP模块,删桶并发提速与成本增强
CI / test (push) Successful in 33s

This commit is contained in:
2026-07-21 12:11:05 +08:00
parent 9cfde8b702
commit f40f2a20e8
44 changed files with 7788 additions and 54 deletions
+62 -8
View File
@@ -3,7 +3,9 @@ package oci
import (
"context"
"fmt"
"time"
"github.com/oracle/oci-go-sdk/v65/common"
"github.com/oracle/oci-go-sdk/v65/core"
)
@@ -62,7 +64,7 @@ func lookupPublicIP(ctx context.Context, vn core.VirtualNetworkClient, privateIP
}
// ChangeInstancePublicIP 实现 Client:为实例主 VNIC 主私有 IP 更换临时公网 IP。
// 删除旧的临时公网 IP 再分配新的;若旧地址是保留 IP(RESERVED),拒绝操作
// 旧临时 IP 删除、旧保留 IP 自动解绑(资源保留在账户),随后分配新的临时 IP
func (c *RealClient) ChangeInstancePublicIP(ctx context.Context, cred Credentials, region, instanceID string) (string, error) {
vn, err := c.vcnClient(cred, region)
if err != nil {
@@ -72,13 +74,26 @@ func (c *RealClient) ChangeInstancePublicIP(ctx context.Context, cred Credential
if err != nil {
return "", err
}
if existing := lookupPublicIP(ctx, vn, priv.Id); existing != nil {
if existing.Lifetime == core.PublicIpLifetimeReserved {
return "", fmt.Errorf("change public ip: private ip has a reserved public ip, release it manually")
}
if _, err := vn.DeletePublicIp(ctx, core.DeletePublicIpRequest{PublicIpId: existing.Id}); err != nil {
return "", fmt.Errorf("delete old public ip: %w", err)
}
return replaceEphemeralPublicIP(ctx, vn, cred, priv)
}
// ChangeVnicPublicIP 实现 Client:为指定 VNIC 的主私有 IP 更换临时公网 IP(次要网卡场景)。
func (c *RealClient) ChangeVnicPublicIP(ctx context.Context, cred Credentials, region, vnicID string) (string, error) {
vn, err := c.vcnClient(cred, region)
if err != nil {
return "", err
}
priv, err := vnicPrimaryPrivateIP(ctx, vn, vnicID)
if err != nil {
return "", err
}
return replaceEphemeralPublicIP(ctx, vn, cred, priv)
}
// replaceEphemeralPublicIP 释放私有 IP 上现有公网 IP(临时删除、保留解绑)并分配新临时 IP。
func replaceEphemeralPublicIP(ctx context.Context, vn core.VirtualNetworkClient, cred Credentials, priv core.PrivateIp) (string, error) {
if err := detachExistingPublicIP(ctx, vn, priv.Id); err != nil {
return "", err
}
// OCI 要求临时公网 IP 与其私有 IP 同 compartment,故不能用生效 compartment
resp, err := vn.CreatePublicIp(ctx, core.CreatePublicIpRequest{
@@ -94,6 +109,45 @@ func (c *RealClient) ChangeInstancePublicIP(ctx context.Context, cred Credential
return deref(resp.IpAddress), nil
}
// detachExistingPublicIP 释放私有 IP 上已绑定的公网 IP:
// 临时 IP 直接删除;保留 IP 仅解绑(回到未分配状态,资源不删除)。
func detachExistingPublicIP(ctx context.Context, vn core.VirtualNetworkClient, privateIPID *string) error {
existing := lookupPublicIP(ctx, vn, privateIPID)
if existing == nil {
return nil
}
if existing.Lifetime != core.PublicIpLifetimeReserved {
if _, err := vn.DeletePublicIp(ctx, core.DeletePublicIpRequest{PublicIpId: existing.Id}); err != nil {
return fmt.Errorf("delete old public ip: %w", err)
}
return nil
}
_, err := vn.UpdatePublicIp(ctx, core.UpdatePublicIpRequest{
PublicIpId: existing.Id,
UpdatePublicIpDetails: core.UpdatePublicIpDetails{PrivateIpId: common.String("")},
})
if err != nil {
return fmt.Errorf("unassign reserved public ip: %w", err)
}
waitPublicIPDetached(ctx, vn, privateIPID)
return nil
}
// waitPublicIPDetached 短轮询等私有 IP 上的旧绑定释放;保留 IP 解绑为异步操作,
// 立即创建新临时 IP 可能撞上未释放的旧绑定。超时不报错,交由后续创建操作反馈。
func waitPublicIPDetached(ctx context.Context, vn core.VirtualNetworkClient, privateIPID *string) {
for i := 0; i < 10; i++ {
if lookupPublicIP(ctx, vn, privateIPID) == nil {
return
}
select {
case <-ctx.Done():
return
case <-time.After(500 * time.Millisecond):
}
}
}
// primaryVnic 返回实例的主 VNIC。
func (c *RealClient) primaryVnic(ctx context.Context, cred Credentials, region, instanceID string) (core.Vnic, error) {
vnics, _, err := c.instanceVnics(ctx, cred, region, instanceID)