package oci import ( "fmt" "strings" ) // Credentials 是调用 OCI API 所需的完整凭据,私钥为 PEM 明文。 // CompartmentID 限定资源操作的目标 compartment,空表示租户根; // 只影响 compute / 网络 / 块存储等资源查询,身份与订阅类调用始终走租户根。 type Credentials struct { TenancyOCID string UserOCID string Region string Fingerprint string PrivateKey string Passphrase string CompartmentID string // Proxy 非 nil 时该租户全部 SDK 出站请求经此代理 Proxy *ProxySpec } // EffectiveCompartment 返回资源操作的目标 compartment,未指定时为租户根。 func (c Credentials) EffectiveCompartment() *string { if c.CompartmentID != "" { id := c.CompartmentID return &id } id := c.TenancyOCID return &id } // Validate 检查凭据必填字段。 func (c Credentials) Validate() error { switch { case c.TenancyOCID == "": return fmt.Errorf("credentials: tenancy is empty") case c.UserOCID == "": return fmt.Errorf("credentials: user is empty") case c.Region == "": return fmt.Errorf("credentials: region is empty") case c.Fingerprint == "": return fmt.Errorf("credentials: fingerprint is empty") case !strings.Contains(c.PrivateKey, "PRIVATE KEY"): return fmt.Errorf("credentials: private key is not a PEM") } return nil } // ParseConfigINI 解析 OCI 标准 config(ini)文本的 [DEFAULT] 段。 // key_file 只在本机指向文件,导入场景私钥内容必须单独提供,因此忽略该行。 func ParseConfigINI(text string) (Credentials, error) { var cred Credentials section := "DEFAULT" for _, line := range strings.Split(text, "\n") { line = strings.TrimSpace(line) if line == "" || strings.HasPrefix(line, "#") || strings.HasPrefix(line, ";") { continue } if strings.HasPrefix(line, "[") && strings.HasSuffix(line, "]") { section = strings.TrimSpace(line[1 : len(line)-1]) continue } if !strings.EqualFold(section, "DEFAULT") { continue } applyConfigLine(&cred, line) } if cred.TenancyOCID == "" && cred.UserOCID == "" { return cred, fmt.Errorf("parse oci config: no recognizable fields") } return cred, nil } func applyConfigLine(cred *Credentials, line string) { key, value, ok := strings.Cut(line, "=") if !ok { return } // OCID、指纹、region 值里不含 #,可安全去掉行尾注释 if i := strings.Index(value, "#"); i >= 0 { value = value[:i] } key = strings.TrimSpace(strings.ToLower(key)) value = strings.TrimSpace(value) switch key { case "user": cred.UserOCID = value case "tenancy": cred.TenancyOCID = value case "fingerprint": cred.Fingerprint = value case "region": cred.Region = value case "pass_phrase": cred.Passphrase = value } }