初始提交:OCI 面板后端(含 GenAI 网关一期)

This commit is contained in:
Wang Defa
2026-07-09 15:31:04 +08:00
commit b9a3e97e84
168 changed files with 31794 additions and 0 deletions
+115
View File
@@ -0,0 +1,115 @@
package oci
import (
"context"
"fmt"
"time"
"github.com/oracle/oci-go-sdk/v65/common"
"github.com/oracle/oci-go-sdk/v65/core"
)
// shapeCacheTTL 是 shape 清单缓存时长:区域提供的 shape 极少变化。
const shapeCacheTTL = 6 * time.Hour
// ComputeShape 是租户在目标区域实际可用的一种实例规格。
// Flex 规格带 Ocpus/Memory 的可选范围;固定规格带其固定值。
type ComputeShape struct {
Name string `json:"name"`
BillingType string `json:"billingType"` // ALWAYS_FREE / LIMITED_FREE / PAID
IsFlexible bool `json:"isFlexible"`
Ocpus float32 `json:"ocpus,omitempty"`
MemoryInGBs float32 `json:"memoryInGBs,omitempty"`
OcpusMin float32 `json:"ocpusMin,omitempty"`
OcpusMax float32 `json:"ocpusMax,omitempty"`
MemoryMinGBs float32 `json:"memoryMinGBs,omitempty"`
MemoryMaxGBs float32 `json:"memoryMaxGBs,omitempty"`
Gpus int `json:"gpus,omitempty"`
ProcessorDescription string `json:"processorDescription,omitempty"`
}
// shapeCacheEntry 是一份 shape 清单的缓存条目。
type shapeCacheEntry struct {
expires time.Time
shapes []ComputeShape
}
// ListShapes 实现 Client:列出租户在目标区域可用的实例规格(带 TTL 缓存)。
// availabilityDomain 为空时返回区域级去重清单。
func (c *RealClient) ListShapes(ctx context.Context, cred Credentials, region, availabilityDomain string) ([]ComputeShape, error) {
key := cred.TenancyOCID + "|" + region + "|" + availabilityDomain
if v, ok := c.shapes.Load(key); ok {
if e := v.(shapeCacheEntry); time.Now().Before(e.expires) {
return e.shapes, nil
}
}
shapes, err := c.fetchShapes(ctx, cred, region, availabilityDomain)
if err != nil {
return nil, err
}
c.shapes.Store(key, shapeCacheEntry{expires: time.Now().Add(shapeCacheTTL), shapes: shapes})
return shapes, nil
}
// fetchShapes 分页拉取 shape 清单并按名称去重(不带 AD 时 OCI 每个可用域各返回一份)。
func (c *RealClient) fetchShapes(ctx context.Context, cred Credentials, region, availabilityDomain string) ([]ComputeShape, error) {
cc, err := c.computeClient(cred, region)
if err != nil {
return nil, err
}
shapes := []ComputeShape{}
seen := map[string]bool{}
var page *string
for {
req := core.ListShapesRequest{
CompartmentId: cred.EffectiveCompartment(),
Limit: common.Int(500),
Page: page,
}
if availabilityDomain != "" {
req.AvailabilityDomain = &availabilityDomain
}
resp, err := cc.ListShapes(ctx, req)
if err != nil {
return nil, fmt.Errorf("list shapes: %w", err)
}
for _, item := range resp.Items {
if name := deref(item.Shape); !seen[name] {
seen[name] = true
shapes = append(shapes, toComputeShape(item))
}
}
if resp.OpcNextPage == nil {
return shapes, nil
}
page = resp.OpcNextPage
}
}
func toComputeShape(s core.Shape) ComputeShape {
out := ComputeShape{
Name: deref(s.Shape),
BillingType: string(s.BillingType),
IsFlexible: s.OcpuOptions != nil,
ProcessorDescription: deref(s.ProcessorDescription),
}
out.Ocpus, out.MemoryInGBs = deref32(s.Ocpus), deref32(s.MemoryInGBs)
if s.Gpus != nil {
out.Gpus = *s.Gpus
}
if o := s.OcpuOptions; o != nil {
out.OcpusMin, out.OcpusMax = deref32(o.Min), deref32(o.Max)
}
if m := s.MemoryOptions; m != nil {
out.MemoryMinGBs, out.MemoryMaxGBs = deref32(m.MinInGBs), deref32(m.MaxInGBs)
}
return out
}
// deref32 解引用 *float32nil 时返回零值。
func deref32(p *float32) float32 {
if p == nil {
return 0
}
return *p
}