fix: use goid to identify differnt goroutine (#22722)

Co-authored-by: Qiu Jian <qiujian@yunionyun.com>
This commit is contained in:
Jian Qiu
2025-06-19 14:50:39 +08:00
committed by GitHub
parent 93466228d5
commit be7bc9335c
40 changed files with 914 additions and 212 deletions
+3 -2
View File
@@ -50,6 +50,7 @@ require (
github.com/miekg/dns v1.1.25
github.com/minio/minio-go v6.0.14+incompatible
github.com/mitchellh/go-wordwrap v1.0.1
github.com/petermattis/goid v0.0.0-20250508124226-395b08cebbdb
github.com/pierrec/lz4/v4 v4.1.15
github.com/pkg/errors v0.9.1
github.com/pkg/sftp v1.13.6
@@ -95,12 +96,12 @@ require (
k8s.io/cri-api v0.22.17
k8s.io/klog/v2 v2.20.0
moul.io/http2curl/v2 v2.3.0
yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20250616091331-d7f1f89a7d90
yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20250618092159-24a4b21d2439
yunion.io/x/executor v0.0.0-20250518005516-5402e9e0bed0
yunion.io/x/jsonutils v1.0.1-0.20250507052344-1abcf4f443b1
yunion.io/x/log v1.0.1-0.20240305175729-7cf2d6cd5a91
yunion.io/x/ovsdb v0.0.0-20230306173834-f164f413a900
yunion.io/x/pkg v1.10.4-0.20250519013345-54017bf6c1f0
yunion.io/x/pkg v1.10.4-0.20250618071935-840c253075b0
yunion.io/x/s3cli v0.0.0-20241221171442-1c11599d28e1
yunion.io/x/sqlchemy v1.1.3-0.20250531010554-ce98f840b833
yunion.io/x/structarg v0.0.0-20231017124457-df4d5009457c
+6 -4
View File
@@ -713,6 +713,8 @@ github.com/openzipkin/zipkin-go-opentracing v0.3.4/go.mod h1:js2AbwmHW0YD9DwIw2J
github.com/oracle/oci-go-sdk v24.3.0+incompatible h1:x4mcfb4agelf1O4/1/auGlZ1lr97jXRSSN5MxTgG/zU=
github.com/oracle/oci-go-sdk v24.3.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/petermattis/goid v0.0.0-20250508124226-395b08cebbdb h1:3PrKuO92dUTMrQ9dx0YNejC6U/Si6jqKmyQ9vWjwqR4=
github.com/petermattis/goid v0.0.0-20250508124226-395b08cebbdb/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4=
github.com/philhofer/fwd v1.0.0 h1:UbZqGr5Y38ApvM/V/jEljVxwocdweyH+vmYvRPBnbqQ=
github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
@@ -1410,8 +1412,8 @@ sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20250616091331-d7f1f89a7d90 h1:Cbzs++XW+hHXLI5cufagP6hoo+L+7vXU1bZOvyqTJnE=
yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20250616091331-d7f1f89a7d90/go.mod h1:FXxAEbdNfWXX9gjME3K2nJhkydHY5EKEUZb+RLEzVwQ=
yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20250618092159-24a4b21d2439 h1:LpoTE3tGWCh7r9IcEhI82wpXgIGj+lU2skW2GWwUTM4=
yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20250618092159-24a4b21d2439/go.mod h1:FXxAEbdNfWXX9gjME3K2nJhkydHY5EKEUZb+RLEzVwQ=
yunion.io/x/executor v0.0.0-20250518005516-5402e9e0bed0 h1:msG4SiDSVU7CrXH06WuHlNEZXIooTcmNbfrIGHuIHBU=
yunion.io/x/executor v0.0.0-20250518005516-5402e9e0bed0/go.mod h1:Uxuou9WQIeJXNpy7t2fPLL0BYLvLiMvGQwY7Qc6aSws=
yunion.io/x/jsonutils v0.0.0-20190625054549-a964e1e8a051/go.mod h1:4N0/RVzsYL3kH3WE/H1BjUQdFiWu50JGCFQuuy+Z634=
@@ -1425,8 +1427,8 @@ yunion.io/x/ovsdb v0.0.0-20230306173834-f164f413a900 h1:Hu/4ERvoWaN6aiFs4h4/yvVB
yunion.io/x/ovsdb v0.0.0-20230306173834-f164f413a900/go.mod h1:0vLkNEhlmA64HViPBAnSTUMrx5QP1CLsxXmxDKQ80tc=
yunion.io/x/pkg v0.0.0-20190620104149-945c25821dbf/go.mod h1:t6rEGG2sQ4J7DhFxSZVOTjNd0YO/KlfWQyK1W4tog+E=
yunion.io/x/pkg v0.0.0-20190628082551-f4033ba2ea30/go.mod h1:t6rEGG2sQ4J7DhFxSZVOTjNd0YO/KlfWQyK1W4tog+E=
yunion.io/x/pkg v1.10.4-0.20250519013345-54017bf6c1f0 h1:iKWkBMKazSijYNhOaSh4qBuIu+PmXYhEAMNwrxaXL4Q=
yunion.io/x/pkg v1.10.4-0.20250519013345-54017bf6c1f0/go.mod h1:0Bwxqd9MA3ACi119/l02FprY/o9gHahmYC2bsSbnVpM=
yunion.io/x/pkg v1.10.4-0.20250618071935-840c253075b0 h1:diTsDq4t6jntGdAKtHZYx9eRWkLg0KyMTp0WFdueT+0=
yunion.io/x/pkg v1.10.4-0.20250618071935-840c253075b0/go.mod h1:0Bwxqd9MA3ACi119/l02FprY/o9gHahmYC2bsSbnVpM=
yunion.io/x/s3cli v0.0.0-20241221171442-1c11599d28e1 h1:1KJ3YYinydPHpDEQRXdr/T8SYcKZ5Er+m489H+PnaQ4=
yunion.io/x/s3cli v0.0.0-20241221171442-1c11599d28e1/go.mod h1:0iFKpOs1y4lbCxeOmq3Xx/0AcQoewVPwj62eRluioEo=
yunion.io/x/sqlchemy v1.1.3-0.20250531010554-ce98f840b833 h1:XTFC1naKYkciCQDLm9izpzHXfTenmmtYsTpVKrsN5hE=
+16 -12
View File
@@ -93,13 +93,13 @@ const (
var quitHandlerRegisted bool
func NewApplication(name string, connMax int, db bool) *Application {
func NewApplication(name string, connMax int, queueSize int, db bool) *Application {
app := Application{name: name,
context: ctx.CtxWithTime(),
connMax: connMax,
session: NewWorkerManager("HttpRequestWorkerManager", connMax, DEFAULT_BACKLOG, db),
readSession: NewWorkerManager("HttpGetRequestWorkerManager", connMax, DEFAULT_BACKLOG, db),
systemSession: NewWorkerManager("InternalHttpRequestWorkerManager", 1, DEFAULT_BACKLOG, false),
session: NewWorkerManager("HttpRequestWorkerManager", connMax, connMax*queueSize, db),
readSession: NewWorkerManager("HttpGetRequestWorkerManager", connMax, connMax*queueSize, db),
systemSession: NewWorkerManager("InternalHttpRequestWorkerManager", 1, queueSize, false),
roots: make(map[string]*RadixNode),
rootLock: &sync.RWMutex{},
idleTimeout: DEFAULT_IDLE_TIMEOUT,
@@ -424,7 +424,7 @@ func (app *Application) defaultHandle(w http.ResponseWriter, r *http.Request, ri
task.appParams.Body, _ = jsonutils.Parse(data)
r.Body = io.NopCloser(bytes.NewBuffer(data))
}
session.Run(
inqueue := session.Run(
task,
currentWorker,
func(err error) {
@@ -432,13 +432,17 @@ func (app *Application) defaultHandle(w http.ResponseWriter, r *http.Request, ri
task.fw.closeChannels()
},
)
runErr := task.fw.wait(task.ctx, currentWorker)
if runErr != nil {
switch je := runErr.(type) {
case *httputils.JSONClientError:
httperrors.GeneralServerError(task.ctx, w, je)
default:
httperrors.InternalServerError(task.ctx, w, "Internal server error")
if !inqueue {
httperrors.TooManyRequestsError(task.ctx, w, "Request queue is full")
} else {
runErr := task.fw.wait(task.ctx, currentWorker)
if runErr != nil {
switch je := runErr.(type) {
case *httputils.JSONClientError:
httperrors.GeneralServerError(task.ctx, w, je)
default:
httperrors.InternalServerError(task.ctx, w, "Internal server error")
}
}
}
task.fw.closeChannels()
+1 -1
View File
@@ -49,7 +49,7 @@ type ApplicationTestSuit struct {
}
func (suite *ApplicationTestSuit) SetupTest() {
suite.app = NewApplication("test", 4, false)
suite.app = NewApplication("test", 4, 10, false)
suite.app.AddHandler("GET", "/delay", func(ctx context.Context, w http.ResponseWriter, r *http.Request) {
time.Sleep(time.Second * 1)
Send(w, "delay pong")
+1 -1
View File
@@ -30,7 +30,7 @@ import (
func InitApp(options *common_options.BaseOptions, dbAccess bool) *appsrv.Application {
// cache := appsrv.NewCache(options.AuthTokenCacheSize)
log.Infof("RequestWorkerCount: %d", options.RequestWorkerCount)
app := appsrv.NewApplication(options.ApplicationID, options.RequestWorkerCount, dbAccess)
app := appsrv.NewApplication(options.ApplicationID, options.RequestWorkerCount, options.RequestWorkerQueueSize, dbAccess)
app.CORSAllowHosts(options.CorsHosts)
app.SetDefaultTimeout(time.Duration(options.DefaultProcessTimeoutSeconds) * time.Second)
// app.SetContext(appsrv.APP_CONTEXT_KEY_CACHE, cache)
+42 -40
View File
@@ -19,10 +19,12 @@ import (
"runtime/debug"
"sync"
"github.com/petermattis/goid"
"yunion.io/x/log"
)
const (
var (
debug_log = false
)
@@ -34,15 +36,15 @@ type SInMemoryLockRecord struct {
key string
lock *sync.Mutex
cond *sync.Cond
holder context.Context
holder int64
depth int
waiter *FIFO
}
func newInMemoryLockRecord(ctx context.Context) *SInMemoryLockRecord {
func newInMemoryLockRecord(ctxDummy context.Context) *SInMemoryLockRecord {
lock := &sync.Mutex{}
cond := sync.NewCond(lock)
rec := SInMemoryLockRecord{lock: lock, cond: cond, holder: ctx, depth: 0, waiter: NewFIFO()}
rec := SInMemoryLockRecord{lock: lock, cond: cond, holder: -1, depth: 0, waiter: NewFIFO()}
return &rec
}
@@ -51,24 +53,29 @@ func (rec *SInMemoryLockRecord) fatalf(fmtStr string, args ...interface{}) {
log.Fatalf(fmtStr, args...)
}
func (rec *SInMemoryLockRecord) lockContext(ctx context.Context) {
func (rec *SInMemoryLockRecord) lockContext(ctxDummy context.Context) {
rec.lock.Lock()
defer rec.lock.Unlock()
if rec.holder == nil {
rec.holder = ctx
curGoid := goid.Get()
if rec.holder < 0 {
if debug_log {
log.Debugf("lockContext: curGoid=[%d] key=[%s] create new record", curGoid, rec.key)
}
rec.holder = curGoid
rec.depth = 1
return
}
if debug_log {
log.Debugf("rec.hold=[%p] ctx=[%p] %v key=[%s]", rec.holder, ctx, rec.holder == ctx, rec.key)
log.Debugf("rec.hold=[%d] ctx=[%d] %v key=[%s]", rec.holder, curGoid, rec.holder == curGoid, rec.key)
}
if rec.holder == ctx {
if rec.holder == curGoid {
rec.depth += 1
if debug_log {
log.Infof("lockContext: same ctx, depth: %d [%p] key=[%s]", rec.depth, rec.holder, rec.key)
log.Infof("lockContext: same ctx, depth: %d holder=[%d] ctx=[%d] key=[%s]", rec.depth, rec.holder, curGoid, rec.key)
}
if rec.depth > 32 {
// XXX MUST BE BUG ???
@@ -79,57 +86,59 @@ func (rec *SInMemoryLockRecord) lockContext(ctx context.Context) {
// check
rec.waiter.Enum(func(ele interface{}) {
electx := ele.(context.Context)
if electx == ctx {
rec.fatalf("try to lock from a waiter context???? key=[%s]", rec.key)
electx := ele.(int64)
if electx == curGoid {
rec.fatalf("try to lock from a waiter context???? curGoid=[%d] waiterGoid=[%d] key=[%s]", curGoid, electx, rec.key)
}
})
rec.waiter.Push(ctx)
rec.waiter.Push(curGoid)
if debug_log {
log.Debugf("waiter size %d after push", rec.waiter.Len())
log.Debugf("Start to wait ... [%p] key=[%s]", ctx, rec.key)
log.Debugf("waiter size %d after push curGoid=[%d]", rec.waiter.Len(), curGoid)
log.Debugf("Start to wait ... holder=[%d] curGoid [%d] key=[%s]", rec.holder, curGoid, rec.key)
}
for rec.holder != nil {
for rec.holder >= 0 {
rec.cond.Wait()
}
if debug_log {
log.Debugf("End of wait ... [%p] key=[%s]", ctx, rec.key)
log.Debugf("End of wait ... holder=[%d] curGoid [%d] key=[%s]", rec.holder, curGoid, rec.key)
}
rec.waiter.Pop(ctx)
rec.waiter.Pop(curGoid)
if debug_log {
log.Debugf("waiter size %d after pop key=[%s]", rec.waiter.Len(), rec.key)
log.Debugf("waiter size %d after pop curGoid=[%d] key=[%s]", rec.waiter.Len(), curGoid, rec.key)
}
rec.holder = ctx
rec.holder = curGoid
rec.depth = 1
}
func (rec *SInMemoryLockRecord) unlockContext(ctx context.Context) (needClean bool) {
func (rec *SInMemoryLockRecord) unlockContext(ctxDummy context.Context) (needClean bool) {
rec.lock.Lock()
defer rec.lock.Unlock()
if rec.holder != ctx {
rec.fatalf("try to unlock a wait context??? key=[%s]", rec.key)
curGoid := goid.Get()
if rec.holder != curGoid {
rec.fatalf("try to unlock a wait context??? key=[%s] holder=[%d] curGoid=[%d]", rec.key, rec.holder, curGoid)
}
if debug_log {
log.Debugf("unlockContext depth %d [%p] key=[%s]", rec.depth, ctx, rec.key)
log.Debugf("unlockContext depth %d curGoid=[%d] key=[%s]", rec.depth, curGoid, rec.key)
}
rec.depth -= 1
if rec.depth <= 0 {
if debug_log {
log.Debugf("depth 0, to release lock for context [%p] key=[%s]", ctx, rec.key)
log.Debugf("depth 0, to release lock for context curGoid=[%d] key=[%s]", curGoid, rec.key)
}
rec.holder = nil
rec.holder = -1
if rec.waiter.Len() == 0 {
return true
}
@@ -154,11 +163,11 @@ func NewInMemoryLockManager() ILockManager {
return &lockMan
}
func (lockman *SInMemoryLockManager) getRecordWithLock(ctx context.Context, key string) *SInMemoryLockRecord {
func (lockman *SInMemoryLockManager) getRecordWithLock(ctx context.Context, key string, new bool) *SInMemoryLockRecord {
lockman.tableLock.Lock()
defer lockman.tableLock.Unlock()
return lockman.getRecord(ctx, key, true)
return lockman.getRecord(ctx, key, new)
}
func (lockman *SInMemoryLockManager) getRecord(ctx context.Context, key string, new bool) *SInMemoryLockRecord {
@@ -175,23 +184,16 @@ func (lockman *SInMemoryLockManager) getRecord(ctx context.Context, key string,
}
func (lockman *SInMemoryLockManager) LockKey(ctx context.Context, key string) {
record := lockman.getRecordWithLock(ctx, key)
record := lockman.getRecordWithLock(ctx, key, true)
record.lockContext(ctx)
}
func (lockman *SInMemoryLockManager) UnlockKey(ctx context.Context, key string) {
lockman.tableLock.Lock()
defer lockman.tableLock.Unlock()
record := lockman.getRecord(ctx, key, false)
record := lockman.getRecordWithLock(ctx, key, false)
if record == nil {
log.Errorf("BUG: unlock an non-existent lock\n%s", debug.Stack())
log.Errorf("BUG: unlock an non-existent lock ctx: %p key: %s\n%s", ctx, key, debug.Stack())
return
}
needClean := record.unlockContext(ctx)
if needClean {
delete(lockman.lockTable, key)
}
record.unlockContext(ctx)
}
@@ -16,9 +16,17 @@ package lockman
import (
"context"
"fmt"
"math/rand"
"os"
"sync"
"testing"
"time"
"github.com/petermattis/goid"
"yunion.io/x/log"
"yunion.io/x/pkg/utils"
)
func TestInMemoryLockManager(t *testing.T) {
@@ -56,3 +64,74 @@ func TestRunManu(t *testing.T) {
}
t.Logf("complete")
}
type app struct {
ctx context.Context
key string
lockman ILockManager
}
func (app *app) run() {
app.lockman.LockKey(app.ctx, app.key)
defer app.lockman.UnlockKey(app.ctx, app.key)
fmt.Printf("run for goid: %d key %s\n", goid.Get(), app.key)
}
type emptyKey struct{}
func TestRunManu3(t *testing.T) {
for i := 0; i < 100; i++ {
TestRunManu2(t)
}
}
func TestRunManu2(t *testing.T) {
rand.Seed(100)
lockman := NewInMemoryLockManager()
debug_log = true
// 使用 WaitGroup 来等待所有 goroutine 完成
var wg sync.WaitGroup
MAX_GOROUTINE := 4096
MAX_KEY := 4
complete := make(chan struct{})
go func() {
for {
select {
case <-time.After(time.Second):
t.Logf("timeout")
utils.DumpAllGoroutineStack(os.Stdout)
case <-complete:
return
}
}
}()
bgCtx := context.Background()
// 为每个 goroutine 创建独立的 context
for i := 0; i < MAX_GOROUTINE; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
// 为每个 goroutine 创建新的 context
ctx := context.WithValue(bgCtx, emptyKey{}, id)
log.Infof("ctx for id %d: %p", id, ctx)
app := &app{
ctx: ctx,
key: fmt.Sprintf("test-%d", id%MAX_KEY),
lockman: lockman,
}
app.run()
}(i)
}
// 等待所有 goroutine 完成
wg.Wait()
close(complete)
t.Logf("complete")
}
+2
View File
@@ -71,6 +71,8 @@ type BaseOptions struct {
ApplicationID string `help:"Application ID"`
RequestWorkerCount int `default:"8" help:"Request worker thread count, default is 8"`
RequestWorkerQueueSize int `default:"10" help:"Request worker queue size, default is 10"`
TaskWorkerCount int `default:"4" help:"Task manager worker thread count, default is 4"`
LocalTaskWorkerCount int `default:"4" help:"Worker thread count that runs local tasks, default is 4"`
+24 -55
View File
@@ -31,12 +31,12 @@ import (
"yunion.io/x/onecloud/pkg/apis"
identity_api "yunion.io/x/onecloud/pkg/apis/identity"
"yunion.io/x/onecloud/pkg/appsrv"
"yunion.io/x/onecloud/pkg/cloudcommon/consts"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/mcclient/auth"
"yunion.io/x/onecloud/pkg/mcclient/modules/identity"
"yunion.io/x/onecloud/pkg/util/ctx"
"yunion.io/x/onecloud/pkg/util/hashcache"
"yunion.io/x/onecloud/pkg/util/rbacutils"
"yunion.io/x/onecloud/pkg/util/tagutils"
@@ -76,7 +76,7 @@ type SPolicyManager struct {
policyCache *hashcache.Cache // policy cache
permissionCache *hashcache.Cache // permission cache
fetchWorker *appsrv.SWorkerManager
// fetchWorker *appsrv.SWorkerManager
lock *sync.Mutex
}
@@ -146,19 +146,19 @@ func (manager *SPolicyManager) init(refreshInterval time.Duration, workerCount i
defaultFetcherFuncAddr := reflect.ValueOf(DefaultPolicyFetcher).Pointer()
remoteFetcherFuncAddr := reflect.ValueOf(auth.FetchMatchPolicies).Pointer()
log.Debugf("DefaultPolicyFetcher: %x RemotePolicyFetcher: %x", defaultFetcherFuncAddr, remoteFetcherFuncAddr)
var isDB bool
if defaultFetcherFuncAddr == remoteFetcherFuncAddr {
// remote fetcher, so start watcher
isDB = false
} else {
isDB = true
}
// var isDB bool
// if defaultFetcherFuncAddr == remoteFetcherFuncAddr {
// remote fetcher, so start watcher
// isDB = false
// } else {
// isDB = true
// }
if workerCount <= 0 {
workerCount = 1
}
log.Infof("policy fetch worker count %d", workerCount)
manager.fetchWorker = appsrv.NewWorkerManager("policyFetchWorker", workerCount, 2048, isDB)
// if workerCount <= 0 {
// workerCount = 1
// }
// log.Infof("policy fetch worker count %d", workerCount)
// manager.fetchWorker = appsrv.NewWorkerManager("policyFetchWorker", workerCount, 2048, isDB)
}
func getMaskedLoginIp(userCred mcclient.TokenCredential) string {
@@ -255,53 +255,22 @@ func (manager *SPolicyManager) Allow(targetScope rbacscope.TRbacScope, userCred
return rbacutils.PolicyDeny
}
type fetchResult struct {
output *mcclient.SFetchMatchPoliciesOutput
err error
}
type policyTask struct {
manager *SPolicyManager
key string
userCred mcclient.TokenCredential
resChan chan fetchResult
}
func (t *policyTask) Run() {
val := t.manager.policyCache.AtomicGet(t.key)
result := fetchResult{}
if gotypes.IsNil(val) {
pg, err := DefaultPolicyFetcher(context.Background(), t.userCred)
if err != nil {
result.err = errors.Wrap(err, "DefaultPolicyFetcher")
} else {
t.manager.policyCache.AtomicSet(t.key, pg)
result.output = pg
}
} else {
result.output = val.(*mcclient.SFetchMatchPoliciesOutput)
}
t.resChan <- result
}
func (t *policyTask) Dump() string {
return ""
}
func (manager *SPolicyManager) fetchMatchedPolicies(userCred mcclient.TokenCredential) (*mcclient.SFetchMatchPoliciesOutput, error) {
key := policyKey(userCred)
task := policyTask{
manager: manager,
key: key,
userCred: userCred,
val := manager.policyCache.AtomicGet(key)
if !gotypes.IsNil(val) {
// cache hit
return val.(*mcclient.SFetchMatchPoliciesOutput), nil
}
task.resChan = make(chan fetchResult)
manager.fetchWorker.Run(&task, nil, nil)
pg, err := DefaultPolicyFetcher(ctx.CtxWithTime(), userCred)
if err != nil {
return nil, errors.Wrap(err, "DefaultPolicyFetcher")
}
res := <-task.resChan
return res.output, res.err
manager.policyCache.AtomicSet(key, pg)
return pg, nil
}
func (manager *SPolicyManager) allow(scope rbacscope.TRbacScope, userCred mcclient.TokenCredential, service string, resource string, action string, extra ...string) rbacutils.SPolicyResult {
+4
View File
@@ -207,6 +207,10 @@ func NewTooLargeEntityError(msg string, params ...interface{}) *httputils.JSONCl
return httputils.NewJsonClientError(httpErrorCode[ErrTooLarge], string(ErrTooLarge), msg, params...)
}
func NewTooManyRequestsError(msg string, params ...interface{}) *httputils.JSONClientError {
return httputils.NewJsonClientError(httpErrorCode[ErrTooManyRequests], string(ErrTooManyRequests), msg, params...)
}
func NewServiceAbnormalError(msg string, params ...interface{}) *httputils.JSONClientError {
return httputils.NewJsonClientError(httpErrorCode[ErrServiceAbnormal], string(ErrServiceAbnormal), msg, params...)
}
+4
View File
@@ -205,3 +205,7 @@ func ProtectedResourceError(ctx context.Context, w http.ResponseWriter, msg stri
func NoProjectError(ctx context.Context, w http.ResponseWriter, msg string, params ...interface{}) {
JsonClientError(ctx, w, NewNoProjectError(msg, params...))
}
func TooManyRequestsError(ctx context.Context, w http.ResponseWriter, msg string, params ...interface{}) {
JsonClientError(ctx, w, NewTooManyRequestsError(msg, params...))
}
+1 -1
View File
@@ -101,7 +101,7 @@ func prepareServer() error {
return errors.Wrapf(httperrors.ErrInputParameter, "cert %s not found", options.Cert)
}
app := appsrv.NewApplication("samldemo", 4, false)
app := appsrv.NewApplication("samldemo", 4, 10, false)
saml, err := samlutils.NewSAMLInstance(options.Entity, options.Cert, options.Key)
if err != nil {
+4
View File
@@ -0,0 +1,4 @@
*~
*.test
.*.swp
.DS_Store
+202
View File
@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
+4
View File
@@ -0,0 +1,4 @@
# goid ![Build Status](https://github.com/petermattis/goid/actions/workflows/go.yml/badge.svg)
Programatically retrieve the current goroutine's ID. See [the CI
configuration](.github/workflows/go.yml) for supported Go versions.
+35
View File
@@ -0,0 +1,35 @@
// Copyright 2016 Peter Mattis.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing
// permissions and limitations under the License. See the AUTHORS file
// for names of contributors.
package goid
import (
"bytes"
"runtime"
"strconv"
)
func ExtractGID(s []byte) int64 {
s = s[len("goroutine "):]
s = s[:bytes.IndexByte(s, ' ')]
gid, _ := strconv.ParseInt(string(s), 10, 64)
return gid
}
// Parse the goid from runtime.Stack() output. Slow, but it works.
func getSlow() int64 {
var buf [64]byte
return ExtractGID(buf[:runtime.Stack(buf[:], false)])
}
+26
View File
@@ -0,0 +1,26 @@
// Copyright 2018 Peter Mattis.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing
// permissions and limitations under the License. See the AUTHORS file
// for names of contributors.
//go:build gccgo
// +build gccgo
package goid
//extern runtime.getg
func getg() *g
func Get() int64 {
return getg().goid
}
+23
View File
@@ -0,0 +1,23 @@
// Copyright 2015 Peter Mattis.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing
// permissions and limitations under the License. See the AUTHORS file
// for names of contributors.
// +build !go1.4
#include <runtime.h>
void ·Get(int64 ret) {
ret = g->goid;
USED(&ret);
}
+22
View File
@@ -0,0 +1,22 @@
// Copyright 2015 Peter Mattis.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing
// permissions and limitations under the License. See the AUTHORS file
// for names of contributors.
//go:build !go1.4
// +build !go1.4
package goid
// Get returns the id of the current goroutine.
func Get() int64
+35
View File
@@ -0,0 +1,35 @@
// Copyright 2015 Peter Mattis.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing
// permissions and limitations under the License. See the AUTHORS file
// for names of contributors.
//go:build go1.4 && !go1.5
// +build go1.4,!go1.5
package goid
import "unsafe"
var pointerSize = unsafe.Sizeof(uintptr(0))
// Backdoor access to runtime·getg().
func getg() uintptr // in goid_go1.4.s
// Get returns the id of the current goroutine.
func Get() int64 {
// The goid is the 16th field in the G struct where each field is a
// pointer, uintptr or padded to that size. See runtime.h from the
// Go sources. I'm not aware of a cleaner way to determine the
// offset.
return *(*int64)(unsafe.Pointer(getg() + 16*pointerSize))
}
+18
View File
@@ -0,0 +1,18 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Assembly to get into package runtime without using exported symbols.
// See https://github.com/golang/go/blob/release-branch.go1.4/misc/cgo/test/backdoor/thunk.s
// +build amd64 amd64p32 arm 386
// +build go1.4,!go1.5
#include "textflag.h"
#ifdef GOARCH_arm
#define JMP B
#endif
TEXT ·getg(SB),NOSPLIT,$0-0
JMP runtime·getg(SB)
+28
View File
@@ -0,0 +1,28 @@
// Copyright 2016 Peter Mattis.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing
// permissions and limitations under the License. See the AUTHORS file
// for names of contributors.
//go:build (386 || amd64 || amd64p32 || arm || arm64 || s390x) && gc && go1.5
// +build 386 amd64 amd64p32 arm arm64 s390x
// +build gc
// +build go1.5
package goid
// Defined in goid_go1.5.s.
func getg() *g
func Get() int64 {
return getg().goid
}
+44
View File
@@ -0,0 +1,44 @@
// Copyright 2021 Peter Mattis.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing
// permissions and limitations under the License. See the AUTHORS file
// for names of contributors.
// Assembly to mimic runtime.getg.
//go:build (386 || amd64 || amd64p32 || arm || arm64 || s390x) && gc && go1.5
// +build 386 amd64 amd64p32 arm arm64 s390x
// +build gc
// +build go1.5
#include "textflag.h"
// func getg() *g
TEXT ·getg(SB),NOSPLIT,$0-8
#ifdef GOARCH_386
MOVL (TLS), AX
MOVL AX, ret+0(FP)
#endif
#ifdef GOARCH_amd64
MOVQ (TLS), AX
MOVQ AX, ret+0(FP)
#endif
#ifdef GOARCH_arm
MOVW g, ret+0(FP)
#endif
#ifdef GOARCH_arm64
MOVD g, ret+0(FP)
#endif
#ifdef GOARCH_s390x
MOVD g, ret+0(FP)
#endif
RET
+24
View File
@@ -0,0 +1,24 @@
// Copyright 2016 Peter Mattis.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing
// permissions and limitations under the License. See the AUTHORS file
// for names of contributors.
//go:build (go1.4 && !go1.5 && !amd64 && !amd64p32 && !arm && !386) || (go1.5 && !386 && !amd64 && !amd64p32 && !arm && !arm64 && !s390x)
// +build go1.4,!go1.5,!amd64,!amd64p32,!arm,!386 go1.5,!386,!amd64,!amd64p32,!arm,!arm64,!s390x
package goid
// Get returns the id of the current goroutine.
func Get() int64 {
return getSlow()
}
+17
View File
@@ -0,0 +1,17 @@
//go:build gccgo && go1.8
// +build gccgo,go1.8
package goid
// https://github.com/gcc-mirror/gcc/blob/releases/gcc-7/libgo/go/runtime/runtime2.go#L329-L354
type g struct {
_panic uintptr
_defer uintptr
m uintptr
syscallsp uintptr
syscallpc uintptr
param uintptr
atomicstatus uint32
goid int64 // Here it is!
}
+38
View File
@@ -0,0 +1,38 @@
//go:build gc && go1.23
// +build gc,go1.23
package goid
type stack struct {
lo uintptr
hi uintptr
}
type gobuf struct {
sp uintptr
pc uintptr
g uintptr
ctxt uintptr
ret uintptr
lr uintptr
bp uintptr
}
type g struct {
stack stack
stackguard0 uintptr
stackguard1 uintptr
_panic uintptr
_defer uintptr
m uintptr
sched gobuf
syscallsp uintptr
syscallpc uintptr
syscallbp uintptr
stktopsp uintptr
param uintptr
atomicstatus uint32
stackLock uint32
goid int64 // Here it is!
}
+57
View File
@@ -0,0 +1,57 @@
// Copyright 2016 Peter Mattis.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing
// permissions and limitations under the License. See the AUTHORS file
// for names of contributors.
//go:build go1.5 && !go1.6
// +build go1.5,!go1.6
package goid
// Just enough of the structs from runtime/runtime2.go to get the offset to goid.
// See https://github.com/golang/go/blob/release-branch.go1.5/src/runtime/runtime2.go
type stack struct {
lo uintptr
hi uintptr
}
type gobuf struct {
sp uintptr
pc uintptr
g uintptr
ctxt uintptr
ret uintptr
lr uintptr
bp uintptr
}
type g struct {
stack stack
stackguard0 uintptr
stackguard1 uintptr
_panic uintptr
_defer uintptr
m uintptr
stackAlloc uintptr
sched gobuf
syscallsp uintptr
syscallpc uintptr
stkbar []uintptr
stkbarPos uintptr
param uintptr
atomicstatus uint32
stackLock uint32
goid int64 // Here it is!
}
+43
View File
@@ -0,0 +1,43 @@
//go:build gc && go1.6 && !go1.9
// +build gc,go1.6,!go1.9
package goid
// Just enough of the structs from runtime/runtime2.go to get the offset to goid.
// See https://github.com/golang/go/blob/release-branch.go1.6/src/runtime/runtime2.go
type stack struct {
lo uintptr
hi uintptr
}
type gobuf struct {
sp uintptr
pc uintptr
g uintptr
ctxt uintptr
ret uintptr
lr uintptr
bp uintptr
}
type g struct {
stack stack
stackguard0 uintptr
stackguard1 uintptr
_panic uintptr
_defer uintptr
m uintptr
stackAlloc uintptr
sched gobuf
syscallsp uintptr
syscallpc uintptr
stkbar []uintptr
stkbarPos uintptr
stktopsp uintptr
param uintptr
atomicstatus uint32
stackLock uint32
goid int64 // Here it is!
}
+37
View File
@@ -0,0 +1,37 @@
//go:build gc && go1.9 && !go1.23
// +build gc,go1.9,!go1.23
package goid
type stack struct {
lo uintptr
hi uintptr
}
type gobuf struct {
sp uintptr
pc uintptr
g uintptr
ctxt uintptr
ret uintptr
lr uintptr
bp uintptr
}
type g struct {
stack stack
stackguard0 uintptr
stackguard1 uintptr
_panic uintptr
_defer uintptr
m uintptr
sched gobuf
syscallsp uintptr
syscallpc uintptr
stktopsp uintptr
param uintptr
atomicstatus uint32
stackLock uint32
goid int64 // Here it is!
}
+5 -2
View File
@@ -1044,6 +1044,9 @@ github.com/openzipkin/zipkin-go-opentracing/wire
# github.com/oracle/oci-go-sdk v24.3.0+incompatible
## explicit
github.com/oracle/oci-go-sdk/common
# github.com/petermattis/goid v0.0.0-20250508124226-395b08cebbdb
## explicit; go 1.17
github.com/petermattis/goid
# github.com/philhofer/fwd v1.0.0
## explicit
github.com/philhofer/fwd
@@ -1849,7 +1852,7 @@ sigs.k8s.io/structured-merge-diff/v4/value
# sigs.k8s.io/yaml v1.2.0
## explicit; go 1.12
sigs.k8s.io/yaml
# yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20250616091331-d7f1f89a7d90
# yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20250618092159-24a4b21d2439
## explicit; go 1.21
yunion.io/x/cloudmux/pkg/apis
yunion.io/x/cloudmux/pkg/apis/billing
@@ -1946,7 +1949,7 @@ yunion.io/x/log/hooks
yunion.io/x/ovsdb/cli_util
yunion.io/x/ovsdb/schema/ovn_nb
yunion.io/x/ovsdb/types
# yunion.io/x/pkg v1.10.4-0.20250519013345-54017bf6c1f0
# yunion.io/x/pkg v1.10.4-0.20250618071935-840c253075b0
## explicit; go 1.18
yunion.io/x/pkg/appctx
yunion.io/x/pkg/errors
+1
View File
@@ -21,6 +21,7 @@ const (
STORAGE_VSAN = "vsan"
STORAGE_NFS = "nfs"
STORAGE_CIFS = "cifs"
STORAGE_PMEM = "pmem"
STORAGE_PUBLIC_CLOUD = "cloud"
STORAGE_CLOUD_EFFICIENCY = "cloud_efficiency"
+1 -1
View File
@@ -808,7 +808,7 @@ func (self *SAliyunClient) GetSubAccounts() ([]cloudprovider.SSubAccount, error)
accounts, err := self.ListAccounts()
if err != nil {
if e, ok := errors.Cause(err).(*alierr.ServerError); ok && e.ErrorCode() == "EntityNotExists.ResourceDirectory" {
if e, ok := errors.Cause(err).(*alierr.ServerError); ok && (e.ErrorCode() == "EntityNotExists.ResourceDirectory" || e.ErrorCode() == "NoPermission") {
return ret, nil
}
return nil, errors.Wrapf(err, "ListAccounts")
+3
View File
@@ -323,6 +323,9 @@ func (self *SCtyunClient) request(method httputils.THttpMethod, service, resourc
func (self *SCtyunClient) GetIRegions() ([]cloudprovider.ICloudRegion, error) {
ret := []cloudprovider.ICloudRegion{}
for i := range self.regions {
if !self.regions[i].OpenapiAvailable {
continue
}
self.regions[i].client = self
ret = append(ret, &self.regions[i])
}
@@ -19,59 +19,6 @@ import (
"yunion.io/x/cloudmux/pkg/cloudprovider"
)
var CtyunRegionIdMap = map[string]string{
"07323cf87fa811ea977e0242ac110002": "cn-lasa-4",
"200000001627": "cn-fuzhou-5",
"200000001681": "cn-ln-liaoyang-1",
"200000001703": "cn-sd-qd20-public-ctcloud",
"200000001704": "cn-gx-nn23-public-ctcloud",
"200000001781": "cn-hb-wh41-public-ctcloud",
"200000001788": "cn-wulumuqi-27",
"200000001790": "cn-sh36-public-ctcloud",
"200000001852": "cn-huabei2-public-ctcloud",
"200000001858": "cfbr-fsao1-public-ctcloud",
"200000001859": "cfae-fdxb1-public-ctcloud",
"200000001860": "cfde-ffra1-public-ctcloud",
"200000001861": "cfsg-fsin3-public-ctcloud",
"200000002368": "cn-xinan1-public-ctcloud",
"200000002401": "cn-hn-cs42-public-ctcloud",
"200000002527": "cn-jx-khn5-public-ctcloud",
"21c52b2a876e11ea9f6a0242ac110002": "cn-hangzhou-2",
"22c0f506ef1d11ea80620242ac110002": "cn-nanjing-4",
"276826f4313311eaaae30242ac110002": "cn-wuhan-3",
"2cdd393e876f11ea98880242ac110002": "cn-yaan-2",
"4009c41a876e11eabdc50242ac110002": "cn-wuhu-1",
"415089caaea711eab0790242ac110002": "cn-kunming-2",
"45d9efdad66f11ec9aab0242ac110002": "cn-hefei2",
"461f819e6e3e11ea9ad30242ac110002": "cn-fujian-3",
"49829300a71211ea95240242ac110002": "cn-jinzhong-2",
"52c69bbc042411ec8dac0242ac110002": "cn-nanjing-5",
"6019b5007a0b11eab5db0242ac110002": "cn-huhehaote-6",
"60a39fca876e11ea91cf0242ac110002": "cn-nanjing-3",
"705213b6876e11eaa5740242ac110002": "cn-haikou-2",
"7dcbf0ba919c11ea83d60242ac110002": "cn-tianjin-2",
"8062c840876e11ea9d060242ac110002": "cn-wuhan-5",
"8d11979c4d5d11eab0520242ac110002": "cn-foshan-3",
"8ef3dba6876e11ea8c2a0242ac110002": "cn-nanning-2",
"9833d24065a211eaa6070242ac110002": "cn-chenzhou-4",
"9859b8964d5d11eaba270242ac110002": "cn-jiangxi-2",
"990ba31c22ec11eaaebd0242ac110002": "cn-hunan-3",
"995b39bae63811ec8c4b0242ac110002": "cn-guangzhou-5",
"a10d954c70f411eab3650242ac110002": "cn-chongqing-2",
"a17034a4794111eaaa590242ac110002": "cn-shanghai-7",
"a2ed23940b3911ea98040242ac110002": "cn-shanxi-2",
"aaf589124d5d11eaa04d0242ac110002": "cn-guiyang-1",
"ad51908ca3db11ea96c20242ac110002": "cn-haerbin-2",
"aefabf04a3df11eaa3650242ac110002": "cn-zhengzhou-2",
"b6bb383e876c11ea8a5e0242ac110002": "cn-beijing-5",
"b7e069bc876e11eaa4c00242ac110002": "cn-xian-4",
"bb9fdb42056f11eda1610242ac110002": "cn-huadong1-public-ctcloud",
"d7d93102848711ea9ff10242ac110002": "cn-fuzhou-4",
"dc3aceb4412211ecb8e70242ac110002": "cn-xian-5",
"dff35c48876e11eaadc90242ac110002": "cn-lanzhou-3",
"eeed8c16e13111e9a5b40242ac110002": "cn-nanjing-2",
}
var LatitudeAndLongitude = map[string]cloudprovider.SGeographicInfo{
"cn-beijing-5": api.RegionBeijing,
"cn-hangzhou-2": api.RegionHangzhou,
+11 -23
View File
@@ -37,12 +37,14 @@ type SRegion struct {
product *SProduct
IsMultiZones bool
RegionParent string
RegionId string
RegionType string
ZoneList []string
RegionName string
IsMultiZones bool
OpenapiAvailable bool
RegionParent string
RegionId string
RegionCode string
RegionType string
ZoneList []string
RegionName string
}
func (self *SRegion) list(service, res string, params map[string]interface{}) (jsonutils.JSONObject, error) {
@@ -118,9 +120,8 @@ func (self *SRegion) CreateISecurityGroup(opts *cloudprovider.SecurityGroupCreat
}
func (self *SRegion) GetId() string {
id, ok := CtyunRegionIdMap[self.RegionId]
if ok {
return id
if len(self.RegionCode) > 0 {
return self.RegionCode
}
return self.RegionId
}
@@ -136,25 +137,12 @@ func (self *SRegion) GetI18n() cloudprovider.SModelI18nTable {
return table
}
func (self *SRegion) getProduct() (*SProduct, error) {
if !gotypes.IsNil(self.product) {
return self.product, nil
}
var err error
self.product, err = self.GetProduct()
return self.product, err
}
func (self *SRegion) GetGlobalId() string {
return fmt.Sprintf("%s/%s", self.client.GetAccessEnv(), self.GetId())
}
func (self *SRegion) GetStatus() string {
product, err := self.getProduct()
if err != nil {
return api.CLOUD_REGION_STATUS_OUTOFSERVICE
}
if len(product.Other.Region) == 0 {
if !self.OpenapiAvailable {
return api.CLOUD_REGION_STATUS_OUTOFSERVICE
}
return api.CLOUD_REGION_STATUS_INSERVER
+9 -2
View File
@@ -154,8 +154,15 @@ func (self *SSecurityGroup) CreateRule(opts *cloudprovider.SecurityGroupRuleCrea
}
for i := range self.SecurityGroupRuleList {
if !utils.IsInStringArray(self.SecurityGroupRuleList[i].Id, ruleIds) {
self.SecurityGroupRuleList[i].secgroup = self
return &self.SecurityGroupRuleList[i], nil
if self.SecurityGroupRuleList[i].GetDirection() == opts.Direction &&
self.SecurityGroupRuleList[i].GetProtocol() == opts.Protocol &&
self.SecurityGroupRuleList[i].GetPriority() == opts.Priority &&
self.SecurityGroupRuleList[i].GetPorts() == opts.Ports &&
self.SecurityGroupRuleList[i].DestCidrIP == opts.CIDR &&
self.SecurityGroupRuleList[i].GetAction() == opts.Action {
self.SecurityGroupRuleList[i].secgroup = self
return &self.SecurityGroupRuleList[i], nil
}
}
}
time.Sleep(time.Second * 3)
+1 -1
View File
@@ -72,7 +72,7 @@ func (self *SZone) GetIHostById(id string) (cloudprovider.ICloudHost, error) {
}
func (self *SZone) GetStorages() ([]SStorage, error) {
product, err := self.region.getProduct()
product, err := self.region.GetProduct()
if err != nil {
return nil, errors.Wrapf(err, "getProduct")
}
+5 -1
View File
@@ -147,6 +147,8 @@ func (self *SDatastore) getVolumeId() (string, error) {
return fsInfo.Vmfs.Uuid, nil
case *types.NasDatastoreInfo:
return fmt.Sprintf("%s:%s", fsInfo.Nas.RemoteHost, fsInfo.Nas.RemotePath), nil
case *types.PMemDatastoreInfo:
return strings.TrimPrefix(fsInfo.Url, "ds:///"), nil
}
if moStore.Summary.Type == "vsan" {
vsanId := moStore.Summary.Url
@@ -414,10 +416,12 @@ func (self *SDatastore) GetStorageType() string {
}
case "nfs", "nfs41":
return api.STORAGE_NFS
case "vsan":
case "vsan", "vsand":
return api.STORAGE_VSAN
case "cifs":
return api.STORAGE_CIFS
case "pmem":
return api.STORAGE_PMEM
default:
log.Fatalf("unsupported datastore type %s", moStore.Summary.Type)
return ""
+1 -1
View File
@@ -924,7 +924,7 @@ func (client *SQcloudClient) fetchBuckets() error {
func (client *SQcloudClient) GetSubAccounts() ([]cloudprovider.SSubAccount, error) {
nodes, err := client.DescribeOrganizationMembers()
if err != nil && errors.Cause(err) != cloudprovider.ErrNotFound {
if err != nil && errors.Cause(err) != cloudprovider.ErrNotFound && errors.Cause(err) != cloudprovider.ErrNoPermission {
return nil, err
}
subAccount := cloudprovider.SSubAccount{}
+37 -12
View File
@@ -26,9 +26,33 @@ import (
"yunion.io/x/pkg/util/sets"
)
type StatusInfo struct {
Status string `json:"status"`
TotalCount int64 `json:"total_count"`
PendingDeletedCount int64 `json:"pending_deleted_count"`
}
type StatusInfoList []StatusInfo
func (a StatusInfoList) Len() int { return len(a) }
func (a StatusInfoList) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a StatusInfoList) Less(i, j int) bool {
if a[i].TotalCount != a[j].TotalCount {
return a[i].TotalCount > a[j].TotalCount
}
if a[i].PendingDeletedCount != a[j].PendingDeletedCount {
return a[i].PendingDeletedCount > a[j].PendingDeletedCount
}
return a[i].Status < a[j].Status
}
type TotalCountWithStatusInfo struct {
StatusInfo StatusInfoList `json:"status_info"`
}
func PrintJSONList(list *ListResult, columns []string) {
colsWithData := make([]string, 0)
if columns == nil || len(columns) == 0 {
if len(columns) == 0 {
colsWithDataMap := make(map[string]bool)
for _, obj := range list.Data {
objdict, _ := obj.(*jsonutils.JSONDict)
@@ -140,21 +164,22 @@ func PrintJSONList(list *ListResult, columns []string) {
}
fmt.Println("*** ", title, " ***")
if list.Totals != nil {
if totalDict, ok := list.Totals.(*jsonutils.JSONDict); ok {
totalMap, err := totalDict.GetMap()
if err != nil {
fmt.Println("error to convert totals to JSONDict")
} else {
segs := make([]string, 0)
for k, v := range totalMap {
segs = append(segs, fmt.Sprintf("%s: %s", k, v.String()))
}
fmt.Printf("***%s***\n", strings.Join(segs, ", "))
totalWithStatusInfo := TotalCountWithStatusInfo{}
err := list.Totals.Unmarshal(&totalWithStatusInfo)
if err != nil {
fmt.Println("error to unmarshal totals to TotalCountWithStatusInfo", err)
} else if len(totalWithStatusInfo.StatusInfo) > 0 {
sort.Sort(totalWithStatusInfo.StatusInfo)
pt := prettytable.NewPrettyTableWithTryTermWidth([]string{"#", "Status", "Count", "PendingDeletedCount"}, tryTermWidth)
rows := make([][]string, 0)
for i, statusInfo := range totalWithStatusInfo.StatusInfo {
rows = append(rows, []string{fmt.Sprintf("#%d", i+1), statusInfo.Status, strconv.FormatInt(statusInfo.TotalCount, 10), strconv.FormatInt(statusInfo.PendingDeletedCount, 10)})
}
fmt.Print(pt.GetString(rows))
}
}
if colTruncated {
fmt.Println(fmt.Sprintf("!!!Some text truncated, set env %s=-1 to show full text!!!", OS_MAX_COLUMN_TEXT_LENGTH))
fmt.Println("!!!Some text truncated, set env", OS_MAX_COLUMN_TEXT_LENGTH, "=-1 to show full text!!!")
}
}