初始提交:OCI 面板后端(含 GenAI 网关一期)
This commit is contained in:
@@ -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 解引用 *float32,nil 时返回零值。
|
||||
func deref32(p *float32) float32 {
|
||||
if p == nil {
|
||||
return 0
|
||||
}
|
||||
return *p
|
||||
}
|
||||
Reference in New Issue
Block a user