mirror of
https://hubproxy.babadafafafafa.cn/https://github.com/yunionio/cloudpods.git
synced 2026-09-20 08:03:53 +08:00
Compare commits
67 Commits
4abe94ca0b
...
v4.0.0-rc.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
97acf6086c | ||
|
|
78abadcc7b | ||
|
|
e748d8e94a | ||
|
|
b401b032bb | ||
|
|
6607ffc3f1 | ||
|
|
2fe1d0e788 | ||
|
|
044d554d71 | ||
|
|
7e0e67daee | ||
|
|
8779d89e06 | ||
|
|
5c182471c5 | ||
|
|
1902770c49 | ||
|
|
11fccaeb51 | ||
|
|
ea70981aa3 | ||
|
|
2ab08b0e2a | ||
|
|
76c9a6841c | ||
|
|
8ddf395e62 | ||
|
|
591de392b7 | ||
|
|
fb0375dab4 | ||
|
|
411dd53c12 | ||
|
|
b3a687c380 | ||
|
|
48d9270e71 | ||
|
|
5a17a9e37b | ||
|
|
44ed13473a | ||
|
|
d8b00188a0 | ||
|
|
0b61ca0432 | ||
|
|
b9a9151555 | ||
|
|
17db7be134 | ||
|
|
892431d5b9 | ||
|
|
3d36c293e5 | ||
|
|
3ff50f0d11 | ||
|
|
6144325daf | ||
|
|
bf3b83870c | ||
|
|
62b7eea828 | ||
|
|
4e07811e2f | ||
|
|
f819e021b3 | ||
|
|
3224eac821 | ||
|
|
a1fce125da | ||
|
|
aa0a6b58d3 | ||
|
|
0c9a44e279 | ||
|
|
4dd92825a8 | ||
|
|
30a319fe5e | ||
|
|
faf35a6879 | ||
|
|
4520b54a5b | ||
|
|
fa53aea075 | ||
|
|
36b5532b04 | ||
|
|
01ab43941e | ||
|
|
249569be9f | ||
|
|
db0b275772 | ||
|
|
e6bb86c934 | ||
|
|
c53f707089 | ||
|
|
ef36176130 | ||
|
|
edd11ea1cd | ||
|
|
4ad7d635bc | ||
|
|
18604b46b1 | ||
|
|
4609c543c9 | ||
|
|
779559dbdc | ||
|
|
27c6c82b82 | ||
|
|
fa99905bf6 | ||
|
|
608e4edb4e | ||
|
|
43c646b537 | ||
|
|
ad798d7bbe | ||
|
|
238458066a | ||
|
|
90a8b10401 | ||
|
|
46195f72ee | ||
|
|
05829a225a | ||
|
|
f0858ce4d2 | ||
|
|
cc3477415d |
5
Makefile
5
Makefile
@@ -84,9 +84,6 @@ vet:
|
||||
# cmd/esxi-agent: prepare_dir
|
||||
# CGO_ENABLED=0 $(GO_BUILD) -o $(BIN_DIR)/$(shell basename $@) $(REPO_PREFIX)/$@
|
||||
|
||||
cmd/host: prepare_dir
|
||||
CGO_ENABLED=1 $(GO_BUILD) -o $(BIN_DIR)/$(shell basename $@) $(REPO_PREFIX)/$@
|
||||
|
||||
cmd/%: prepare_dir
|
||||
CGO_ENABLED=0 $(GO_BUILD) -o $(BIN_DIR)/$(shell basename $@) $(REPO_PREFIX)/$@
|
||||
|
||||
@@ -277,7 +274,7 @@ dep:
|
||||
@echo "$$depDeprecated"
|
||||
@$(MAKE) mod
|
||||
|
||||
RELEASE_BRANCH:=master
|
||||
RELEASE_BRANCH:=release/4.0.0
|
||||
GOPROXY ?= direct
|
||||
|
||||
mod:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM registry.cn-beijing.aliyuncs.com/yunionio/host-deployer-base:1.4.9
|
||||
FROM registry.cn-beijing.aliyuncs.com/yunionio/host-deployer-base:1.4.10
|
||||
|
||||
MAINTAINER "Yaoqi Wan wanyaoqi@yunionyun.com"
|
||||
|
||||
|
||||
@@ -19,178 +19,71 @@ import (
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/objectstore"
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/pkg/util/fileutils"
|
||||
"yunion.io/x/pkg/util/printutils"
|
||||
|
||||
api "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
"yunion.io/x/onecloud/cmd/climc/shell"
|
||||
"yunion.io/x/onecloud/pkg/apis/compute"
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
modules "yunion.io/x/onecloud/pkg/mcclient/modules/compute"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/options"
|
||||
computeoptions "yunion.io/x/onecloud/pkg/mcclient/options/compute"
|
||||
)
|
||||
|
||||
func init() {
|
||||
type BucketListOptions struct {
|
||||
options.BaseListOptions
|
||||
DistinctField string `help:"query specified distinct field"`
|
||||
}
|
||||
R(&BucketListOptions{}, "bucket-list", "List all buckets", func(s *mcclient.ClientSession, args *BucketListOptions) error {
|
||||
params, err := options.ListStructToParams(args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(args.DistinctField) > 0 {
|
||||
params.Add(jsonutils.NewString(args.DistinctField), "extra_field")
|
||||
result, err := modules.Buckets.Get(s, "distinct-field", params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(result)
|
||||
return nil
|
||||
}
|
||||
result, err := modules.Buckets.List(s, params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printList(result, modules.Buckets.GetColumns(s))
|
||||
return nil
|
||||
})
|
||||
|
||||
type BucketIdOptions struct {
|
||||
ID string `help:"ID or name of bucket"`
|
||||
}
|
||||
R(&BucketIdOptions{}, "bucket-show", "Id details of bucket", func(s *mcclient.ClientSession, args *BucketIdOptions) error {
|
||||
result, err := modules.Buckets.Get(s, args.ID, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(result)
|
||||
return nil
|
||||
})
|
||||
|
||||
R(&BucketIdOptions{}, "bucket-syncstatus", "Sync bucket statust", func(s *mcclient.ClientSession, args *BucketIdOptions) error {
|
||||
result, err := modules.Buckets.PerformAction(s, args.ID, "syncstatus", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(result)
|
||||
return nil
|
||||
})
|
||||
|
||||
type BucketUpdateOptions struct {
|
||||
ID string `help:"ID or name of bucket" json:"-"`
|
||||
Name string `help:"new name of bucket" json:"name"`
|
||||
Desc string `help:"Description of bucket" json:"description" token:"desc"`
|
||||
}
|
||||
R(&BucketUpdateOptions{}, "bucket-update", "update bucket", func(s *mcclient.ClientSession, args *BucketUpdateOptions) error {
|
||||
params := jsonutils.Marshal(args)
|
||||
result, err := modules.Buckets.Update(s, args.ID, params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(result)
|
||||
return nil
|
||||
})
|
||||
|
||||
type BucketDeleteOptions struct {
|
||||
ID string `help:"ID or name of bucket" json:"-"`
|
||||
}
|
||||
R(&BucketDeleteOptions{}, "bucket-delete", "delete bucket", func(s *mcclient.ClientSession, args *BucketDeleteOptions) error {
|
||||
result, err := modules.Buckets.Delete(s, args.ID, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(result)
|
||||
return nil
|
||||
})
|
||||
|
||||
type BucketCreateOptions struct {
|
||||
NAME string `help:"name of bucket" json:"name"`
|
||||
CLOUDREGION string `help:"location of bucket" json:"cloudregion"`
|
||||
MANAGER string `help:"cloud provider" json:"manager"`
|
||||
|
||||
StorageClass string `help:"bucket storage class"`
|
||||
Acl string `help:"bucket ACL"`
|
||||
}
|
||||
R(&BucketCreateOptions{}, "bucket-create", "Create a bucket", func(s *mcclient.ClientSession, args *BucketCreateOptions) error {
|
||||
params, err := options.StructToParams(args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
result, err := modules.Buckets.Create(s, params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(result)
|
||||
return nil
|
||||
})
|
||||
|
||||
type BucketListObjectsOptions struct {
|
||||
ID string `help:"ID or name of bucket" json:"-"`
|
||||
Prefix string `help:"List objects with prefix"`
|
||||
Recursive bool `help:"List objects recursively"`
|
||||
Limit int `help:"maximal items per request"`
|
||||
PagingMarker string `help:"paging marker"`
|
||||
}
|
||||
R(&BucketListObjectsOptions{}, "bucket-object-list", "List objects in a bucket", func(s *mcclient.ClientSession, args *BucketListObjectsOptions) error {
|
||||
params, err := options.StructToParams(args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
result, err := modules.Buckets.GetSpecific(s, args.ID, "objects", params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cmd := shell.NewResourceCmd(&modules.Buckets)
|
||||
cmd.List(&computeoptions.BucketListOptions{})
|
||||
cmd.GetProperty(&computeoptions.BucketGetPropertyOptions{})
|
||||
cmd.Show(&computeoptions.BucketIdOptions{})
|
||||
cmd.Perform("syncstatus", &computeoptions.BucketIdOptions{})
|
||||
cmd.Update(&computeoptions.BucketUpdateOptions{})
|
||||
cmd.Delete(&computeoptions.BucketIdOptions{})
|
||||
cmd.Create(&computeoptions.BucketCreateOptions{})
|
||||
cmd.GetWithCustomOptionShow("objects", func(data jsonutils.JSONObject, args shell.IGetOpt) {
|
||||
listResult := printutils.ListResult{}
|
||||
err = result.Unmarshal(&listResult)
|
||||
err := data.Unmarshal(&listResult)
|
||||
if err != nil {
|
||||
return err
|
||||
return
|
||||
}
|
||||
printList(&listResult, []string{})
|
||||
return nil
|
||||
})
|
||||
}, &computeoptions.BucketListObjectsOptions{})
|
||||
cmd.Perform("delete", &computeoptions.BucketDeleteObjectsOptions{})
|
||||
cmd.Perform("makedir", &computeoptions.BucketMakeDirOptions{})
|
||||
cmd.Perform("temp-url", &computeoptions.BucketPresignObjectsOptions{})
|
||||
cmd.Perform("acl", &computeoptions.BucketSetAclOptions{})
|
||||
cmd.GetWithCustomOptionShow("acl", func(data jsonutils.JSONObject, args shell.IGetOpt) {
|
||||
printObject(data)
|
||||
}, &computeoptions.BucketAclOptions{})
|
||||
cmd.Perform("sync", &computeoptions.BucketSyncOptions{})
|
||||
cmd.Perform("limit", &computeoptions.BucketLimitOptions{})
|
||||
cmd.GetWithCustomOptionShow("access-info", func(data jsonutils.JSONObject, args shell.IGetOpt) {
|
||||
printObject(data)
|
||||
}, &computeoptions.BucketAccessInfoOptions{})
|
||||
cmd.Perform("metadata", &computeoptions.BucketSetMetadataOptions{})
|
||||
cmd.Perform("set-website", &computeoptions.BucketSetWebsiteOption{})
|
||||
cmd.GetWithCustomOptionShow("website", func(data jsonutils.JSONObject, args shell.IGetOpt) {
|
||||
printObject(data)
|
||||
}, &computeoptions.BucketGetWebsiteConfOption{})
|
||||
cmd.Perform("delete-website", &computeoptions.BucketDeleteWebsiteConfOption{})
|
||||
cmd.Perform("set-cors", &computeoptions.BucketSetCorsOption{})
|
||||
cmd.GetWithCustomOptionShow("cors", func(data jsonutils.JSONObject, args shell.IGetOpt) {
|
||||
printObject(data)
|
||||
}, &computeoptions.BucketGetCorsOption{})
|
||||
cmd.Perform("delete-cors", &computeoptions.BucketDeleteCorsOption{})
|
||||
cmd.Perform("set-referer", &computeoptions.BucketSetRefererOption{})
|
||||
cmd.GetWithCustomOptionShow("referer", func(data jsonutils.JSONObject, args shell.IGetOpt) {
|
||||
printObject(data)
|
||||
}, &computeoptions.BucketGetRefererOption{})
|
||||
cmd.GetWithCustomOptionShow("cdn-domain", func(data jsonutils.JSONObject, args shell.IGetOpt) {
|
||||
printObject(data)
|
||||
}, &computeoptions.BucketGetCdnDomainOption{})
|
||||
cmd.GetWithCustomOptionShow("policy", func(data jsonutils.JSONObject, args shell.IGetOpt) {
|
||||
printObject(data)
|
||||
}, &computeoptions.BucketGetPolicyOption{})
|
||||
cmd.Perform("set-policy", &computeoptions.BucketSetPolicyOption{})
|
||||
cmd.Perform("delete-policy", &computeoptions.BucketDeletePolicyOption{})
|
||||
|
||||
type BucketDeleteObjectsOptions struct {
|
||||
ID string `help:"ID or name of bucket" json:"-"`
|
||||
KEYS []string `help:"List of objects to delete"`
|
||||
}
|
||||
R(&BucketDeleteObjectsOptions{}, "bucket-object-delete", "Delete objects in a bucket", func(s *mcclient.ClientSession, args *BucketDeleteObjectsOptions) error {
|
||||
params := jsonutils.Marshal(args)
|
||||
result, err := modules.Buckets.PerformAction(s, args.ID, "delete", params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(result)
|
||||
return nil
|
||||
})
|
||||
|
||||
type BucketMakeDirOptions struct {
|
||||
ID string `help:"ID or name of bucket" json:"-"`
|
||||
KEY string `help:"DIR key to create"`
|
||||
}
|
||||
R(&BucketMakeDirOptions{}, "bucket-mkdir", "Mkdir in a bucket", func(s *mcclient.ClientSession, args *BucketMakeDirOptions) error {
|
||||
params := jsonutils.Marshal(args)
|
||||
result, err := modules.Buckets.PerformAction(s, args.ID, "makedir", params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(result)
|
||||
return nil
|
||||
})
|
||||
|
||||
type BucketUploadObjectsOptions struct {
|
||||
ID string `help:"ID or name of bucket" json:"-"`
|
||||
KEY string `help:"Key of object to upload"`
|
||||
Path string `help:"Path to file to upload" required:"true"`
|
||||
|
||||
ContentLength int64 `help:"Content lenght (bytes)" default:"-1"`
|
||||
StorageClass string `help:"storage CLass"`
|
||||
Acl string `help:"object acl." choices:"private|public-read|public-read-write"`
|
||||
|
||||
objectstore.ObjectHeaderOptions
|
||||
}
|
||||
R(&BucketUploadObjectsOptions{}, "bucket-object-upload", "Upload an object into a bucket", func(s *mcclient.ClientSession, args *BucketUploadObjectsOptions) error {
|
||||
R(&computeoptions.BucketUploadObjectsOptions{}, "bucket-object-upload", "Upload an object into a bucket", func(s *mcclient.ClientSession, args *computeoptions.BucketUploadObjectsOptions) error {
|
||||
var body io.Reader
|
||||
if len(args.Path) > 0 {
|
||||
file, err := os.Open(args.Path)
|
||||
@@ -223,332 +116,36 @@ func init() {
|
||||
return nil
|
||||
})
|
||||
|
||||
type BucketPresignObjectsOptions struct {
|
||||
ID string `help:"ID or name of bucket" json:"-"`
|
||||
KEY string `help:"Key of object to upload"`
|
||||
Method string `help:"Request method" choices:"GET|PUT|DELETE"`
|
||||
ExpireSeconds int `help:"expire in seconds" default:"60"`
|
||||
}
|
||||
R(&BucketPresignObjectsOptions{}, "bucket-object-tempurl", "Get temporal URL for an object in a bucket", func(s *mcclient.ClientSession, args *BucketPresignObjectsOptions) error {
|
||||
params, err := options.StructToParams(args)
|
||||
R(&computeoptions.BucketPerfMonOptions{}, "bucket-perf-mon", "Bucket performance monitor", func(s *mcclient.ClientSession, args *computeoptions.BucketPerfMonOptions) error {
|
||||
result, err := modules.Buckets.Get(s, args.ID, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
result, err := modules.Buckets.PerformAction(s, args.ID, "temp-url", params)
|
||||
bucketDetails := compute.BucketDetails{}
|
||||
err = result.Unmarshal(&bucketDetails)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(result)
|
||||
return nil
|
||||
})
|
||||
|
||||
type BucketSetAclOptions struct {
|
||||
ID string `help:"ID or name of bucket" json:"-"`
|
||||
ACL string `help:"ACL to set" choices:"default|private|public-read|public-read-write" json:"acl"`
|
||||
Key []string `help:"Optional object key" json:"key"`
|
||||
}
|
||||
R(&BucketSetAclOptions{}, "bucket-set-acl", "Set ACL of bucket or object", func(s *mcclient.ClientSession, args *BucketSetAclOptions) error {
|
||||
params := jsonutils.Marshal(args)
|
||||
result, err := modules.Buckets.PerformAction(s, args.ID, "acl", params)
|
||||
bucket, err := modules.GetIBucket(s.GetContext(), s, &bucketDetails)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(result)
|
||||
return nil
|
||||
})
|
||||
|
||||
type BucketAclOptions struct {
|
||||
ID string `help:"ID or name of bucket" json:"-"`
|
||||
Key string `help:"Optional object key"`
|
||||
}
|
||||
R(&BucketAclOptions{}, "bucket-acl", "Get ACL of bucket or object", func(s *mcclient.ClientSession, args *BucketAclOptions) error {
|
||||
params, err := options.StructToParams(args)
|
||||
payload, err := fileutils.GetSizeBytes(args.Payload, 1024)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
result, err := modules.Buckets.GetSpecific(s, args.ID, "acl", params)
|
||||
|
||||
stats, err := modules.ProbeBucketStats(s.GetContext(), bucket, "test", int64(payload))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(result)
|
||||
return nil
|
||||
})
|
||||
|
||||
type BucketSyncOptions struct {
|
||||
ID string `help:"ID or name of bucket" json:"-"`
|
||||
StatsOnly bool `help:"sync statistics only"`
|
||||
}
|
||||
R(&BucketSyncOptions{}, "bucket-sync", "Sync bucket", func(s *mcclient.ClientSession, args *BucketSyncOptions) error {
|
||||
params, err := options.StructToParams(args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
result, err := modules.Buckets.PerformAction(s, args.ID, "sync", params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(result)
|
||||
return nil
|
||||
})
|
||||
fmt.Printf("Upload delay %f ms throughput %f MB/s\n", stats.UploadDelayMs(), stats.UploadThroughputMbps(payload/1024/1024))
|
||||
fmt.Printf("Download delay %f ms throughput %f MB/s\n", stats.DownloadDelayMs(), stats.DownloadThroughputMbps(payload/1024/1024))
|
||||
fmt.Printf("Delete delay %f ms\n", stats.DeleteDelayMs())
|
||||
|
||||
type BucketLimitOptions struct {
|
||||
ID string `help:"ID or name of bucket" json:"-"`
|
||||
SizeBytes int64 `help:"size limit in bytes"`
|
||||
ObjectCount int64 `help:"object count limit"`
|
||||
}
|
||||
R(&BucketLimitOptions{}, "bucket-limit", "Set limit of bucket", func(s *mcclient.ClientSession, args *BucketLimitOptions) error {
|
||||
limit := jsonutils.Marshal(args)
|
||||
params := jsonutils.NewDict()
|
||||
params.Set("limit", limit)
|
||||
result, err := modules.Buckets.PerformAction(s, args.ID, "limit", params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(result)
|
||||
return nil
|
||||
})
|
||||
|
||||
type BucketAccessInfoOptions struct {
|
||||
ID string `help:"ID or name of bucket" json:"-"`
|
||||
}
|
||||
R(&BucketAccessInfoOptions{}, "bucket-access-info", "Show backend access info of a bucket", func(s *mcclient.ClientSession, args *BucketAccessInfoOptions) error {
|
||||
result, err := modules.Buckets.GetSpecific(s, args.ID, "access-info", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(result)
|
||||
return nil
|
||||
})
|
||||
|
||||
type BucketSetMetadataOptions struct {
|
||||
ID string `help:"ID or name of bucket" json:"-"`
|
||||
|
||||
Key []string `help:"Optional object key" json:"key"`
|
||||
|
||||
objectstore.ObjectHeaderOptions
|
||||
}
|
||||
R(&BucketSetMetadataOptions{}, "bucket-set-metadata", "Set metadata of object", func(s *mcclient.ClientSession, args *BucketSetMetadataOptions) error {
|
||||
input := api.BucketMetadataInput{}
|
||||
input.Key = args.Key
|
||||
input.Metadata = args.ObjectHeaderOptions.Options2Header()
|
||||
err := input.Validate()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
result, err := modules.Buckets.PerformAction(s, args.ID, "metadata", jsonutils.Marshal(input))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(result)
|
||||
return nil
|
||||
})
|
||||
|
||||
type BucketSetWebsiteOption struct {
|
||||
ID string `help:"ID or name of bucket" json:"-"`
|
||||
// 主页
|
||||
Index string `help:"main page"`
|
||||
// 错误时返回的文档
|
||||
ErrorDocument string `help:"error return"`
|
||||
// http或https
|
||||
Protocol string `help:"force https" choices:"http|https"`
|
||||
}
|
||||
R(&BucketSetWebsiteOption{}, "bucket-set-website", "Set bucket website", func(s *mcclient.ClientSession, args *BucketSetWebsiteOption) error {
|
||||
conf := api.BucketWebsiteConf{
|
||||
Index: args.Index,
|
||||
ErrorDocument: args.ErrorDocument,
|
||||
Protocol: args.Protocol,
|
||||
}
|
||||
result, err := modules.Buckets.PerformAction(s, args.ID, "set-website", jsonutils.Marshal(conf))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(result)
|
||||
return nil
|
||||
})
|
||||
|
||||
type BucketGetWebsiteConfOption struct {
|
||||
ID string `help:"ID or name of bucket" json:"-"`
|
||||
}
|
||||
R(&BucketGetWebsiteConfOption{}, "bucket-get-website", "Get bucket website", func(s *mcclient.ClientSession, args *BucketGetWebsiteConfOption) error {
|
||||
result, err := modules.Buckets.GetSpecific(s, args.ID, "website", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(result)
|
||||
return nil
|
||||
})
|
||||
|
||||
type BucketDeleteWebsiteConfOption struct {
|
||||
ID string `help:"ID or name of bucket" json:"-"`
|
||||
}
|
||||
R(&BucketDeleteWebsiteConfOption{}, "bucket-delete-website", "Delete bucket website", func(s *mcclient.ClientSession, args *BucketDeleteWebsiteConfOption) error {
|
||||
result, err := modules.Buckets.PerformAction(s, args.ID, "delete-website", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(result)
|
||||
return nil
|
||||
})
|
||||
|
||||
type BucketSetCorsOption struct {
|
||||
ID string `help:"ID or name of bucket" json:"-"`
|
||||
AllowedMethods []string `help:"allowed http method" choices:"PUT|GET|POST|DELETE|HEAD"`
|
||||
// 允许的源站,可以设为*
|
||||
AllowedOrigins []string
|
||||
AllowedHeaders []string
|
||||
MaxAgeSeconds int
|
||||
ExposeHeaders []string
|
||||
RuleId string
|
||||
}
|
||||
R(&BucketSetCorsOption{}, "bucket-set-cors", "Set bucket cors", func(s *mcclient.ClientSession, args *BucketSetCorsOption) error {
|
||||
|
||||
rule := api.BucketCORSRule{
|
||||
AllowedOrigins: args.AllowedOrigins,
|
||||
AllowedMethods: args.AllowedMethods,
|
||||
AllowedHeaders: args.AllowedHeaders,
|
||||
MaxAgeSeconds: args.MaxAgeSeconds,
|
||||
ExposeHeaders: args.ExposeHeaders,
|
||||
Id: args.RuleId,
|
||||
}
|
||||
rules := api.BucketCORSRules{Data: []api.BucketCORSRule{rule}}
|
||||
result, err := modules.Buckets.PerformAction(s, args.ID, "set-cors", jsonutils.Marshal(rules))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(result)
|
||||
return nil
|
||||
})
|
||||
|
||||
type BucketGetCorsOption struct {
|
||||
ID string `help:"ID or name of bucket" json:"-"`
|
||||
}
|
||||
R(&BucketGetCorsOption{}, "bucket-get-cors", "Get bucket cors", func(s *mcclient.ClientSession, args *BucketGetCorsOption) error {
|
||||
result, err := modules.Buckets.GetSpecific(s, args.ID, "cors", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(result)
|
||||
return nil
|
||||
})
|
||||
|
||||
type BucketDeleteCorsOption struct {
|
||||
ID string `help:"ID or name of bucket" json:"-"`
|
||||
Id []string `"help:Id of rules to delete"`
|
||||
}
|
||||
R(&BucketDeleteCorsOption{}, "bucket-delete-cors", "Delete bucket cors", func(s *mcclient.ClientSession, args *BucketDeleteCorsOption) error {
|
||||
input := api.BucketCORSRuleDeleteInput{}
|
||||
input.Id = args.Id
|
||||
result, err := modules.Buckets.PerformAction(s, args.ID, "delete-cors", jsonutils.Marshal(input))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(result)
|
||||
return nil
|
||||
})
|
||||
|
||||
type BucketSetRefererOption struct {
|
||||
ID string `help:"ID or name of bucket" json:"-"`
|
||||
// 域名列表
|
||||
DomainList []string
|
||||
// 是否允许空referer 访问
|
||||
AllowEmptyRefer bool `help:"all empty refer access"`
|
||||
Enabled bool
|
||||
RerererType string `help:"Referer type" choices:"Black-List|White-List"`
|
||||
}
|
||||
R(&BucketSetRefererOption{}, "bucket-set-referer", "Set bucket referer", func(s *mcclient.ClientSession, args *BucketSetRefererOption) error {
|
||||
conf := api.BucketRefererConf{
|
||||
Enabled: args.Enabled,
|
||||
AllowEmptyRefer: args.AllowEmptyRefer,
|
||||
RefererType: args.RerererType,
|
||||
DomainList: args.DomainList,
|
||||
}
|
||||
result, err := modules.Buckets.PerformAction(s, args.ID, "set-referer", jsonutils.Marshal(conf))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(result)
|
||||
return nil
|
||||
})
|
||||
|
||||
type BucketGetRefererOption struct {
|
||||
ID string `help:"ID or name of bucket" json:"-"`
|
||||
}
|
||||
R(&BucketGetRefererOption{}, "bucket-get-referer", "get bucket referer", func(s *mcclient.ClientSession, args *BucketGetRefererOption) error {
|
||||
result, err := modules.Buckets.GetSpecific(s, args.ID, "referer", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(result)
|
||||
return nil
|
||||
})
|
||||
|
||||
type BucketGetCdnDomainOption struct {
|
||||
ID string `help:"ID or name of bucket" json:"-"`
|
||||
}
|
||||
R(&BucketGetRefererOption{}, "bucket-get-cdn-domain", "get bucket cdn domain", func(s *mcclient.ClientSession, args *BucketGetRefererOption) error {
|
||||
result, err := modules.Buckets.GetSpecific(s, args.ID, "cdn-domain", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(result)
|
||||
return nil
|
||||
})
|
||||
|
||||
type BucketGetPolicyOption struct {
|
||||
ID string `help:"ID or name of bucket" json:"-"`
|
||||
}
|
||||
R(&BucketGetPolicyOption{}, "bucket-get-policy", "get bucket policy", func(s *mcclient.ClientSession, args *BucketGetPolicyOption) error {
|
||||
result, err := modules.Buckets.GetSpecific(s, args.ID, "policy", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(result)
|
||||
return nil
|
||||
})
|
||||
|
||||
type BucketSetPolicyOption struct {
|
||||
ID string `help:"ID or name of bucket" json:"-"`
|
||||
// 格式主账号id:子账号id
|
||||
PrincipalId []string `help:"ext account id, accountId:subaccountId"`
|
||||
// Read|ReadWrite|FullControl
|
||||
CannedAction string `help:"authority action" choice:"Read|FullControl"`
|
||||
// Allow|Deny
|
||||
Effect string `help:"allow or deny" choice:"Allow|Deny"`
|
||||
// 被授权的资源地址
|
||||
ResourcePath []string
|
||||
// ip 条件
|
||||
IpEquals []string
|
||||
IpNotEquals []string
|
||||
}
|
||||
R(&BucketSetPolicyOption{}, "bucket-set-policy", "set bucket policy", func(s *mcclient.ClientSession, args *BucketSetPolicyOption) error {
|
||||
opts := api.BucketPolicyStatementInput{}
|
||||
opts.CannedAction = args.CannedAction
|
||||
opts.Effect = args.Effect
|
||||
opts.IpEquals = args.IpEquals
|
||||
opts.IpNotEquals = args.IpNotEquals
|
||||
opts.ResourcePath = args.ResourcePath
|
||||
opts.PrincipalId = args.PrincipalId
|
||||
|
||||
result, err := modules.Buckets.PerformAction(s, args.ID, "set-policy", jsonutils.Marshal(opts))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(result)
|
||||
return nil
|
||||
})
|
||||
|
||||
type BucketDeletePolicyOption struct {
|
||||
ID string `help:"ID or name of bucket" json:"-"`
|
||||
Id []string
|
||||
}
|
||||
R(&BucketDeletePolicyOption{}, "bucket-delete-policy", "delete bucket policy", func(s *mcclient.ClientSession, args *BucketDeletePolicyOption) error {
|
||||
input := api.BucketPolicyDeleteInput{}
|
||||
input.Id = args.Id
|
||||
result, err := modules.Buckets.PerformAction(s, args.ID, "delete-policy", jsonutils.Marshal(input))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(result)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ func init() {
|
||||
cmd.Perform("rebuild", &compute_options.DiskRebuildOptions{})
|
||||
cmd.Perform("migrate", &compute_options.DiskMigrateOptions{})
|
||||
cmd.Perform("reset-template", &compute_options.DiskResetTemplateOptions{})
|
||||
cmd.Perform("change-billing-type", new(compute_options.DiskChangeBillingTypeOptions))
|
||||
|
||||
type DiskDetailOptions struct {
|
||||
ID string `help:"ID or Name of disk"`
|
||||
|
||||
31
cmd/climc/shell/compute/hostfiles.go
Normal file
31
cmd/climc/shell/compute/hostfiles.go
Normal file
@@ -0,0 +1,31 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// 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.
|
||||
|
||||
package compute
|
||||
|
||||
import (
|
||||
"yunion.io/x/onecloud/cmd/climc/shell"
|
||||
computemodules "yunion.io/x/onecloud/pkg/mcclient/modules/compute"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/options/compute"
|
||||
)
|
||||
|
||||
func init() {
|
||||
cmd := shell.NewResourceCmd(&computemodules.HostFiles)
|
||||
cmd.List(&compute.HostFileListOptions{})
|
||||
cmd.Create(&compute.HostFileCreateOptions{})
|
||||
cmd.Show(&compute.HostFileShowOptions{})
|
||||
cmd.Update(&compute.HostFileUpdateOptions{})
|
||||
cmd.Edit(&compute.HostFileEditOptions{})
|
||||
cmd.Delete(&compute.HostFileDeleteOptions{})
|
||||
}
|
||||
@@ -55,8 +55,8 @@ func init() {
|
||||
cmd.Perform("class-metadata", &options.ResourceMetadataOptions{})
|
||||
cmd.Perform("set-class-metadata", &options.ResourceMetadataOptions{})
|
||||
cmd.PerformClass("validate-ipmi", &compute.HostValidateIPMI{})
|
||||
cmd.Perform("set-commit-bound", &compute.HostSetCommitBoundOptions{})
|
||||
|
||||
cmd.BatchPerform("set-commit-bound", &compute.HostSetCommitBoundOptions{})
|
||||
cmd.BatchPerform("enable", &options.BaseIdsOptions{})
|
||||
cmd.BatchPerform("disable", &options.BaseIdsOptions{})
|
||||
cmd.BatchPerform("syncstatus", &options.BaseIdsOptions{})
|
||||
@@ -67,6 +67,7 @@ func init() {
|
||||
cmd.BatchPerform("unreserve-cpus", &options.BaseIdsOptions{})
|
||||
cmd.BatchPerform("auto-migrate-on-host-down", &compute.HostAutoMigrateOnHostDownOptions{})
|
||||
cmd.BatchPerform("restart-host-agent", &options.BaseIdsOptions{})
|
||||
cmd.BatchPerform("set-host-files", &compute.HostSetHostFilesOptions{})
|
||||
|
||||
cmd.Get("ipmi", &options.BaseIdOptions{})
|
||||
cmd.Get("vnc", &options.BaseIdOptions{})
|
||||
@@ -93,6 +94,9 @@ func init() {
|
||||
fmt.Println("error", err)
|
||||
}
|
||||
}, &options.BaseIdOptions{})
|
||||
cmd.GetWithCustomShow("host-files", func(data jsonutils.JSONObject) {
|
||||
printObject(data)
|
||||
}, &options.BaseIdOptions{})
|
||||
|
||||
R(&compute.HostShowOptions{}, "host-show", "Show details of a host", func(s *mcclient.ClientSession, args *compute.HostShowOptions) error {
|
||||
params, err := args.Params()
|
||||
|
||||
@@ -165,8 +165,9 @@ func init() {
|
||||
})
|
||||
|
||||
type ServerAttachNetworkOptions struct {
|
||||
SERVER string `help:"ID or Name of server"`
|
||||
NETDESC []string `help:"Network description"`
|
||||
SERVER string `help:"ID or Name of server"`
|
||||
DisableSyncConfig bool `help:"Disable sync config"`
|
||||
NETDESC []string `help:"Network description"`
|
||||
}
|
||||
R(&ServerAttachNetworkOptions{}, "server-attach-network", "Attach a server to a virtual network", func(s *mcclient.ClientSession, args *ServerAttachNetworkOptions) error {
|
||||
input := compute.AttachNetworkInput{}
|
||||
@@ -177,6 +178,7 @@ func init() {
|
||||
}
|
||||
input.Nets = append(input.Nets, conf)
|
||||
}
|
||||
input.DisableSyncConfig = &args.DisableSyncConfig
|
||||
params := jsonutils.Marshal(input)
|
||||
srv, err := modules.Servers.PerformAction(s, args.SERVER, "attachnetwork", params)
|
||||
if err != nil {
|
||||
|
||||
@@ -129,7 +129,7 @@ func init() {
|
||||
cmd.BatchPerform("stop-rescue", &options.ServerStartOptions{})
|
||||
cmd.BatchPerform("sync-os-info", &options.ServerIdsOptions{})
|
||||
cmd.BatchPerform("set-root-disk-matcher", &options.ServerSetRootDiskMatcher{})
|
||||
|
||||
cmd.Perform("disable-auto-merge-snapshot", &options.ServerDisableAutoMergeSnapshot{})
|
||||
cmd.Get("vnc", new(options.ServerVncOptions))
|
||||
cmd.Get("desc", new(options.ServerIdOptions))
|
||||
cmd.Get("status", new(options.ServerIdOptions))
|
||||
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/pkg/util/printutils"
|
||||
"yunion.io/x/pkg/util/shellutils"
|
||||
"yunion.io/x/pkg/utils"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
@@ -544,6 +545,81 @@ func (cmd ResourceCmd) Update(args IUpdateOpt) {
|
||||
cmd.UpdateWithKeyword("update", args)
|
||||
}
|
||||
|
||||
type EditType string
|
||||
|
||||
const (
|
||||
EditTypeText EditType = "text"
|
||||
EditTypeYaml EditType = "yaml"
|
||||
EditTypeJson EditType = "json"
|
||||
)
|
||||
|
||||
type IEditOpt interface {
|
||||
IGetOpt
|
||||
EditType() EditType
|
||||
EditFields() []string
|
||||
}
|
||||
|
||||
func (cmd ResourceCmd) Edit(args IEditOpt) {
|
||||
man := cmd.manager
|
||||
callback := func(s *mcclient.ClientSession, args IEditOpt) error {
|
||||
params, err := args.Params()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
obj, err := man.(modulebase.Manager).Get(s, args.GetId(), params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
format := args.EditType()
|
||||
fields := args.EditFields()
|
||||
var editText string
|
||||
|
||||
switch format {
|
||||
case EditTypeText:
|
||||
editText, _ = obj.GetString(fields...)
|
||||
default:
|
||||
editJson, _ := obj.Get(fields...)
|
||||
if editJson == nil {
|
||||
editJson = jsonutils.NewDict()
|
||||
}
|
||||
if format == EditTypeYaml {
|
||||
editText = editJson.YAMLString()
|
||||
} else if format == EditTypeJson {
|
||||
editText = editJson.PrettyString()
|
||||
}
|
||||
}
|
||||
editText, err = shellutils.Edit(editText)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
updateParams := jsonutils.NewDict()
|
||||
switch format {
|
||||
case EditTypeText:
|
||||
updateParams.Add(jsonutils.NewString(editText), fields...)
|
||||
case EditTypeYaml:
|
||||
yamlObj, err := jsonutils.ParseYAML(editText)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
updateParams.Add(yamlObj, fields...)
|
||||
case EditTypeJson:
|
||||
jsonObj, err := jsonutils.ParseString(editText)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
updateParams.Add(jsonObj, fields...)
|
||||
}
|
||||
updateResult, err := man.(modulebase.Manager).Update(s, args.GetId(), updateParams)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
PrintObject(updateResult)
|
||||
return nil
|
||||
}
|
||||
cmd.Run("edit", args, callback)
|
||||
}
|
||||
|
||||
type IMetadataOpt interface {
|
||||
IIdOpt
|
||||
IOpt
|
||||
|
||||
@@ -1,3 +1,17 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// 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.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
|
||||
31
go.mod
31
go.mod
@@ -12,6 +12,7 @@ require (
|
||||
github.com/bitly/go-simplejson v0.5.0
|
||||
github.com/c-bata/go-prompt v0.2.4
|
||||
github.com/cheggaaa/pb/v3 v3.0.8
|
||||
github.com/containerd/containerd v1.4.1
|
||||
github.com/coredns/coredns v1.3.0
|
||||
github.com/coreos/go-iptables v0.6.0
|
||||
github.com/creack/pty v1.1.18
|
||||
@@ -24,6 +25,7 @@ require (
|
||||
github.com/go-yaml/yaml v2.1.0+incompatible
|
||||
github.com/golang-plus/uuid v1.0.0
|
||||
github.com/golang/mock v1.4.4
|
||||
github.com/golang/protobuf v1.5.3
|
||||
github.com/google/cadvisor v0.38.5
|
||||
github.com/google/gopacket v1.1.17
|
||||
github.com/google/uuid v1.6.0
|
||||
@@ -58,7 +60,7 @@ require (
|
||||
github.com/sevlyar/go-daemon v0.1.5
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible
|
||||
github.com/shirou/gopsutil/v3 v3.22.10
|
||||
github.com/sirupsen/logrus v1.9.0
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
github.com/skip2/go-qrcode v0.0.0-20190110000554-dc11ecdae0a9
|
||||
github.com/smartystreets/goconvey v1.7.2
|
||||
github.com/stretchr/testify v1.9.0
|
||||
@@ -74,14 +76,14 @@ require (
|
||||
go.etcd.io/etcd/client/v3 v3.5.0
|
||||
golang.org/x/crypto v0.19.0
|
||||
golang.org/x/net v0.21.0
|
||||
golang.org/x/sync v0.6.0
|
||||
golang.org/x/sys v0.17.0
|
||||
golang.org/x/sync v0.8.0
|
||||
golang.org/x/sys v0.26.0
|
||||
golang.org/x/text v0.14.0
|
||||
golang.org/x/time v0.5.0
|
||||
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028
|
||||
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230215201556-9c5414ab4bde
|
||||
google.golang.org/grpc v1.62.0
|
||||
google.golang.org/protobuf v1.32.0
|
||||
google.golang.org/protobuf v1.35.1
|
||||
gopkg.in/fatih/set.v0 v0.2.1
|
||||
gopkg.in/ldap.v3 v3.0.3
|
||||
gopkg.in/mail.v2 v2.3.1
|
||||
@@ -93,14 +95,14 @@ 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.20250427071042-3ec467b38f4d
|
||||
yunion.io/x/executor v0.0.0-20241205080005-48f5b1212256
|
||||
yunion.io/x/jsonutils v1.0.1-0.20250406102002-98c9140a9edd
|
||||
yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20250529120044-ca8efb3b0df2
|
||||
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.20250403114914-586e94d39281
|
||||
yunion.io/x/pkg v1.10.4-0.20250519013345-54017bf6c1f0
|
||||
yunion.io/x/s3cli v0.0.0-20241221171442-1c11599d28e1
|
||||
yunion.io/x/sqlchemy v1.1.3-0.20250420094945-40f40c75a31f
|
||||
yunion.io/x/sqlchemy v1.1.3-0.20250531010554-ce98f840b833
|
||||
yunion.io/x/structarg v0.0.0-20231017124457-df4d5009457c
|
||||
)
|
||||
|
||||
@@ -125,7 +127,8 @@ require (
|
||||
github.com/DataDog/dd-trace-go v0.6.1 // indirect
|
||||
github.com/DataDog/zstd v1.3.4 // indirect
|
||||
github.com/Microsoft/azure-vhd-utils v0.0.0-20181115010904-44cbada2ece3 // indirect
|
||||
github.com/Microsoft/go-winio v0.4.15 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||
github.com/Microsoft/hcsshim v0.8.14 // indirect
|
||||
github.com/RoaringBitmap/roaring v0.4.16 // indirect
|
||||
github.com/Shopify/sarama v1.20.0 // indirect
|
||||
github.com/Shopify/toxiproxy v2.1.4+incompatible // indirect
|
||||
@@ -155,9 +158,12 @@ require (
|
||||
github.com/checkpoint-restore/go-criu/v4 v4.1.0 // indirect
|
||||
github.com/cilium/ebpf v0.0.0-20200702112145-1c8d4c9ef775 // indirect
|
||||
github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58 // indirect
|
||||
github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59 // indirect
|
||||
github.com/containerd/console v1.0.0 // indirect
|
||||
github.com/containerd/containerd v1.4.1 // indirect
|
||||
github.com/containerd/continuity v0.4.5 // indirect
|
||||
github.com/containerd/log v0.1.0 // indirect
|
||||
github.com/containerd/ttrpc v1.0.2 // indirect
|
||||
github.com/containerd/typeurl v1.0.1 // indirect
|
||||
github.com/coreos/go-semver v0.3.0 // indirect
|
||||
github.com/coreos/go-systemd/v22 v22.3.2 // indirect
|
||||
github.com/cyphar/filepath-securejoin v0.2.2 // indirect
|
||||
@@ -167,6 +173,7 @@ require (
|
||||
github.com/dnstap/golang-dnstap v0.0.0-20170829151710-2cf77a2b5e11 // indirect
|
||||
github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible // indirect
|
||||
github.com/docker/go-connections v0.4.0 // indirect
|
||||
github.com/docker/go-events v0.0.0-20250114142523-c867878c5e32 // indirect
|
||||
github.com/docker/go-units v0.4.0 // indirect
|
||||
github.com/dustin/go-humanize v1.0.0 // indirect
|
||||
github.com/eapache/go-resiliency v1.1.0 // indirect
|
||||
@@ -195,7 +202,6 @@ require (
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang-plus/errors v1.0.0 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/google/btree v1.0.1 // indirect
|
||||
github.com/google/go-querystring v1.0.0 // indirect
|
||||
@@ -292,6 +298,7 @@ require (
|
||||
github.com/xuri/efp v0.0.0-20220603152613-6918739fd470 // indirect
|
||||
github.com/xuri/nfp v0.0.0-20220409054826-5e722a1d9e22 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.2 // indirect
|
||||
go.etcd.io/bbolt v1.3.7 // indirect
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.0 // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.48.0 // indirect
|
||||
|
||||
70
go.sum
70
go.sum
@@ -93,8 +93,12 @@ github.com/LeeEirc/terminalparser v0.0.0-20240205084113-fbf78c8480f2 h1:XGB3B065
|
||||
github.com/LeeEirc/terminalparser v0.0.0-20240205084113-fbf78c8480f2/go.mod h1:tiLv6VBLH4Z3KdBSe2qIKRwQDGCVQ9/F5fOKpQGvyoA=
|
||||
github.com/Microsoft/azure-vhd-utils v0.0.0-20181115010904-44cbada2ece3 h1:gImoAO1xAcC1oDlYmD/X7dggsodGf2DFJOVE5m0ssms=
|
||||
github.com/Microsoft/azure-vhd-utils v0.0.0-20181115010904-44cbada2ece3/go.mod h1:u0H9gMieFLxkUy8RS0X8VbFWyPs2815qQAaitRbj6x0=
|
||||
github.com/Microsoft/go-winio v0.4.15 h1:qkLXKzb1QoVatRyd/YlXZ/Kg0m5K3SPuoD82jjSOaBc=
|
||||
github.com/Microsoft/go-winio v0.4.15/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw=
|
||||
github.com/Microsoft/go-winio v0.4.16-0.20201130162521-d1ffc52c7331/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0=
|
||||
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
||||
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
||||
github.com/Microsoft/hcsshim v0.8.14 h1:lbPVK25c1cu5xTLITwpUcxoA9vKrKErASPYygvouJns=
|
||||
github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2ow3VK6a9Lg=
|
||||
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
|
||||
github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
@@ -207,6 +211,7 @@ github.com/cheggaaa/pb/v3 v3.0.8/go.mod h1:UICbiLec/XO6Hw6k+BHEtHeQFzzBH4i2/qk/o
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3/go.mod h1:MA5e5Lr8slmEg9bt0VpxxWqJlO4iwu3FBdHUzV7wQVg=
|
||||
github.com/cilium/ebpf v0.0.0-20200702112145-1c8d4c9ef775 h1:cHzBGGVew0ezFsq2grfy2RsB8hO/eNyBgOLHBCqfR1U=
|
||||
github.com/cilium/ebpf v0.0.0-20200702112145-1c8d4c9ef775/go.mod h1:7cR51M8ViRLIdUjrmSXlK9pkrsDlLHbO8jiB8X8JnOc=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
@@ -216,12 +221,25 @@ github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGX
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa h1:jQCWAUqqlij9Pgj2i/PB79y4KOPYVyFYdROxgaCwdTQ=
|
||||
github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa/go.mod h1:x/1Gn8zydmfq8dk6e9PdstVsDgu9RuyIIJqAaF//0IM=
|
||||
github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59 h1:qWj4qVYZ95vLWwqyNJCQg7rDsG5wPdze0UaPolH7DUk=
|
||||
github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59/go.mod h1:pA0z1pT8KYB3TCXK/ocprsh7MAkoW8bZVzPdih9snmM=
|
||||
github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw=
|
||||
github.com/containerd/console v1.0.0 h1:fU3UuQapBs+zLJu82NhR11Rif1ny2zfMMAyPJzSN5tQ=
|
||||
github.com/containerd/console v1.0.0/go.mod h1:8Pf4gM6VEbTNRIT26AyyU7hxdQU3MvAvxVI0sc00XBE=
|
||||
github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
|
||||
github.com/containerd/containerd v1.4.1 h1:pASeJT3R3YyVn+94qEPk0SnU1OQ20Jd/T+SPKy9xehY=
|
||||
github.com/containerd/containerd v1.4.1/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
|
||||
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
|
||||
github.com/containerd/continuity v0.4.5 h1:ZRoN1sXq9u7V6QoHMcVWGhOwDFqZ4B9i5H6un1Wh0x4=
|
||||
github.com/containerd/continuity v0.4.5/go.mod h1:/lNJvtJKUQStBzpVQ1+rasXO1LAWtUQssk28EZvJ3nE=
|
||||
github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI=
|
||||
github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0=
|
||||
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
|
||||
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
|
||||
github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o=
|
||||
github.com/containerd/ttrpc v1.0.2 h1:2/O3oTZN36q2xRolk0a2WWGgh7/Vf/liElg5hFYLX9U=
|
||||
github.com/containerd/ttrpc v1.0.2/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y=
|
||||
github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc=
|
||||
github.com/containerd/typeurl v1.0.1 h1:PvuK4E3D5S5q6IqsPDCy928FhP0LUIGcmZ/Yhgp5Djw=
|
||||
github.com/containerd/typeurl v1.0.1/go.mod h1:TB1hUtrpaiO88KEK56ijojHS1+NeF0izUACaJW2mdXg=
|
||||
github.com/coredns/coredns v1.3.0 h1:Ubjr8ZrOpEj95/A9dqQqQAG2k5DWEFdg2ZB3tUXuULA=
|
||||
@@ -230,10 +248,12 @@ github.com/coreos/go-iptables v0.6.0 h1:is9qnZMPYjLd8LYqmm/qlE+wwEgJIkTYdhV3rfZo
|
||||
github.com/coreos/go-iptables v0.6.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q=
|
||||
github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM=
|
||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
|
||||
github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
|
||||
github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI=
|
||||
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
|
||||
github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
|
||||
@@ -256,6 +276,8 @@ github.com/docker/docker v20.10.27+incompatible h1:Id/ZooynV4ZlD6xX20RCd3SR0Ikn7
|
||||
github.com/docker/docker v20.10.27+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
|
||||
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
||||
github.com/docker/go-events v0.0.0-20250114142523-c867878c5e32 h1:EHZfspsnLAz8Hzccd67D5abwLiqoqym2jz/jOS39mCk=
|
||||
github.com/docker/go-events v0.0.0-20250114142523-c867878c5e32/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA=
|
||||
github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
|
||||
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96 h1:cenwrSVm+Z7QLSV/BsnenAOcDXdX4cMv4wP0B/5QbPg=
|
||||
@@ -669,12 +691,15 @@ github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGV
|
||||
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 h1:lDH9UUVJtmYCjyT0CI4q8xvlXPxeZ0gYCVvWbmPlp88=
|
||||
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
|
||||
github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||
github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI=
|
||||
github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
|
||||
github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
|
||||
github.com/opencontainers/runc v1.0.0-rc92 h1:+IczUKCRzDzFDnw99O/PAqrcBBCoRp9xN3cB1SYSNS4=
|
||||
github.com/opencontainers/runc v1.0.0-rc92/go.mod h1:X1zlU4p7wOlX4+WRCz+hvlRv8phdL7UqbYD+vQwNMmE=
|
||||
github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
github.com/opencontainers/runtime-spec v1.0.3-0.20200728170252-4d89ac9fbff6 h1:NhsM2gc769rVWDqJvapK37r+7+CBXI8xHhnfnt8uQsg=
|
||||
github.com/opencontainers/runtime-spec v1.0.3-0.20200728170252-4d89ac9fbff6/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
github.com/opencontainers/selinux v1.6.0 h1:+bIAS/Za3q5FTwWym4fTB0vObnfCf3G/NC7K6Jx62mY=
|
||||
@@ -727,6 +752,7 @@ github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB8
|
||||
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
|
||||
github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4=
|
||||
github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
|
||||
github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
@@ -773,8 +799,9 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx
|
||||
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
|
||||
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/skip2/go-qrcode v0.0.0-20190110000554-dc11ecdae0a9 h1:lpEzuenPuO1XNTeikEmvqYFcU37GVLl8SRNblzyvGBE=
|
||||
github.com/skip2/go-qrcode v0.0.0-20190110000554-dc11ecdae0a9/go.mod h1:PLPIyL7ikehBD1OAjmKKiOEhbvWyHGaNDjquXMcYABo=
|
||||
github.com/smartystreets/assertions v0.0.0-20180607162144-eb5b59917fa2/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
@@ -840,6 +867,7 @@ github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLY
|
||||
github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc=
|
||||
github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
github.com/vishvananda/netlink v1.1.0 h1:1iyaYNBLmP6L0220aDnYQpo1QEV4t4hJ+xEEhhJH8j0=
|
||||
github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
|
||||
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU=
|
||||
@@ -879,6 +907,8 @@ github.com/zexi/influxql-to-metricsql v0.1.1 h1:dXnVzlxVLuo88zGkDca7erEnmvprGWjz
|
||||
github.com/zexi/influxql-to-metricsql v0.1.1/go.mod h1:JlC5FY+6De9ZPxG47G5DOgva8P9X1VaKS4ExzCmhSCc=
|
||||
github.com/zexi/promql/v2 v2.12.1 h1:crHKpULdLLsBZ9b78Rg6qQkugzlk6BHeCj93tw/F5RU=
|
||||
github.com/zexi/promql/v2 v2.12.1/go.mod h1:2UtzWZGmth95n2qdIZWpJ5yQ0cE5hEvz0dGsajI1Sqg=
|
||||
go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ=
|
||||
go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw=
|
||||
go.etcd.io/etcd/api/v3 v3.5.0 h1:GsV3S+OfZEOCNXdtNkBSR7kgLobAa/SO6tCxRa0GAYw=
|
||||
go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.0 h1:2aQv6F436YnN7I4VbI8PPYrBhu+SmrTaADcf8Mi/6PU=
|
||||
@@ -984,6 +1014,7 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
|
||||
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
@@ -1032,8 +1063,8 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
|
||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
|
||||
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20180724212812-e072cadbbdc8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -1059,6 +1090,7 @@ golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -1089,6 +1121,7 @@ golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201110211018-35f3e6cf4a65/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -1107,8 +1140,8 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
|
||||
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
@@ -1269,6 +1302,7 @@ google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiq
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
@@ -1294,8 +1328,8 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
|
||||
google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
|
||||
google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
|
||||
@@ -1376,13 +1410,13 @@ 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.20250427071042-3ec467b38f4d h1:RnK6jhPwXRkQUDRL96YV7qeKbGq5zSZ2SQ/T6Jur574=
|
||||
yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20250427071042-3ec467b38f4d/go.mod h1:FXxAEbdNfWXX9gjME3K2nJhkydHY5EKEUZb+RLEzVwQ=
|
||||
yunion.io/x/executor v0.0.0-20241205080005-48f5b1212256 h1:kLKQ6zbgPDQflRwoHFAjxNChcbhXIFgsUVLkJwiXu/8=
|
||||
yunion.io/x/executor v0.0.0-20241205080005-48f5b1212256/go.mod h1:Uxuou9WQIeJXNpy7t2fPLL0BYLvLiMvGQwY7Qc6aSws=
|
||||
yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20250529120044-ca8efb3b0df2 h1:6hV5gSWYcFJAsIMVONNXKU/S0kzbrrdYWSx++RX8B4s=
|
||||
yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20250529120044-ca8efb3b0df2/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=
|
||||
yunion.io/x/jsonutils v1.0.1-0.20250406102002-98c9140a9edd h1:FWwB4CXiyIrh2YvxPliC9ZmrzXcFv+nuG3lhpipR4Sk=
|
||||
yunion.io/x/jsonutils v1.0.1-0.20250406102002-98c9140a9edd/go.mod h1:VK4Z93dgiKgAijcSqbMKmGaBMJuHulR16Hz4K015ZPo=
|
||||
yunion.io/x/jsonutils v1.0.1-0.20250507052344-1abcf4f443b1 h1:/+THlvf/MvgCW+7KeCDCr33e81KSRa5JmdZ1IIyLOXQ=
|
||||
yunion.io/x/jsonutils v1.0.1-0.20250507052344-1abcf4f443b1/go.mod h1:VK4Z93dgiKgAijcSqbMKmGaBMJuHulR16Hz4K015ZPo=
|
||||
yunion.io/x/log v0.0.0-20190514041436-04ce53b17c6b/go.mod h1:+gauLs73omeJAPlsXcevLsJLKixV+sR/E7WSYTSx1fE=
|
||||
yunion.io/x/log v0.0.0-20190629062853-9f6483a7103d/go.mod h1:LC6f/4FozL0iaAbnFt2eDX9jlsyo3WiOUPm03d7+U4U=
|
||||
yunion.io/x/log v1.0.1-0.20240305175729-7cf2d6cd5a91 h1:inY5o3LDa/zgsIZuPN0HmpzKIsu/lLgsBmMttuDPGj4=
|
||||
@@ -1391,11 +1425,11 @@ 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.20250403114914-586e94d39281 h1:P22/MaBc9bqE9DyHvS3oQjc4XsaIEbIVGMLdTSroDew=
|
||||
yunion.io/x/pkg v1.10.4-0.20250403114914-586e94d39281/go.mod h1:0Bwxqd9MA3ACi119/l02FprY/o9gHahmYC2bsSbnVpM=
|
||||
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/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.20250420094945-40f40c75a31f h1:xuy9a8Hg0d8dfD8j13f687eKPCxEvttgpLQWb4NvKpI=
|
||||
yunion.io/x/sqlchemy v1.1.3-0.20250420094945-40f40c75a31f/go.mod h1:vCIZpqhZ5Jzaq3tFyrti/vv8BijQKtkzSgNT/uH4H5A=
|
||||
yunion.io/x/sqlchemy v1.1.3-0.20250531010554-ce98f840b833 h1:XTFC1naKYkciCQDLm9izpzHXfTenmmtYsTpVKrsN5hE=
|
||||
yunion.io/x/sqlchemy v1.1.3-0.20250531010554-ce98f840b833/go.mod h1:vCIZpqhZ5Jzaq3tFyrti/vv8BijQKtkzSgNT/uH4H5A=
|
||||
yunion.io/x/structarg v0.0.0-20231017124457-df4d5009457c h1:QuLab2kSRECZRxo4Lo2KcYn6XjQFDGaZ1+x0pYDVVwQ=
|
||||
yunion.io/x/structarg v0.0.0-20231017124457-df4d5009457c/go.mod h1:EP6NSv2C0zzqBDTKumv8hPWLb3XvgMZDHQRfyuOrQng=
|
||||
|
||||
@@ -15,28 +15,5 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
_ "yunion.io/x/onecloud/pkg/mcclient/modules/ansible"
|
||||
_ "yunion.io/x/onecloud/pkg/mcclient/modules/cloudevent"
|
||||
_ "yunion.io/x/onecloud/pkg/mcclient/modules/cloudid"
|
||||
_ "yunion.io/x/onecloud/pkg/mcclient/modules/cloudnet"
|
||||
_ "yunion.io/x/onecloud/pkg/mcclient/modules/cloudproxy"
|
||||
modules "yunion.io/x/onecloud/pkg/mcclient/modules/compute"
|
||||
_ "yunion.io/x/onecloud/pkg/mcclient/modules/devtool"
|
||||
_ "yunion.io/x/onecloud/pkg/mcclient/modules/etcd"
|
||||
_ "yunion.io/x/onecloud/pkg/mcclient/modules/identity"
|
||||
_ "yunion.io/x/onecloud/pkg/mcclient/modules/image"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/modules/k8s"
|
||||
_ "yunion.io/x/onecloud/pkg/mcclient/modules/logger"
|
||||
_ "yunion.io/x/onecloud/pkg/mcclient/modules/monitor"
|
||||
_ "yunion.io/x/onecloud/pkg/mcclient/modules/notify"
|
||||
_ "yunion.io/x/onecloud/pkg/mcclient/modules/quota"
|
||||
_ "yunion.io/x/onecloud/pkg/mcclient/modules/scheduledtask"
|
||||
_ "yunion.io/x/onecloud/pkg/mcclient/modules/scheduler"
|
||||
_ "yunion.io/x/onecloud/pkg/mcclient/modules/webconsole"
|
||||
_ "yunion.io/x/onecloud/pkg/mcclient/modules/yunionconf"
|
||||
_ "yunion.io/x/onecloud/pkg/mcclient/modules/loader"
|
||||
)
|
||||
|
||||
func init() {
|
||||
modules.InitUsages()
|
||||
modules.Usages.RegisterManager(modules.UsageManagerK8s, k8s.Usages)
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ package compute
|
||||
import (
|
||||
"net/http"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/cloudmux/pkg/apis/compute"
|
||||
"yunion.io/x/cloudmux/pkg/cloudprovider"
|
||||
@@ -53,6 +54,8 @@ type BucketCreateInput struct {
|
||||
CloudproviderResourceInput
|
||||
|
||||
StorageClass string `json:"storage_class"`
|
||||
|
||||
EnablePerfMon *bool `json:"enable_perf_mon"`
|
||||
}
|
||||
|
||||
type BucketDetails struct {
|
||||
@@ -66,28 +69,28 @@ type BucketDetails struct {
|
||||
AccessUrls []cloudprovider.SBucketAccessUrl `json:"access_urls"`
|
||||
}
|
||||
|
||||
func (self BucketDetails) GetMetricTags() map[string]string {
|
||||
func (bucket BucketDetails) GetMetricTags() map[string]string {
|
||||
ret := map[string]string{
|
||||
"id": self.Id,
|
||||
"brand": self.Brand,
|
||||
"cloudregion": self.Cloudregion,
|
||||
"cloudregion_id": self.CloudregionId,
|
||||
"domain_id": self.DomainId,
|
||||
"oss_id": self.Id,
|
||||
"oss_name": self.Name,
|
||||
"project_domain": self.ProjectDomain,
|
||||
"region_ext_id": self.RegionExtId,
|
||||
"status": self.Status,
|
||||
"tenant": self.Project,
|
||||
"tenant_id": self.ProjectId,
|
||||
"account": self.Account,
|
||||
"account_id": self.AccountId,
|
||||
"external_id": self.ExternalId,
|
||||
"id": bucket.Id,
|
||||
"brand": bucket.Brand,
|
||||
"cloudregion": bucket.Cloudregion,
|
||||
"cloudregion_id": bucket.CloudregionId,
|
||||
"domain_id": bucket.DomainId,
|
||||
"oss_id": bucket.Id,
|
||||
"oss_name": bucket.Name,
|
||||
"project_domain": bucket.ProjectDomain,
|
||||
"region_ext_id": bucket.RegionExtId,
|
||||
"status": bucket.Status,
|
||||
"tenant": bucket.Project,
|
||||
"tenant_id": bucket.ProjectId,
|
||||
"account": bucket.Account,
|
||||
"account_id": bucket.AccountId,
|
||||
"external_id": bucket.ExternalId,
|
||||
}
|
||||
return AppendMetricTags(ret, self.MetadataResourceInfo, self.ProjectizedResourceInfo)
|
||||
return AppendMetricTags(ret, bucket.MetadataResourceInfo, bucket.ProjectizedResourceInfo)
|
||||
}
|
||||
|
||||
func (self BucketDetails) GetMetricPairs() map[string]string {
|
||||
func (bucket BucketDetails) GetMetricPairs() map[string]string {
|
||||
ret := map[string]string{}
|
||||
return ret
|
||||
}
|
||||
@@ -150,6 +153,8 @@ type BucketSyncstatusInput struct {
|
||||
|
||||
type BucketUpdateInput struct {
|
||||
apis.SharableVirtualResourceBaseUpdateInput
|
||||
|
||||
EnablePerfMon *bool `json:"enable_perf_mon"`
|
||||
}
|
||||
|
||||
type BucketPerformTempUrlInput struct {
|
||||
@@ -370,3 +375,29 @@ func init() {
|
||||
return &SBackupStorageAccessInfo{}
|
||||
})
|
||||
}
|
||||
|
||||
type BucketProbeResult struct {
|
||||
UploadTime time.Duration
|
||||
DownloadTime time.Duration
|
||||
DeleteTime time.Duration
|
||||
}
|
||||
|
||||
func (result BucketProbeResult) UploadDelayMs() float64 {
|
||||
return float64(result.UploadTime) / float64(time.Millisecond)
|
||||
}
|
||||
|
||||
func (result BucketProbeResult) DownloadDelayMs() float64 {
|
||||
return float64(result.DownloadTime) / float64(time.Millisecond)
|
||||
}
|
||||
|
||||
func (result BucketProbeResult) DeleteDelayMs() float64 {
|
||||
return float64(result.DeleteTime) / float64(time.Millisecond)
|
||||
}
|
||||
|
||||
func (result BucketProbeResult) UploadThroughputMbps(sizeMBytes int) float64 {
|
||||
return float64(sizeMBytes) * 8 / float64(result.UploadTime.Seconds())
|
||||
}
|
||||
|
||||
func (result BucketProbeResult) DownloadThroughputMbps(sizeMBytes int) float64 {
|
||||
return float64(sizeMBytes) * 8 / float64(result.DownloadTime.Seconds())
|
||||
}
|
||||
|
||||
@@ -75,6 +75,7 @@ const (
|
||||
CLOUD_PROVIDER_ZETTAKIT = compute.CLOUD_PROVIDER_ZETTAKIT
|
||||
CLOUD_PROVIDER_UIS = compute.CLOUD_PROVIDER_UIS
|
||||
CLOUD_PROVIDER_CAS = compute.CLOUD_PROVIDER_CAS
|
||||
CLOUD_PROVIDER_CLOUDFLARE = compute.CLOUD_PROVIDER_CLOUDFLARE
|
||||
|
||||
CLOUD_PROVIDER_GENERICS3 = compute.CLOUD_PROVIDER_GENERICS3
|
||||
CLOUD_PROVIDER_CEPH = compute.CLOUD_PROVIDER_CEPH
|
||||
@@ -143,6 +144,7 @@ var (
|
||||
CLOUD_PROVIDER_JDCLOUD,
|
||||
CLOUD_PROVIDER_VOLCENGINE,
|
||||
CLOUD_PROVIDER_ORACLE,
|
||||
CLOUD_PROVIDER_CLOUDFLARE,
|
||||
}
|
||||
|
||||
CLOUD_PROVIDERS = []string{
|
||||
@@ -181,6 +183,7 @@ var (
|
||||
CLOUD_PROVIDER_ZETTAKIT,
|
||||
CLOUD_PROVIDER_UIS,
|
||||
CLOUD_PROVIDER_CAS,
|
||||
CLOUD_PROVIDER_CLOUDFLARE,
|
||||
}
|
||||
|
||||
CLOUD_PROVIDER_HOST_TYPE_MAP = map[string][]string{
|
||||
|
||||
@@ -130,6 +130,7 @@ const (
|
||||
type ContainerSpec struct {
|
||||
apis.ContainerSpec
|
||||
// Volume mounts
|
||||
RootFs *apis.ContainerRootfs `json:"rootfs"`
|
||||
VolumeMounts []*apis.ContainerVolumeMount `json:"volume_mounts"`
|
||||
Devices []*ContainerDevice `json:"devices"`
|
||||
}
|
||||
@@ -207,6 +208,8 @@ type ContainerSaveVolumeMountToImageInput struct {
|
||||
Index int `json:"index"`
|
||||
Dirs []string `json:"dirs"`
|
||||
UsedByPostOverlay bool `json:"used_by_post_overlay"`
|
||||
|
||||
DirPrefix string `json:"dir_prefix"`
|
||||
}
|
||||
|
||||
type ContainerExecInfoOutput struct {
|
||||
|
||||
@@ -376,3 +376,11 @@ func (d *DiskFsFeatures) IsZero() bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type DiskChangeBillingTypeInput struct {
|
||||
// 仅在磁盘挂载在虚拟机上时调用
|
||||
// 目前支持阿里云
|
||||
// enmu: [postpaid, prepaid]
|
||||
// required: true
|
||||
BillingType string `json:"billing_type"`
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ type DnsRecordCreateInput struct {
|
||||
DnsValue string `json:"dns_value"`
|
||||
TTL int64 `json:"ttl"`
|
||||
MxPriority int64 `json:"mx_priority"`
|
||||
Proxied *bool `json:"proxied"`
|
||||
|
||||
PolicyType string `json:"policy_type"`
|
||||
PolicyValue string `json:"policy_value"`
|
||||
@@ -48,6 +49,7 @@ type DnsRecordUpdateInput struct {
|
||||
DnsValue string `json:"dns_value"`
|
||||
TTL *int64 `json:"ttl"`
|
||||
MxPriority *int64 `json:"mx_priority"`
|
||||
Proxied *bool `json:"proxied"`
|
||||
}
|
||||
|
||||
type DnsRecordDetails struct {
|
||||
|
||||
@@ -180,10 +180,6 @@ const (
|
||||
VM_QGA_SET_NETWORK = "qga_set_network"
|
||||
VM_QGA_SET_NETWORK_FAILED = "qga_set_network_failed"
|
||||
|
||||
// 更改计费模式
|
||||
VM_CHANGE_BILLING_TYPE = "change_billing_type"
|
||||
VM_CHANGE_BILLING_TYPE_FAILED = "change_billing_type_failed"
|
||||
|
||||
SHUTDOWN_STOP = "stop"
|
||||
SHUTDOWN_TERMINATE = "terminate"
|
||||
SHUTDOWN_STOP_RELEASE_GPU = "stop_release_gpu"
|
||||
@@ -265,6 +261,9 @@ const (
|
||||
VM_VIDEO_STANDARD = "std"
|
||||
VM_VIDEO_QXL = "qxl"
|
||||
VM_VIDEO_VIRTIO = "virtio"
|
||||
|
||||
VM_BOOT_MODE_BIOS = "BIOS"
|
||||
VM_BOOT_MODE_UEFI = "UEFI"
|
||||
)
|
||||
|
||||
var VM_RUNNING_STATUS = []string{VM_START_START, VM_STARTING, VM_RUNNING, VM_BLOCK_STREAM, VM_BLOCK_STREAM_FAIL}
|
||||
@@ -317,22 +316,23 @@ const (
|
||||
VM_AZURE_DEFAULT_LOGIN_USER = compute.VM_AZURE_DEFAULT_LOGIN_USER
|
||||
VM_ZSTACK_DEFAULT_LOGIN_USER = compute.VM_ZSTACK_DEFAULT_LOGIN_USER
|
||||
|
||||
VM_METADATA_APP_TAGS = "app_tags"
|
||||
VM_METADATA_CREATE_PARAMS = "create_params"
|
||||
VM_METADATA_LOGIN_ACCOUNT = "login_account"
|
||||
VM_METADATA_LOGIN_KEY = "login_key"
|
||||
VM_METADATA_LAST_LOGIN_KEY = "last_login_key"
|
||||
VM_METADATA_LOGIN_KEY_TIMESTAMP = "login_key_timestamp"
|
||||
VM_METADATA_OS_ARCH = "os_arch"
|
||||
VM_METADATA_OS_DISTRO = "os_distribution"
|
||||
VM_METADATA_OS_NAME = "os_name"
|
||||
VM_METADATA_OS_VERSION = "os_version"
|
||||
VM_METADATA_CGROUP_CPUSET = "cgroup_cpuset"
|
||||
VM_METADATA_ENABLE_MEMCLEAN = "enable_memclean"
|
||||
VM_METADATA_HOTPLUG_CPU_MEM = "hotplug_cpu_mem"
|
||||
VM_METADATA_HOT_REMOVE_NIC = "hot_remove_nic"
|
||||
VM_METADATA_START_VMEM_MB = "start_vmem_mb"
|
||||
VM_METADATA_START_VCPU_COUNT = "start_vcpu_count"
|
||||
VM_METADATA_APP_TAGS = "app_tags"
|
||||
VM_METADATA_CREATE_PARAMS = "create_params"
|
||||
VM_METADATA_LOGIN_ACCOUNT = "login_account"
|
||||
VM_METADATA_LOGIN_KEY = "login_key"
|
||||
VM_METADATA_LAST_LOGIN_KEY = "last_login_key"
|
||||
VM_METADATA_LOGIN_KEY_TIMESTAMP = "login_key_timestamp"
|
||||
VM_METADATA_OS_ARCH = "os_arch"
|
||||
VM_METADATA_OS_DISTRO = "os_distribution"
|
||||
VM_METADATA_OS_NAME = "os_name"
|
||||
VM_METADATA_OS_VERSION = "os_version"
|
||||
VM_METADATA_CGROUP_CPUSET = "cgroup_cpuset"
|
||||
VM_METADATA_ENABLE_MEMCLEAN = "enable_memclean"
|
||||
VM_METADATA_HOTPLUG_CPU_MEM = "hotplug_cpu_mem"
|
||||
VM_METADATA_HOT_REMOVE_NIC = "hot_remove_nic"
|
||||
VM_METADATA_START_VMEM_MB = "start_vmem_mb"
|
||||
VM_METADATA_START_VCPU_COUNT = "start_vcpu_count"
|
||||
VM_METADATA_DISABLE_AUTO_MERGE_SNAPSHOT = "disable_auto_merge_snapshot"
|
||||
|
||||
VM_METADATA_RELEASED_DEVICES = "released_devices"
|
||||
|
||||
|
||||
@@ -324,6 +324,8 @@ func (self ServerDetails) GetMetricTags() map[string]string {
|
||||
"paltform": self.Hypervisor,
|
||||
"host": self.Host,
|
||||
"host_id": self.HostId,
|
||||
"ips": self.IPs,
|
||||
"vm_ip": self.IPs,
|
||||
"vm_id": self.Id,
|
||||
"vm_name": self.Name,
|
||||
"zone": self.Zone,
|
||||
@@ -377,6 +379,7 @@ type GuestDiskInfo struct {
|
||||
MediumType string `json:"medium_type"`
|
||||
StorageType string `json:"storage_type"`
|
||||
Iops int `json:"iops"`
|
||||
Throughput int `json:"throughput"`
|
||||
Bps int `json:"bps"`
|
||||
ImageId string `json:"image_id,omitempty"`
|
||||
Image string `json:"image,omitemtpy"`
|
||||
@@ -1201,7 +1204,7 @@ type ServerQgaGetNetworkInput struct {
|
||||
}
|
||||
|
||||
type ServerQgaTimeoutInput struct {
|
||||
// qga execute timeout millisecond
|
||||
// qga execute timeout second
|
||||
Timeout int
|
||||
}
|
||||
|
||||
@@ -1421,3 +1424,8 @@ type ServerChangeBillingTypeInput struct {
|
||||
// required: true
|
||||
BillingType string `json:"billing_type"`
|
||||
}
|
||||
|
||||
type ServerPerformStatusInput struct {
|
||||
apis.PerformStatusInput
|
||||
Containers map[string]*ContainerPerformStatusInput `json:"containers"`
|
||||
}
|
||||
|
||||
@@ -250,6 +250,8 @@ type HostDetails struct {
|
||||
SysWarn string `json:"sys_warn"`
|
||||
// host init error info
|
||||
SysError string `json:"sys_error"`
|
||||
|
||||
HostFiles []string `json:"host_files"`
|
||||
}
|
||||
|
||||
func (self HostDetails) GetMetricTags() map[string]string {
|
||||
@@ -711,13 +713,13 @@ type HostUploadGuestsStatusRequest struct {
|
||||
GuestIds []string `json:"guest_ids"`
|
||||
}
|
||||
|
||||
type HostUploadGuestStatusResponse struct {
|
||||
type HostUploadGuestStatusInput struct {
|
||||
apis.PerformStatusInput
|
||||
Containers map[string]*ContainerPerformStatusInput `json:"containers"`
|
||||
}
|
||||
|
||||
type HostUploadGuestsStatusResponse struct {
|
||||
Guests map[string]*HostUploadGuestStatusResponse `json:"guests"`
|
||||
type HostUploadGuestsStatusInput struct {
|
||||
Guests map[string]*HostUploadGuestStatusInput `json:"guests"`
|
||||
}
|
||||
|
||||
type GuestUploadContainerStatusResponse struct {
|
||||
|
||||
62
pkg/apis/compute/hostfile.go
Normal file
62
pkg/apis/compute/hostfile.go
Normal file
@@ -0,0 +1,62 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// 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.
|
||||
|
||||
package compute
|
||||
|
||||
import (
|
||||
"yunion.io/x/onecloud/pkg/apis"
|
||||
)
|
||||
|
||||
type HostFileType string
|
||||
|
||||
const (
|
||||
PlainFile HostFileType = "plain"
|
||||
ScriptFile HostFileType = "script"
|
||||
TelegrafConf HostFileType = "telegraf"
|
||||
ApparmorProfile HostFileType = "apparmor"
|
||||
)
|
||||
|
||||
type HostFileCreateInput struct {
|
||||
apis.InfrasResourceBaseCreateInput
|
||||
|
||||
Path string `json:"path" help:"Path of the host file"`
|
||||
Content string `json:"content" help:"Content of the host file"`
|
||||
Type HostFileType `json:"type" help:"Type of the host file"`
|
||||
}
|
||||
|
||||
type HostFileUpdateInput struct {
|
||||
apis.InfrasResourceBaseUpdateInput
|
||||
|
||||
Path string `json:"path"`
|
||||
Content string `json:"content"`
|
||||
}
|
||||
|
||||
type HostFileListInput struct {
|
||||
apis.InfrasResourceBaseListInput
|
||||
|
||||
Type []string `json:"type"`
|
||||
Path string `json:"path"`
|
||||
}
|
||||
|
||||
type HostSetHostFilesInput struct {
|
||||
HostFiles []string `json:"host_files"`
|
||||
}
|
||||
|
||||
type HostFileDetails struct {
|
||||
apis.InfrasResourceBaseDetails
|
||||
|
||||
Hosts []string `json:"hosts"`
|
||||
|
||||
SHostFile
|
||||
}
|
||||
@@ -255,6 +255,8 @@ type SecgroupResourceInput struct {
|
||||
|
||||
type SecgroupFilterListInput struct {
|
||||
SecgroupResourceInput
|
||||
RegionalFilterListInput
|
||||
ManagedResourceListInput
|
||||
|
||||
// 以安全组排序
|
||||
OrderBySecgroup string `json:"order_by_secgroup"`
|
||||
@@ -291,6 +293,16 @@ type SecgroupDetails struct {
|
||||
type SecurityGroupResourceInfo struct {
|
||||
// 安全组名称
|
||||
Secgroup string `json:"secgroup"`
|
||||
|
||||
// VPC归属区域ID
|
||||
CloudregionId string `json:"cloudregion_id"`
|
||||
|
||||
CloudregionResourceInfo
|
||||
|
||||
// VPC归属云订阅ID
|
||||
ManagerId string `json:"manager_id"`
|
||||
|
||||
ManagedResourceInfo
|
||||
}
|
||||
|
||||
type GuestsecgroupListInput struct {
|
||||
|
||||
@@ -74,6 +74,8 @@ const (
|
||||
STORAGE_CLOUD_BASIC = compute.STORAGE_CLOUD_BASIC
|
||||
STORAGE_CLOUD_PREMIUM = compute.STORAGE_CLOUD_PREMIUM //高性能云硬盘
|
||||
STORAGE_CLOUD_HSSD = compute.STORAGE_CLOUD_HSSD //增强型SSD云硬盘
|
||||
STORAGE_CLOUD_BSSD = compute.STORAGE_CLOUD_BSSD //增强型SSD云硬盘
|
||||
STORAGE_CLOUD_TSSD = compute.STORAGE_CLOUD_TSSD //极速型SSD云硬盘
|
||||
|
||||
// huawei storage type
|
||||
STORAGE_HUAWEI_SSD = compute.STORAGE_HUAWEI_SSD // 超高IO云硬盘
|
||||
|
||||
@@ -247,7 +247,6 @@ type SCloudaccount struct {
|
||||
// 云系统信息
|
||||
Sysinfo jsonutils.JSONObject `json:"sysinfo"`
|
||||
// 品牌信息, 一般和provider相同
|
||||
// example: DStack
|
||||
Brand string `json:"brand"`
|
||||
// 额外信息
|
||||
Options *jsonutils.JSONDict `json:"options"`
|
||||
@@ -568,6 +567,8 @@ type SDisk struct {
|
||||
Preallocation string `json:"preallocation"`
|
||||
// # is persistent
|
||||
Nonpersistent bool `json:"nonpersistent"`
|
||||
// auto reset disk after guest shutdown
|
||||
AutoReset bool `json:"auto_reset"`
|
||||
// 是否标记为SSD磁盘
|
||||
IsSsd bool `json:"is_ssd"`
|
||||
// 最大连接数
|
||||
@@ -1014,6 +1015,8 @@ type SGuest struct {
|
||||
VmemSize int `json:"vmem_size"`
|
||||
// CPU 内存绑定信息
|
||||
CpuNumaPin jsonutils.JSONObject `json:"cpu_numa_pin"`
|
||||
// 额外分配的 CPU 数量
|
||||
ExtraCpuCount int `json:"extra_cpu_count"`
|
||||
// 启动顺序
|
||||
BootOrder string `json:"boot_order"`
|
||||
// 关机操作类型
|
||||
@@ -1266,6 +1269,21 @@ type SHostBackupstorage struct {
|
||||
BackupstorageId string `json:"backupstorage_id"`
|
||||
}
|
||||
|
||||
// SHostFile is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SHostFile.
|
||||
type SHostFile struct {
|
||||
apis.SInfrasResourceBase
|
||||
Type string `json:"type"`
|
||||
Path string `json:"path"`
|
||||
Content string `json:"content"`
|
||||
}
|
||||
|
||||
// SHostFileJoint is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SHostFileJoint.
|
||||
type SHostFileJoint struct {
|
||||
HostId string `json:"host_id"`
|
||||
HostFileId string `json:"host_file_id"`
|
||||
Deleted bool `json:"deleted"`
|
||||
}
|
||||
|
||||
// SHostJointsBase is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SHostJointsBase.
|
||||
type SHostJointsBase struct {
|
||||
apis.SJointResourceBase
|
||||
@@ -1449,6 +1467,8 @@ type SInterVpcNetworkVpc struct {
|
||||
// SIsolatedDevice is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SIsolatedDevice.
|
||||
type SIsolatedDevice struct {
|
||||
apis.SStandaloneResourceBase
|
||||
apis.SExternalizedResourceBase
|
||||
apis.SSharableBaseResource
|
||||
SHostResourceBase
|
||||
// # PCI / GPU-HPC / GPU-VGA / USB / NIC
|
||||
// 设备类型
|
||||
|
||||
@@ -58,6 +58,10 @@ const (
|
||||
STATUS_AVAILABLE = "available"
|
||||
STATUS_CREATE_FAILED = "create_failed"
|
||||
|
||||
// 更改计费模式
|
||||
STATUS_CHANGE_BILLING_TYPE = "change_billing_type"
|
||||
STATUS_CHANGE_BILLING_TYPE_FAILED = "change_billing_type_failed"
|
||||
|
||||
CLOUD_TAG_PREFIX = "ext:"
|
||||
USER_TAG_PREFIX = "user:"
|
||||
SYS_CLOUD_TAG_PREFIX = "sys:"
|
||||
@@ -86,6 +90,7 @@ var (
|
||||
SERVICE_TYPE_CLOUDEVENT,
|
||||
SERVICE_TYPE_ANSIBLE,
|
||||
SERVICE_TYPE_INFLUXDB,
|
||||
SERVICE_TYPE_VICTORIA_METRICS,
|
||||
SERVICE_TYPE_APIMAP,
|
||||
SERVICE_TYPE_LOG,
|
||||
"autoupdate",
|
||||
@@ -108,6 +113,30 @@ var (
|
||||
SERVICE_TYPE_ETCD,
|
||||
"itsm",
|
||||
SERVICE_TYPE_NTP,
|
||||
"kafka",
|
||||
}
|
||||
|
||||
EXTERNAL_SERVICES = []string{
|
||||
SERVICE_TYPE_OFFLINE_CLOUDMETA,
|
||||
SERVICE_TYPE_CLOUDMETA,
|
||||
SERVICE_TYPE_SCHEDULER,
|
||||
SERVICE_TYPE_VNCPROXY,
|
||||
SERVICE_TYPE_ETCD,
|
||||
SERVICE_TYPE_INFLUXDB,
|
||||
SERVICE_TYPE_INFLUXDB,
|
||||
SERVICE_TYPE_VICTORIA_METRICS,
|
||||
SERVICE_TYPE_LOG,
|
||||
"s3gateway",
|
||||
"common",
|
||||
"websocket",
|
||||
"echarts-ssr",
|
||||
"cloudwatcher",
|
||||
"cloudnet",
|
||||
"repo",
|
||||
SERVICE_TYPE_ETCD,
|
||||
"itsm",
|
||||
SERVICE_TYPE_NTP,
|
||||
"kafka",
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -275,6 +275,8 @@ type ContainerVolumeMountDiskPostOverlay struct {
|
||||
// 合并后要挂载到容器的目录
|
||||
ContainerTargetDir string `json:"container_target_dir"`
|
||||
Image *ContainerVolumeMountDiskPostImageOverlay `json:"image"`
|
||||
FsUser *int64 `json:"fs_user,omitempty"`
|
||||
FsGroup *int64 `json:"fs_group,omitempty"`
|
||||
}
|
||||
|
||||
func (o ContainerVolumeMountDiskPostOverlay) IsEqual(input ContainerVolumeMountDiskPostOverlay) bool {
|
||||
@@ -344,3 +346,9 @@ type ContainerPullImageAuthConfig struct {
|
||||
// RegistryToken is a bearer token to be sent to a registry
|
||||
RegistryToken string `json:"registry_token,omitempty"`
|
||||
}
|
||||
|
||||
type ContainerRootfs struct {
|
||||
Type ContainerVolumeMountType `json:"type"`
|
||||
Disk *ContainerVolumeMountDisk `json:"disk"`
|
||||
//CephFS *ContainerVolumeMountCephFS `json:"ceph_fs"`
|
||||
}
|
||||
|
||||
@@ -41,6 +41,12 @@ type ContainerVolumeMountCephFS struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type ContainerRootfs struct {
|
||||
Type apis.ContainerVolumeMountType `json:"type"`
|
||||
Disk *ContainerVolumeMountDisk `json:"disk"`
|
||||
// CephFS *ContainerVolumeMountCephFS `json:"ceph_fs"`
|
||||
}
|
||||
|
||||
type ContainerVolumeMount struct {
|
||||
// 用于标识当前 pod volume mount 的唯一性
|
||||
UniqueName string `json:"unique_name"`
|
||||
@@ -65,6 +71,7 @@ type ContainerVolumeMount struct {
|
||||
type ContainerSpec struct {
|
||||
apis.ContainerSpec
|
||||
ImageCredentialToken string `json:"image_credential_token"`
|
||||
Rootfs *ContainerRootfs `json:"rootfs"`
|
||||
VolumeMounts []*ContainerVolumeMount `json:"volume_mounts"`
|
||||
Devices []*ContainerDevice `json:"devices"`
|
||||
}
|
||||
@@ -130,6 +137,8 @@ type ContainerSaveVolumeMountToImageInput struct {
|
||||
VolumeMountIndex int `json:"volume_mount_index"`
|
||||
VolumeMount *ContainerVolumeMount `json:"volume_mount"`
|
||||
VolumeMountDirs []string `json:"volume_mount_dirs"`
|
||||
|
||||
VolumeMountPrefix string `json:"volume_mount_prefix"`
|
||||
}
|
||||
|
||||
type ContainerCommitInput struct {
|
||||
|
||||
@@ -14,7 +14,11 @@
|
||||
|
||||
package monitor
|
||||
|
||||
import "yunion.io/x/onecloud/pkg/apis"
|
||||
import (
|
||||
"yunion.io/x/pkg/util/sets"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/apis"
|
||||
)
|
||||
|
||||
const EXT_PREFIX = "ext"
|
||||
|
||||
@@ -59,19 +63,33 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
MetricCloudResTypes = sets.NewString(
|
||||
METRIC_RES_TYPE_HOST,
|
||||
METRIC_RES_TYPE_AGENT,
|
||||
METRIC_RES_TYPE_GUEST,
|
||||
METRIC_RES_TYPE_CONTAINER,
|
||||
METRIC_RES_TYPE_OSS,
|
||||
METRIC_RES_TYPE_RDS,
|
||||
METRIC_RES_TYPE_REDIS,
|
||||
METRIC_RES_TYPE_TENANT,
|
||||
METRIC_RES_TYPE_DOMAIN,
|
||||
METRIC_RES_TYPE_STORAGE,
|
||||
METRIC_RES_TYPE_CLOUDACCOUNT)
|
||||
|
||||
MetricResType = []string{METRIC_RES_TYPE_GUEST, METRIC_RES_TYPE_HOST, METRIC_RES_TYPE_REDIS, METRIC_RES_TYPE_OSS,
|
||||
METRIC_RES_TYPE_RDS, METRIC_RES_TYPE_CLOUDACCOUNT}
|
||||
MetricUnit = []string{METRIC_UNIT_PERCENT, METRIC_UNIT_BPS, METRIC_UNIT_MBPS, METRIC_UNIT_BYTEPS, "count/s",
|
||||
METRIC_UNIT_COUNT, METRIC_UNIT_MS, METRIC_UNIT_BYTE, METRIC_UNIT_NULL}
|
||||
ResTypeScoreMap = map[string]float64{
|
||||
METRIC_RES_TYPE_GUEST: 1,
|
||||
METRIC_RES_TYPE_AGENT: 1.1,
|
||||
METRIC_RES_TYPE_HOST: 2,
|
||||
METRIC_RES_TYPE_OSS: 3,
|
||||
METRIC_RES_TYPE_RDS: 4,
|
||||
METRIC_RES_TYPE_REDIS: 5,
|
||||
METRIC_RES_TYPE_CLOUDACCOUNT: 6,
|
||||
METRIC_RES_TYPE_STORAGE: 7,
|
||||
METRIC_RES_TYPE_HOST: -100,
|
||||
METRIC_RES_TYPE_GUEST: -99,
|
||||
METRIC_RES_TYPE_AGENT: -98,
|
||||
METRIC_RES_TYPE_CONTAINER: -97,
|
||||
METRIC_RES_TYPE_SYSTEM: -96,
|
||||
METRIC_RES_TYPE_K8S: -95,
|
||||
METRIC_RES_TYPE_ELB: -94,
|
||||
METRIC_RES_TYPE_CLOUDACCOUNT: -93,
|
||||
METRIC_RES_TYPE_STORAGE: -93,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@ type SAlertPanel struct {
|
||||
type SAlertRecord struct {
|
||||
// db.SVirtualResourceBase
|
||||
apis.SEnabledResourceBase
|
||||
apis.SStatusStandaloneResourceBase
|
||||
apis.SStandaloneAnonResourceBase
|
||||
SMonitorScopedResource
|
||||
AlertId string `json:"alert_id"`
|
||||
Level string `json:"level"`
|
||||
@@ -89,6 +89,7 @@ type SAlertRecord struct {
|
||||
EvalData jsonutils.JSONObject `json:"eval_data"`
|
||||
AlertRule jsonutils.JSONObject `json:"alert_rule"`
|
||||
ResType string `json:"res_type"`
|
||||
ResIds string `json:"res_ids"`
|
||||
}
|
||||
|
||||
// SAlertRecordShield is an autogenerated struct via yunion.io/x/onecloud/pkg/monitor/models.SAlertRecordShield.
|
||||
|
||||
@@ -102,6 +102,8 @@ type NotificationManagerEventNotifyInput struct {
|
||||
// description: direct contact, admin privileges required
|
||||
// required: false
|
||||
Contacts []SContact `json:"contacts"`
|
||||
// 消息机器人列表
|
||||
RobotIds []string `json:"robot_ids"`
|
||||
// description: contact types
|
||||
// required: false
|
||||
// example: email
|
||||
|
||||
@@ -123,16 +123,6 @@ type SNotificationLog struct {
|
||||
SendTimes int `json:"send_times"`
|
||||
}
|
||||
|
||||
// SNotifyAction is an autogenerated struct via yunion.io/x/onecloud/pkg/notify/models.SNotifyAction.
|
||||
type SNotifyAction struct {
|
||||
apis.SEnabledStatusStandaloneResourceBase
|
||||
}
|
||||
|
||||
// SNotifyResource is an autogenerated struct via yunion.io/x/onecloud/pkg/notify/models.SNotifyResource.
|
||||
type SNotifyResource struct {
|
||||
apis.SEnabledStatusStandaloneResourceBase
|
||||
}
|
||||
|
||||
// SReceiver is an autogenerated struct via yunion.io/x/onecloud/pkg/notify/models.SReceiver.
|
||||
type SReceiver struct {
|
||||
apis.SVirtualResourceBase
|
||||
@@ -216,14 +206,14 @@ type STopic struct {
|
||||
|
||||
// STopicAction is an autogenerated struct via yunion.io/x/onecloud/pkg/notify/models.STopicAction.
|
||||
type STopicAction struct {
|
||||
apis.SJointResourceBase
|
||||
apis.SResourceBase
|
||||
ActionId string `json:"action_id"`
|
||||
TopicId string `json:"topic_id"`
|
||||
}
|
||||
|
||||
// STopicResource is an autogenerated struct via yunion.io/x/onecloud/pkg/notify/models.STopicResource.
|
||||
type STopicResource struct {
|
||||
apis.SJointResourceBase
|
||||
apis.SResourceBase
|
||||
ResourceId string `json:"resource_id"`
|
||||
TopicId string `json:"topic_id"`
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/apis/compute"
|
||||
"yunion.io/x/onecloud/pkg/appsrv"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/workmanager"
|
||||
"yunion.io/x/onecloud/pkg/hostman/hostutils"
|
||||
@@ -48,12 +49,13 @@ func performImageCache(
|
||||
) {
|
||||
_, _, body := appsrv.FetchEnv(ctx, w, r)
|
||||
|
||||
disk, err := body.Get("disk")
|
||||
input := compute.CacheImageInput{}
|
||||
err := body.Unmarshal(&input, "disk")
|
||||
if err != nil {
|
||||
httperrors.MissingParameterError(ctx, w, "disk")
|
||||
httperrors.BadRequestError(ctx, w, "unmarshal disk %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
hostutils.DelayImageCacheTask(ctx, performTask, disk)
|
||||
hostutils.DelayImageCacheTask(ctx, performTask, input)
|
||||
hostutils.ResponseOk(ctx, w)
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import (
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/auth"
|
||||
modules "yunion.io/x/onecloud/pkg/mcclient/modules/identity"
|
||||
"yunion.io/x/onecloud/pkg/util/ctx"
|
||||
)
|
||||
|
||||
type tenantCacheSyncWorker struct {
|
||||
@@ -34,7 +35,7 @@ type tenantCacheSyncWorker struct {
|
||||
|
||||
func (w *tenantCacheSyncWorker) Run() {
|
||||
log.Debugf("[tenantCacheSyncWorker] Run project cache sync worker ...")
|
||||
err := syncProjects(context.Background(), w.ids)
|
||||
err := syncProjects(ctx.CtxWithTime(), w.ids)
|
||||
if err != nil {
|
||||
log.Errorf("fail to syncProjects %s", err)
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import (
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/auth"
|
||||
modules "yunion.io/x/onecloud/pkg/mcclient/modules/identity"
|
||||
"yunion.io/x/onecloud/pkg/util/ctx"
|
||||
)
|
||||
|
||||
type userCacheSyncWorker struct {
|
||||
@@ -34,7 +35,7 @@ type userCacheSyncWorker struct {
|
||||
|
||||
func (w *userCacheSyncWorker) Run() {
|
||||
log.Debugf("[userCacheSyncWorker] Run project cache sync worker ...")
|
||||
err := syncUsers(context.Background(), w.ids)
|
||||
err := syncUsers(ctx.CtxWithTime(), w.ids)
|
||||
if err != nil {
|
||||
log.Errorf("fail to syncUsers %s", err)
|
||||
}
|
||||
|
||||
@@ -66,13 +66,12 @@ func ObjectIdQueryWithTagFiltersOptimized(ctx context.Context, q *sqlchemy.SQuer
|
||||
if len(filters.Filters) > 0 || len(filters.NoFilters) > 0 {
|
||||
idSubQ := q.Copy().SubQuery().Query()
|
||||
idSubQ.AppendField(sqlchemy.DISTINCT(idField, idSubQ.Field(idField)))
|
||||
subQ := idSubQ.SubQuery()
|
||||
if len(filters.Filters) > 0 {
|
||||
if GetMetadaManagerInContext(ctx) == Metadata {
|
||||
sq := tenantIdQueryWithTags(ctx, modelName, filters.Filters)
|
||||
q = q.In(idField, sq.SubQuery())
|
||||
} else { // clickhouse
|
||||
ids := objIdQueryWithTagsOptimized(ctx, subQ, idField, modelName, filters.Filters)
|
||||
ids := tenantIdQueryWithTagsWithCache(ctx, modelName, filters.Filters)
|
||||
if len(ids) > 0 {
|
||||
q = q.In(idField, ids)
|
||||
}
|
||||
@@ -83,7 +82,7 @@ func ObjectIdQueryWithTagFiltersOptimized(ctx context.Context, q *sqlchemy.SQuer
|
||||
sq := tenantIdQueryWithTags(ctx, modelName, filters.Filters)
|
||||
q = q.NotIn(idField, sq.SubQuery())
|
||||
} else { // clickhouse
|
||||
ids := objIdQueryWithTagsOptimized(ctx, subQ, idField, modelName, filters.NoFilters)
|
||||
ids := tenantIdQueryWithTagsWithCache(ctx, modelName, filters.NoFilters)
|
||||
if len(ids) > 0 {
|
||||
q = q.NotIn(idField, ids)
|
||||
}
|
||||
@@ -153,6 +152,50 @@ func tenantIdQueryWithTags(ctx context.Context, modelName string, tagsList []map
|
||||
return sq.Filter(sqlchemy.OR(conditions...)).Distinct()
|
||||
}
|
||||
|
||||
var (
|
||||
tagsCache = hashcache.NewCache(1024, time.Minute*15)
|
||||
)
|
||||
|
||||
func tenantIdQueryWithTagsWithCache(ctx context.Context, modelName string, tagsList []map[string][]string) []string {
|
||||
manager := Metadata
|
||||
|
||||
ret := []string{}
|
||||
sq := manager.Query("obj_id")
|
||||
for _, tags := range tagsList {
|
||||
if len(tags) == 0 {
|
||||
continue
|
||||
}
|
||||
hashKeys := []string{modelName, jsonutils.Marshal(tags).String()}
|
||||
hash := fmt.Sprintf("%x", md5.Sum([]byte(jsonutils.Marshal(hashKeys).String())))
|
||||
cache := tagsCache.Get(hash)
|
||||
if cache != nil {
|
||||
ids := cache.([]string)
|
||||
ret = append(ret, ids...)
|
||||
log.Debugf("cache hit %s %s %s", hash, hashKeys, ids)
|
||||
continue
|
||||
}
|
||||
conditions := []sqlchemy.ICondition{}
|
||||
for key, val := range tags {
|
||||
if len(val) > 0 {
|
||||
sqq := sq.Copy().Equals("obj_type", modelName).Equals("key", key).In("value", val)
|
||||
conditions = append(conditions, sqlchemy.In(sq.Field("obj_id"), sqq.SubQuery()))
|
||||
} else {
|
||||
sqq := sq.Copy().Equals("obj_type", modelName).Equals("key", key)
|
||||
conditions = append(conditions, sqlchemy.In(sq.Field("obj_id"), sqq.SubQuery()))
|
||||
}
|
||||
}
|
||||
ids, err := FetchIds(sq.Copy().Filter(sqlchemy.AND(conditions...)).Distinct())
|
||||
if err != nil {
|
||||
log.Errorf("FetchIds %s %v", sq.String(), err)
|
||||
continue
|
||||
}
|
||||
ret = append(ret, ids...)
|
||||
log.Debugf("cache miss %s %s %s", hash, hashKeys, ids)
|
||||
tagsCache.AtomicSet(hash, ids)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func objIdQueryWithTags(ctx context.Context, objIdSubQ *sqlchemy.SSubQuery, idField string, modelName string, tagsList []map[string][]string) *sqlchemy.SQuery {
|
||||
manager := GetMetadaManagerInContext(ctx)
|
||||
|
||||
@@ -192,53 +235,6 @@ func objIdQueryWithTags(ctx context.Context, objIdSubQ *sqlchemy.SSubQuery, idFi
|
||||
return query
|
||||
}
|
||||
|
||||
var (
|
||||
tagsCache = hashcache.NewCache(1024, time.Minute*15)
|
||||
)
|
||||
|
||||
func objIdQueryWithTagsOptimized(ctx context.Context, objIdSubQ *sqlchemy.SSubQuery, idField string, modelName string, tagsList []map[string][]string) []string {
|
||||
manager := GetMetadaManagerInContext(ctx)
|
||||
|
||||
ret := []string{}
|
||||
for _, tags := range tagsList {
|
||||
if len(tags) == 0 {
|
||||
continue
|
||||
}
|
||||
objIdQ := objIdSubQ.Query()
|
||||
objIdQ = objIdQ.AppendField(objIdQ.Field(idField))
|
||||
for key, val := range tags {
|
||||
hashKeys := []string{idField, key, modelName}
|
||||
hashKeys = append(hashKeys, val...)
|
||||
hash := fmt.Sprintf("%x", md5.Sum([]byte(jsonutils.Marshal(hashKeys).String())))
|
||||
cache := tagsCache.Get(hash)
|
||||
if cache != nil {
|
||||
ids := cache.([]string)
|
||||
ret = append(ret, ids...)
|
||||
continue
|
||||
}
|
||||
sq := manager.Query("obj_id").Equals("obj_type", modelName).Equals("key", key)
|
||||
if len(val) > 0 {
|
||||
ssq := sq.In("value", val).SubQuery()
|
||||
if utils.IsInArray(tagutils.NoValue, val) {
|
||||
objIdQ = objIdQ.LeftJoin(ssq, sqlchemy.Equals(objIdQ.Field(idField), ssq.Field("obj_id")))
|
||||
} else {
|
||||
objIdQ = objIdQ.Join(ssq, sqlchemy.Equals(objIdQ.Field(idField), ssq.Field("obj_id")))
|
||||
}
|
||||
} else {
|
||||
ssq := sq.SubQuery()
|
||||
objIdQ = objIdQ.Join(ssq, sqlchemy.Equals(objIdQ.Field(idField), ssq.Field("obj_id")))
|
||||
}
|
||||
ids, err := FetchIds(objIdQ)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
ret = append(ret, ids...)
|
||||
tagsCache.AtomicSet(hash, ids)
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (meta *SMetadataResourceBaseModelManager) ListItemFilter(
|
||||
ctx context.Context,
|
||||
manager IModelManager,
|
||||
|
||||
@@ -182,13 +182,18 @@ func lang(ctx context.Context, contactType npk.TNotifyChannel, reIds []string, c
|
||||
return langMap, nil
|
||||
}
|
||||
|
||||
func isEmptyRecipients(recipientId []string) bool {
|
||||
func isEmptyRecipients(recipientId, robots []string) bool {
|
||||
var recvs []string
|
||||
for _, c := range recipientId {
|
||||
if len(c) > 0 {
|
||||
recvs = append(recvs, c)
|
||||
}
|
||||
}
|
||||
for _, robot := range robots {
|
||||
if len(robot) > 0 {
|
||||
recvs = append(recvs, robot)
|
||||
}
|
||||
}
|
||||
return len(recvs) == 0
|
||||
}
|
||||
|
||||
@@ -216,7 +221,7 @@ func genMsgViaLang(ctx context.Context, p sNotifyParams) ([]npk.SNotifyMessage,
|
||||
reIds = p.recipientId
|
||||
}
|
||||
|
||||
if isEmptyRecipients(p.recipientId) {
|
||||
if isEmptyRecipients(p.recipientId, p.robots) {
|
||||
return nil, errors.Wrap(errors.ErrEmpty, "empty receipients")
|
||||
}
|
||||
|
||||
@@ -414,10 +419,10 @@ func (t *notifyTask) Run() {
|
||||
}
|
||||
|
||||
func intelliNotify(ctx context.Context, p sNotifyParams) {
|
||||
if isEmptyRecipients(p.recipientId) {
|
||||
if isEmptyRecipients(p.recipientId, p.robots) {
|
||||
return
|
||||
}
|
||||
log.Infof("recipientId: %v, contacts: %v, event %s priority %s", p.recipientId, p.contacts, p.event, p.priority)
|
||||
log.Infof("recipientId: %v, robots: %v, contacts: %v, event %s priority %s", p.recipientId, p.robots, p.contacts, p.event, p.priority)
|
||||
msgs, err := genMsgViaLang(ctx, p)
|
||||
if err != nil {
|
||||
log.Errorf("unable send notification: %v", err)
|
||||
|
||||
@@ -166,6 +166,7 @@ type HostCommonOptions struct {
|
||||
ExecutorConnectTimeoutSeconds int `help:"executor client connection timeout in seconds, default is 30" default:"30"`
|
||||
ImageDeployDriver string `help:"Image deploy driver" default:"qemu-kvm" choices:"qemu-kvm|nbd|libguestfs"`
|
||||
DeployConcurrent int `help:"qemu-kvm deploy driver concurrent" default:"5"`
|
||||
Qcow2Preallocation string `help:"Qcow2 image create preallocation" default:"metadata" choices:"disable|metadata|falloc|full"`
|
||||
}
|
||||
|
||||
type DBOptions struct {
|
||||
|
||||
@@ -65,28 +65,29 @@ func (n SNic) GetMac() net.HardwareAddr {
|
||||
}
|
||||
|
||||
type SServerNic struct {
|
||||
Name string `json:"name"`
|
||||
Index int `json:"index"`
|
||||
Bridge string `json:"bridge"`
|
||||
Domain string `json:"domain"`
|
||||
Ip string `json:"ip"`
|
||||
Vlan int `json:"vlan"`
|
||||
Driver string `json:"driver"`
|
||||
Masklen int `json:"masklen"`
|
||||
Virtual bool `json:"virtual"`
|
||||
Manual bool `json:"manual"`
|
||||
WireId string `json:"wire_id"`
|
||||
NetId string `json:"net_id"`
|
||||
Mac string `json:"mac"`
|
||||
BandWidth int `json:"bw"`
|
||||
Mtu int16 `json:"mtu,omitempty"`
|
||||
Dns string `json:"dns"`
|
||||
Ntp string `json:"ntp"`
|
||||
Net string `json:"net"`
|
||||
Interface string `json:"interface"`
|
||||
Gateway string `json:"gateway"`
|
||||
Ifname string `json:"ifname"`
|
||||
Routes []SRoute `json:"routes,omitempty"`
|
||||
Name string `json:"name"`
|
||||
Index int `json:"index"`
|
||||
Bridge string `json:"bridge"`
|
||||
Domain string `json:"domain"`
|
||||
Ip string `json:"ip"`
|
||||
Vlan int `json:"vlan"`
|
||||
VlanInterface bool `json:"vlan_interface"`
|
||||
Driver string `json:"driver"`
|
||||
Masklen int `json:"masklen"`
|
||||
Virtual bool `json:"virtual"`
|
||||
Manual bool `json:"manual"`
|
||||
WireId string `json:"wire_id"`
|
||||
NetId string `json:"net_id"`
|
||||
Mac string `json:"mac"`
|
||||
BandWidth int `json:"bw"`
|
||||
Mtu int16 `json:"mtu,omitempty"`
|
||||
Dns string `json:"dns"`
|
||||
Ntp string `json:"ntp"`
|
||||
Net string `json:"net"`
|
||||
Interface string `json:"interface"`
|
||||
Gateway string `json:"gateway"`
|
||||
Ifname string `json:"ifname"`
|
||||
Routes []SRoute `json:"routes,omitempty"`
|
||||
|
||||
Ip6 string `json:"ip6"`
|
||||
Masklen6 int `json:"masklen6"`
|
||||
|
||||
177
pkg/cloudmon/misc/bucketprobe.go
Normal file
177
pkg/cloudmon/misc/bucketprobe.go
Normal file
@@ -0,0 +1,177 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// 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.
|
||||
|
||||
package misc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
computeapi "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
"yunion.io/x/onecloud/pkg/cloudmon/options"
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/auth"
|
||||
computemodules "yunion.io/x/onecloud/pkg/mcclient/modules/compute"
|
||||
baseoptions "yunion.io/x/onecloud/pkg/mcclient/options"
|
||||
"yunion.io/x/onecloud/pkg/util/influxdb"
|
||||
)
|
||||
|
||||
func BucketProbe(ctx context.Context, userCred mcclient.TokenCredential, isStart bool) {
|
||||
if options.Options.EnableBucketProbeDebug {
|
||||
log.Debugf("BucketProbe start")
|
||||
}
|
||||
if !options.Options.EnableBucketProbe {
|
||||
if options.Options.EnableBucketProbeDebug {
|
||||
log.Debugf("BucketProbe is disabled")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
sess := auth.GetSession(ctx, userCred, options.Options.Region)
|
||||
|
||||
metrics, err := gatherBucketMetrics(ctx, sess)
|
||||
if err != nil {
|
||||
log.Errorf("BucketProbe gatherBucketMetrics failed: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
err = sendMetrics(sess, metrics, "telegraf")
|
||||
if err != nil {
|
||||
log.Errorf("StatusProbe SendMetrics error: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func gatherBucketMetrics(ctx context.Context, sess *mcclient.ClientSession) ([]influxdb.SMetricData, error) {
|
||||
allMetrics := []influxdb.SMetricData{}
|
||||
|
||||
params := baseoptions.BaseListOptions{}
|
||||
params.Scope = "max"
|
||||
limit := 1000
|
||||
params.Limit = &limit
|
||||
params.Filter = []string{
|
||||
"enable_perf_mon.equals(1)",
|
||||
}
|
||||
boolTrue := true
|
||||
params.Details = &boolTrue
|
||||
|
||||
total := -1
|
||||
offset := 0
|
||||
for total < 0 || offset < total {
|
||||
params.Offset = &offset
|
||||
results, err := computemodules.Buckets.List(sess, jsonutils.Marshal(params))
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "computemodules.Buckets.List")
|
||||
}
|
||||
total = results.Total
|
||||
offset = results.Offset + len(results.Data)
|
||||
|
||||
for _, bucket := range results.Data {
|
||||
bucketDetails := computeapi.BucketDetails{}
|
||||
err = bucket.Unmarshal(&bucketDetails)
|
||||
if err != nil {
|
||||
log.Errorf("BucketProbe failed: %s", err)
|
||||
continue
|
||||
}
|
||||
|
||||
metrics, err := probeBucketStats(ctx, sess, &bucketDetails)
|
||||
if err != nil {
|
||||
log.Errorf("BucketProbe failed: %s", err)
|
||||
continue
|
||||
}
|
||||
allMetrics = append(allMetrics, metrics...)
|
||||
}
|
||||
}
|
||||
|
||||
return allMetrics, nil
|
||||
}
|
||||
|
||||
func probeBucketStats(ctx context.Context, sess *mcclient.ClientSession, bucketDetails *computeapi.BucketDetails) ([]influxdb.SMetricData, error) {
|
||||
bucket, err := computemodules.GetIBucket(ctx, sess, bucketDetails)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "getIBucket")
|
||||
}
|
||||
|
||||
resultDelay, err := computemodules.ProbeBucketStats(ctx, bucket, options.Options.BucketProbeTestKey, 0)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "doProbeBucketStats zero")
|
||||
}
|
||||
|
||||
resultRate, err := computemodules.ProbeBucketStats(ctx, bucket, options.Options.BucketProbeTestKey, int64(options.Options.BucketProbeTestSizeMb)*1024*1024)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "doProbeBucketStats with payload")
|
||||
}
|
||||
|
||||
metricTags := []influxdb.SKeyValue{}
|
||||
for k, v := range bucketDetails.GetMetricTags() {
|
||||
if len(v) == 0 {
|
||||
continue
|
||||
}
|
||||
metricTags = append(metricTags, influxdb.SKeyValue{
|
||||
Key: k,
|
||||
Value: v,
|
||||
})
|
||||
}
|
||||
|
||||
metrics := []influxdb.SKeyValue{}
|
||||
for k, v := range bucketDetails.GetMetricTags() {
|
||||
if len(v) == 0 {
|
||||
continue
|
||||
}
|
||||
metrics = append(metrics, influxdb.SKeyValue{
|
||||
Key: k,
|
||||
Value: v,
|
||||
})
|
||||
}
|
||||
|
||||
metrics = append(metrics,
|
||||
influxdb.SKeyValue{
|
||||
Key: "upload_delay_ms",
|
||||
Value: fmt.Sprintf("%f", resultDelay.UploadDelayMs()),
|
||||
},
|
||||
influxdb.SKeyValue{
|
||||
Key: "download_delay_ms",
|
||||
Value: fmt.Sprintf("%f", resultDelay.DownloadDelayMs()),
|
||||
},
|
||||
influxdb.SKeyValue{
|
||||
Key: "delete_delay_ms",
|
||||
Value: fmt.Sprintf("%f", resultDelay.DeleteDelayMs()),
|
||||
},
|
||||
influxdb.SKeyValue{
|
||||
Key: "upload_rate_mbps",
|
||||
Value: fmt.Sprintf("%f", resultRate.UploadThroughputMbps(options.Options.BucketProbeTestSizeMb)),
|
||||
},
|
||||
influxdb.SKeyValue{
|
||||
Key: "download_rate_mbps",
|
||||
Value: fmt.Sprintf("%f", resultRate.DownloadThroughputMbps(options.Options.BucketProbeTestSizeMb)),
|
||||
},
|
||||
)
|
||||
|
||||
if options.Options.EnableBucketProbeDebug {
|
||||
log.Debugf("BucketProbe for bucket %s metrics: %s", bucketDetails.Name, jsonutils.Marshal(metrics))
|
||||
}
|
||||
|
||||
return []influxdb.SMetricData{
|
||||
{
|
||||
Name: "bucket_perf",
|
||||
Tags: metricTags,
|
||||
Metrics: metrics,
|
||||
Timestamp: time.Now(),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
437
pkg/cloudmon/misc/httpstats.go
Normal file
437
pkg/cloudmon/misc/httpstats.go
Normal file
@@ -0,0 +1,437 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// 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.
|
||||
|
||||
package misc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/log"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/cloudmon/options"
|
||||
"yunion.io/x/onecloud/pkg/util/influxdb"
|
||||
)
|
||||
|
||||
type SHttpStats struct {
|
||||
HttpCode2xx float64 `json:"duration.2XX"`
|
||||
HttpCode4xx float64 `json:"duration.4XX"`
|
||||
HttpCode5xx float64 `json:"duration.5XX"`
|
||||
HitHttpCode2xx int64 `json:"hit.2XX"`
|
||||
HitHttpCode4xx int64 `json:"hit.4XX"`
|
||||
HitHttpCode5xx int64 `json:"hit.5XX"`
|
||||
|
||||
Method string `json:"method"`
|
||||
Name string `json:"name"`
|
||||
Path string `json:"path"`
|
||||
}
|
||||
|
||||
type sApiHttpStats struct {
|
||||
SHttpStats
|
||||
|
||||
Paths []SHttpStats `json:"paths"`
|
||||
}
|
||||
|
||||
func (apiStats *sApiHttpStats) convertSnapshot(now time.Time) *sHttpStatsSnapshot {
|
||||
snapshot := &sHttpStatsSnapshot{
|
||||
snapshotAt: now,
|
||||
stats: map[string]*SHttpStats{},
|
||||
}
|
||||
apiStats.SHttpStats.Method = "any"
|
||||
apiStats.SHttpStats.Path = "any"
|
||||
apiStats.SHttpStats.Name = "any"
|
||||
snapshot.stats[getStatsKey(apiStats.SHttpStats.Method, apiStats.SHttpStats.Path, apiStats.SHttpStats.Name)] = &apiStats.SHttpStats
|
||||
for i := range apiStats.Paths {
|
||||
pathStats := apiStats.Paths[i]
|
||||
snapshot.stats[getStatsKey(pathStats.Method, pathStats.Path, pathStats.Name)] = &pathStats
|
||||
}
|
||||
return snapshot
|
||||
}
|
||||
|
||||
type sHttpStatsExt struct {
|
||||
Duration2xx float64 `json:"duration_2xx"`
|
||||
Duration4xx float64 `json:"duration_4xx"`
|
||||
Duration5xx float64 `json:"duration_5xx"`
|
||||
Hit2xx int64 `json:"hit_2xx"`
|
||||
Hit4xx int64 `json:"hit_4xx"`
|
||||
Hit5xx int64 `json:"hit_5xx"`
|
||||
|
||||
Duration2xxDiff float64 `json:"duration_2xx_diff"`
|
||||
Duration4xxDiff float64 `json:"duration_4xx_diff"`
|
||||
Duration5xxDiff float64 `json:"duration_5xx_diff"`
|
||||
Hit2xxDiff int64 `json:"hit_2xx_diff"`
|
||||
Hit4xxDiff int64 `json:"hit_4xx_diff"`
|
||||
Hit5xxDiff int64 `json:"hit_5xx_diff"`
|
||||
|
||||
Method string `json:"method"`
|
||||
Path string `json:"path"`
|
||||
Name string `json:"name"`
|
||||
|
||||
HasDiff bool `json:"has_diff"`
|
||||
}
|
||||
|
||||
func (v sHttpStatsExt) DelayMs2xx() float64 {
|
||||
if v.Hit2xxDiff > 0 {
|
||||
return v.Duration2xxDiff / float64(v.Hit2xxDiff)
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func (v sHttpStatsExt) Qps2xx(interval time.Duration) float64 {
|
||||
if interval > 0 {
|
||||
return float64(v.Hit2xxDiff) / interval.Seconds()
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func (v sHttpStatsExt) DelayMs4xx() float64 {
|
||||
if v.Hit4xxDiff > 0 {
|
||||
return v.Duration4xxDiff / float64(v.Hit4xxDiff)
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func (v sHttpStatsExt) Qps4xx(interval time.Duration) float64 {
|
||||
if interval > 0 {
|
||||
return float64(v.Hit4xxDiff) / interval.Seconds()
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func (v sHttpStatsExt) DelayMs5xx() float64 {
|
||||
if v.Hit5xxDiff > 0 {
|
||||
return v.Duration5xxDiff / float64(v.Hit5xxDiff)
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func (v sHttpStatsExt) Qps5xx(interval time.Duration) float64 {
|
||||
if interval > 0 {
|
||||
return float64(v.Hit5xxDiff) / interval.Seconds()
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func (v sHttpStatsExt) Qps(interval time.Duration) float64 {
|
||||
if interval > 0 {
|
||||
return float64(v.Hit2xxDiff+v.Hit4xxDiff+v.Hit5xxDiff) / interval.Seconds()
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func (v sHttpStatsExt) DelayMs() float64 {
|
||||
if v.HitDiff() > 0 {
|
||||
return v.DurationMsDiff() / float64(v.HitDiff())
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func (v sHttpStatsExt) DurationMs() float64 {
|
||||
return v.Duration2xx + v.Duration4xx + v.Duration5xx
|
||||
}
|
||||
|
||||
func (v sHttpStatsExt) Hit() int64 {
|
||||
return v.Hit2xx + v.Hit4xx + v.Hit5xx
|
||||
}
|
||||
|
||||
func (v sHttpStatsExt) DurationMsDiff() float64 {
|
||||
return v.Duration2xxDiff + v.Duration4xxDiff + v.Duration5xxDiff
|
||||
}
|
||||
|
||||
func (v sHttpStatsExt) HitDiff() int64 {
|
||||
return v.Hit2xxDiff + v.Hit4xxDiff + v.Hit5xxDiff
|
||||
}
|
||||
|
||||
func (v sHttpStatsExt) Percent2xx() float64 {
|
||||
if v.DurationMsDiff() > 0 {
|
||||
return v.Duration2xxDiff * 100 / v.DurationMsDiff()
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func (v sHttpStatsExt) PercentHit2xx() float64 {
|
||||
if v.HitDiff() > 0 {
|
||||
return float64(v.Hit2xxDiff) * 100 / float64(v.HitDiff())
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func (v sHttpStatsExt) Percent4xx() float64 {
|
||||
if v.DurationMsDiff() > 0 {
|
||||
return v.Duration4xxDiff * 100 / v.DurationMsDiff()
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func (v sHttpStatsExt) PercentHit4xx() float64 {
|
||||
if v.HitDiff() > 0 {
|
||||
return float64(v.Hit4xxDiff) * 100 / float64(v.HitDiff())
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func (v sHttpStatsExt) Percent5xx() float64 {
|
||||
if v.DurationMsDiff() > 0 {
|
||||
return v.Duration5xxDiff * 100 / v.DurationMsDiff()
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func (v sHttpStatsExt) PercentHit5xx() float64 {
|
||||
if v.HitDiff() > 0 {
|
||||
return float64(v.Hit5xxDiff) * 100 / float64(v.HitDiff())
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
type sHttpStatsSnapshot struct {
|
||||
snapshotAt time.Time
|
||||
stats map[string]*SHttpStats
|
||||
}
|
||||
|
||||
type sHttpStatsDiff struct {
|
||||
snapshotAt time.Time
|
||||
interval time.Duration
|
||||
stats map[string]*sHttpStatsExt
|
||||
}
|
||||
|
||||
func calculateHttpStatsDiff(prevSnap *sHttpStatsSnapshot, nowSnap *sHttpStatsSnapshot) *sHttpStatsDiff {
|
||||
diff := sHttpStatsDiff{
|
||||
snapshotAt: nowSnap.snapshotAt,
|
||||
stats: map[string]*sHttpStatsExt{},
|
||||
}
|
||||
if prevSnap != nil {
|
||||
rootKey := getStatsKey("any", "any", "any")
|
||||
prevRoot := prevSnap.stats[rootKey]
|
||||
nowRoot := nowSnap.stats[rootKey]
|
||||
|
||||
if prevRoot.HttpCode2xx > nowRoot.HttpCode2xx || prevRoot.HttpCode4xx > nowRoot.HttpCode4xx || prevRoot.HttpCode5xx > nowRoot.HttpCode5xx ||
|
||||
prevRoot.HitHttpCode2xx > nowRoot.HitHttpCode2xx || prevRoot.HitHttpCode4xx > nowRoot.HitHttpCode4xx || prevRoot.HitHttpCode5xx > nowRoot.HitHttpCode5xx {
|
||||
// detect a reset, skip this round
|
||||
prevSnap = nil
|
||||
}
|
||||
}
|
||||
if prevSnap != nil {
|
||||
diff.interval = nowSnap.snapshotAt.Sub(prevSnap.snapshotAt)
|
||||
} else {
|
||||
intvMin := options.Options.CollectServiceMetricIntervalMinute
|
||||
if intvMin <= 0 {
|
||||
intvMin = 1
|
||||
}
|
||||
diff.interval = time.Duration(intvMin) * time.Minute
|
||||
}
|
||||
|
||||
for k := range nowSnap.stats {
|
||||
v := nowSnap.stats[k]
|
||||
diffStats := sHttpStatsExt{
|
||||
Duration2xx: v.HttpCode2xx,
|
||||
Duration4xx: v.HttpCode4xx,
|
||||
Duration5xx: v.HttpCode5xx,
|
||||
Hit2xx: v.HitHttpCode2xx,
|
||||
Hit4xx: v.HitHttpCode4xx,
|
||||
Hit5xx: v.HitHttpCode5xx,
|
||||
|
||||
Method: v.Method,
|
||||
Path: v.Path,
|
||||
Name: v.Name,
|
||||
}
|
||||
if prevSnap != nil {
|
||||
if prevStats, ok := prevSnap.stats[k]; ok {
|
||||
diffStats.HasDiff = true
|
||||
diffStats.Duration2xxDiff = v.HttpCode2xx - prevStats.HttpCode2xx
|
||||
diffStats.Duration4xxDiff = v.HttpCode4xx - prevStats.HttpCode4xx
|
||||
diffStats.Duration5xxDiff = v.HttpCode5xx - prevStats.HttpCode5xx
|
||||
diffStats.Hit2xxDiff = v.HitHttpCode2xx - prevStats.HitHttpCode2xx
|
||||
diffStats.Hit4xxDiff = v.HitHttpCode4xx - prevStats.HitHttpCode4xx
|
||||
diffStats.Hit5xxDiff = v.HitHttpCode5xx - prevStats.HitHttpCode5xx
|
||||
}
|
||||
}
|
||||
|
||||
diff.stats[k] = &diffStats
|
||||
}
|
||||
return &diff
|
||||
}
|
||||
|
||||
var (
|
||||
httpStatsSnapshot = map[string]*sHttpStatsSnapshot{}
|
||||
)
|
||||
|
||||
func getStatsKey(method, path, name string) string {
|
||||
return fmt.Sprintf("%s.%s.%s", method, path, name)
|
||||
}
|
||||
|
||||
func getSnapshotKey(serviceName, url string) string {
|
||||
return fmt.Sprintf("%s.%s", serviceName, url)
|
||||
}
|
||||
|
||||
func updateHttpStatsSnapshot(serviceName string, url string, now time.Time, apiStats sApiHttpStats, serviceType, regionId, version string) []influxdb.SMetricData {
|
||||
snapshot := apiStats.convertSnapshot(now)
|
||||
|
||||
snapshotKey := getSnapshotKey(serviceName, url)
|
||||
var vdiffStats *sHttpStatsDiff
|
||||
if prevSnap, ok := httpStatsSnapshot[snapshotKey]; ok {
|
||||
vdiffStats = calculateHttpStatsDiff(prevSnap, snapshot)
|
||||
} else {
|
||||
// no prev records, just add
|
||||
vdiffStats = calculateHttpStatsDiff(nil, snapshot)
|
||||
}
|
||||
httpStatsSnapshot[snapshotKey] = snapshot
|
||||
|
||||
metrics := vdiffStats.metrics(serviceName, serviceType, regionId, version)
|
||||
|
||||
log.Debugf("updateHttpStatsSnapshot %s %s snapshotAt: %s diffAt: %s intval: %f metrics: %d", serviceName, url, snapshot.snapshotAt, vdiffStats.snapshotAt, vdiffStats.interval.Seconds(), len(metrics))
|
||||
|
||||
return metrics
|
||||
}
|
||||
|
||||
func appendMetric(metrics []influxdb.SKeyValue, key string, v float64) []influxdb.SKeyValue {
|
||||
if v >= 0 {
|
||||
metrics = append(metrics, influxdb.SKeyValue{
|
||||
Key: key,
|
||||
Value: fmt.Sprintf("%f", v),
|
||||
})
|
||||
}
|
||||
return metrics
|
||||
}
|
||||
|
||||
func (diff *sHttpStatsDiff) metrics(service, serviceType, regionId, version string) []influxdb.SMetricData {
|
||||
metrics := make([]influxdb.SMetricData, 0)
|
||||
genTags := func(v *sHttpStatsExt) []influxdb.SKeyValue {
|
||||
return []influxdb.SKeyValue{
|
||||
{
|
||||
Key: "service",
|
||||
Value: service,
|
||||
},
|
||||
{
|
||||
Key: "service_type",
|
||||
Value: serviceType,
|
||||
},
|
||||
{
|
||||
Key: "region",
|
||||
Value: regionId,
|
||||
},
|
||||
{
|
||||
Key: "version",
|
||||
Value: version,
|
||||
},
|
||||
{
|
||||
Key: "method",
|
||||
Value: v.Method,
|
||||
},
|
||||
{
|
||||
Key: "path",
|
||||
Value: v.Path,
|
||||
},
|
||||
{
|
||||
Key: "name",
|
||||
Value: v.Name,
|
||||
},
|
||||
{
|
||||
Key: "interval_secs",
|
||||
Value: fmt.Sprintf("%f", diff.interval.Seconds()),
|
||||
},
|
||||
}
|
||||
}
|
||||
for k := range diff.stats {
|
||||
v := diff.stats[k]
|
||||
|
||||
// ignore stats with no hit
|
||||
if v.Hit() <= 0 {
|
||||
continue
|
||||
}
|
||||
// ignore stats with no diff
|
||||
if v.HasDiff && v.HitDiff() <= 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
metric := influxdb.SMetricData{
|
||||
Name: METIRCY_TYPE_HTTP_REQUST,
|
||||
Timestamp: diff.snapshotAt,
|
||||
Tags: genTags(v),
|
||||
Metrics: []influxdb.SKeyValue{
|
||||
{
|
||||
Key: "duration_ms_any",
|
||||
Value: fmt.Sprintf("%f", v.DurationMs()),
|
||||
},
|
||||
{
|
||||
Key: "hit_any",
|
||||
Value: fmt.Sprintf("%d", v.Hit()),
|
||||
},
|
||||
},
|
||||
}
|
||||
if v.HasDiff {
|
||||
metric.Metrics = appendMetric(metric.Metrics, "dura_ms_delta_any", v.DurationMsDiff())
|
||||
metric.Metrics = appendMetric(metric.Metrics, "hit_delta_any", float64(v.HitDiff()))
|
||||
metric.Metrics = appendMetric(metric.Metrics, "delay_ms_any", v.DelayMs())
|
||||
metric.Metrics = appendMetric(metric.Metrics, "qps_any", v.Qps(diff.interval))
|
||||
}
|
||||
metric.Metrics = append(metric.Metrics, []influxdb.SKeyValue{
|
||||
{
|
||||
Key: "duration_ms_2xx",
|
||||
Value: fmt.Sprintf("%f", v.Duration2xx),
|
||||
},
|
||||
{
|
||||
Key: "hit_2xx",
|
||||
Value: fmt.Sprintf("%d", v.Hit2xx),
|
||||
},
|
||||
}...)
|
||||
if v.HasDiff {
|
||||
metric.Metrics = appendMetric(metric.Metrics, "dura_ms_delta_2xx", v.Duration2xxDiff)
|
||||
metric.Metrics = appendMetric(metric.Metrics, "hit_delta_2xx", float64(v.Hit2xxDiff))
|
||||
metric.Metrics = appendMetric(metric.Metrics, "delay_ms_2xx", v.DelayMs2xx())
|
||||
metric.Metrics = appendMetric(metric.Metrics, "percent_hit_2xx", v.PercentHit2xx())
|
||||
metric.Metrics = appendMetric(metric.Metrics, "percent_duration_2xx", v.Percent2xx())
|
||||
metric.Metrics = appendMetric(metric.Metrics, "qps_2xx", v.Qps2xx(diff.interval))
|
||||
}
|
||||
metric.Metrics = append(metric.Metrics, []influxdb.SKeyValue{
|
||||
{
|
||||
Key: "duration_ms_4xx",
|
||||
Value: fmt.Sprintf("%f", v.Duration4xx),
|
||||
},
|
||||
{
|
||||
Key: "hit_4xx",
|
||||
Value: fmt.Sprintf("%d", v.Hit4xx),
|
||||
},
|
||||
}...)
|
||||
if v.HasDiff {
|
||||
metric.Metrics = appendMetric(metric.Metrics, "dura_ms_delta_4xx", v.Duration4xxDiff)
|
||||
metric.Metrics = appendMetric(metric.Metrics, "hit_delta_4xx", float64(v.Hit4xxDiff))
|
||||
metric.Metrics = appendMetric(metric.Metrics, "delay_ms_4xx", v.DelayMs4xx())
|
||||
metric.Metrics = appendMetric(metric.Metrics, "percent_hit_4xx", v.PercentHit4xx())
|
||||
metric.Metrics = appendMetric(metric.Metrics, "percent_duration_4xx", v.Percent4xx())
|
||||
metric.Metrics = appendMetric(metric.Metrics, "qps_4xx", v.Qps4xx(diff.interval))
|
||||
}
|
||||
metric.Metrics = append(metric.Metrics, []influxdb.SKeyValue{
|
||||
{
|
||||
Key: "duration_ms_5xx",
|
||||
Value: fmt.Sprintf("%f", v.Duration5xx),
|
||||
},
|
||||
{
|
||||
Key: "hit_5xx",
|
||||
Value: fmt.Sprintf("%d", v.Hit5xx),
|
||||
},
|
||||
}...)
|
||||
if v.HasDiff {
|
||||
metric.Metrics = appendMetric(metric.Metrics, "dura_ms_delta_5xx", v.Duration5xxDiff)
|
||||
metric.Metrics = appendMetric(metric.Metrics, "hit_delta_5xx", float64(v.Hit5xxDiff))
|
||||
metric.Metrics = appendMetric(metric.Metrics, "delay_ms_5xx", v.DelayMs5xx())
|
||||
metric.Metrics = appendMetric(metric.Metrics, "percent_hit_5xx", v.PercentHit5xx())
|
||||
metric.Metrics = appendMetric(metric.Metrics, "percent_duration_5xx", v.Percent5xx())
|
||||
metric.Metrics = appendMetric(metric.Metrics, "qps_5xx", v.Qps5xx(diff.interval))
|
||||
}
|
||||
|
||||
metrics = append(metrics, metric)
|
||||
}
|
||||
return metrics
|
||||
}
|
||||
215
pkg/cloudmon/misc/httpstats_test.go
Normal file
215
pkg/cloudmon/misc/httpstats_test.go
Normal file
@@ -0,0 +1,215 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// 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.
|
||||
|
||||
package misc
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/pkg/util/timeutils"
|
||||
)
|
||||
|
||||
func TestUnmarshalHttpStats(t *testing.T) {
|
||||
input := `{"duration.2XX":4532188.710192006, "duration.4XX":196870.22898800002, "duration.5XX":32787.14909299999, "hit.2XX":88678, "hit.4XX":1748, "hit.5XX":179, "paths":[{"duration.2XX":150, "duration.4XX":250, "duration.5XX":310, "hit.2XX":1500, "hit.4XX":2500, "hit.5XX":3500, "method":"GET", "path":"/servers", "name":"list_servers"}, {"duration.2XX":150, "duration.4XX":250, "duration.5XX":350, "hit.2XX":1500, "hit.4XX":2500, "hit.5XX":3500, "method":"POST", "path":"/servers", "name":"create_servers"}]}`
|
||||
inputJson, err := jsonutils.ParseString(input)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Logf("json: %s", inputJson.PrettyString())
|
||||
var stats sApiHttpStats
|
||||
err = inputJson.Unmarshal(&stats)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if stats.HttpCode2xx != 4532188.710192006 {
|
||||
t.Fatalf("duration.2XX: %f", stats.HttpCode2xx)
|
||||
}
|
||||
if stats.HttpCode4xx != 196870.22898800002 {
|
||||
t.Fatalf("duration.4XX: %f", stats.HttpCode4xx)
|
||||
}
|
||||
if stats.HttpCode5xx != 32787.14909299999 {
|
||||
t.Fatalf("duration.5XX: %f", stats.HttpCode5xx)
|
||||
}
|
||||
if stats.HitHttpCode2xx != 88678 {
|
||||
t.Fatalf("hit.2XX: %d", stats.HitHttpCode2xx)
|
||||
}
|
||||
if stats.HitHttpCode4xx != 1748 {
|
||||
t.Fatalf("hit.4XX: %d", stats.HitHttpCode4xx)
|
||||
}
|
||||
if stats.HitHttpCode5xx != 179 {
|
||||
t.Fatalf("hit.5XX: %d", stats.HitHttpCode5xx)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHttpStats(t *testing.T) {
|
||||
cases := []struct {
|
||||
prevTime time.Time
|
||||
nowTime time.Time
|
||||
prevStats *sApiHttpStats
|
||||
nowStats sApiHttpStats
|
||||
}{
|
||||
{
|
||||
nowTime: func() time.Time {
|
||||
tm, _ := timeutils.ParseTimeStr("2025-06-01 00:01:00")
|
||||
return tm
|
||||
}(),
|
||||
nowStats: sApiHttpStats{
|
||||
SHttpStats: SHttpStats{
|
||||
HttpCode2xx: 400,
|
||||
HttpCode4xx: 700,
|
||||
HttpCode5xx: 1000,
|
||||
HitHttpCode2xx: 4000,
|
||||
HitHttpCode4xx: 7000,
|
||||
HitHttpCode5xx: 10000,
|
||||
},
|
||||
Paths: []SHttpStats{
|
||||
{
|
||||
HttpCode2xx: 150,
|
||||
HttpCode4xx: 250,
|
||||
HttpCode5xx: 310,
|
||||
HitHttpCode2xx: 1500,
|
||||
HitHttpCode4xx: 2500,
|
||||
HitHttpCode5xx: 3500,
|
||||
Method: "GET",
|
||||
Path: "/servers",
|
||||
Name: "list_servers",
|
||||
},
|
||||
{
|
||||
HttpCode2xx: 150,
|
||||
HttpCode4xx: 250,
|
||||
HttpCode5xx: 350,
|
||||
HitHttpCode2xx: 1500,
|
||||
HitHttpCode4xx: 2500,
|
||||
HitHttpCode5xx: 3500,
|
||||
Method: "POST",
|
||||
Path: "/servers",
|
||||
Name: "create_servers",
|
||||
},
|
||||
{
|
||||
HttpCode2xx: 100,
|
||||
HttpCode4xx: 200,
|
||||
HttpCode5xx: 300,
|
||||
HitHttpCode2xx: 1000,
|
||||
HitHttpCode4xx: 2000,
|
||||
HitHttpCode5xx: 3000,
|
||||
Method: "PUT",
|
||||
Path: "/servers/*",
|
||||
Name: "update_servers",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
prevTime: func() time.Time {
|
||||
tm, _ := timeutils.ParseTimeStr("2025-06-01 00:00:00")
|
||||
return tm
|
||||
}(),
|
||||
nowTime: func() time.Time {
|
||||
tm, _ := timeutils.ParseTimeStr("2025-06-01 00:01:00")
|
||||
return tm
|
||||
}(),
|
||||
prevStats: &sApiHttpStats{
|
||||
SHttpStats: SHttpStats{
|
||||
HttpCode2xx: 200,
|
||||
HttpCode4xx: 400,
|
||||
HttpCode5xx: 600,
|
||||
HitHttpCode2xx: 2000,
|
||||
HitHttpCode4xx: 4000,
|
||||
HitHttpCode5xx: 6000,
|
||||
},
|
||||
Paths: []SHttpStats{
|
||||
{
|
||||
HttpCode2xx: 100,
|
||||
HttpCode4xx: 200,
|
||||
HttpCode5xx: 300,
|
||||
HitHttpCode2xx: 1000,
|
||||
HitHttpCode4xx: 2000,
|
||||
HitHttpCode5xx: 3000,
|
||||
Method: "GET",
|
||||
Path: "/servers",
|
||||
Name: "list_servers",
|
||||
},
|
||||
{
|
||||
HttpCode2xx: 100,
|
||||
HttpCode4xx: 200,
|
||||
HttpCode5xx: 300,
|
||||
HitHttpCode2xx: 1000,
|
||||
HitHttpCode4xx: 2000,
|
||||
HitHttpCode5xx: 3000,
|
||||
Method: "POST",
|
||||
Path: "/servers",
|
||||
Name: "create_servers",
|
||||
},
|
||||
},
|
||||
},
|
||||
nowStats: sApiHttpStats{
|
||||
SHttpStats: SHttpStats{
|
||||
HttpCode2xx: 400,
|
||||
HttpCode4xx: 700,
|
||||
HttpCode5xx: 1000,
|
||||
HitHttpCode2xx: 4000,
|
||||
HitHttpCode4xx: 7000,
|
||||
HitHttpCode5xx: 10000,
|
||||
},
|
||||
Paths: []SHttpStats{
|
||||
{
|
||||
HttpCode2xx: 150,
|
||||
HttpCode4xx: 250,
|
||||
HttpCode5xx: 310,
|
||||
HitHttpCode2xx: 1500,
|
||||
HitHttpCode4xx: 2500,
|
||||
HitHttpCode5xx: 3500,
|
||||
Method: "GET",
|
||||
Path: "/servers",
|
||||
Name: "list_servers",
|
||||
},
|
||||
{
|
||||
HttpCode2xx: 150,
|
||||
HttpCode4xx: 250,
|
||||
HttpCode5xx: 350,
|
||||
HitHttpCode2xx: 1500,
|
||||
HitHttpCode4xx: 2500,
|
||||
HitHttpCode5xx: 3500,
|
||||
Method: "POST",
|
||||
Path: "/servers",
|
||||
Name: "create_servers",
|
||||
},
|
||||
{
|
||||
HttpCode2xx: 100,
|
||||
HttpCode4xx: 200,
|
||||
HttpCode5xx: 300,
|
||||
HitHttpCode2xx: 1000,
|
||||
HitHttpCode4xx: 2000,
|
||||
HitHttpCode5xx: 3000,
|
||||
Method: "PUT",
|
||||
Path: "/servers/*",
|
||||
Name: "update_servers",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, c := range cases {
|
||||
var prev *sHttpStatsSnapshot
|
||||
if c.prevStats != nil {
|
||||
prev = c.prevStats.convertSnapshot(c.prevTime)
|
||||
}
|
||||
curr := c.nowStats.convertSnapshot(c.nowTime)
|
||||
diff := calculateHttpStatsDiff(prev, curr)
|
||||
metrics := diff.metrics("test", "test", "test", "test")
|
||||
t.Log(jsonutils.Marshal(metrics).PrettyString())
|
||||
}
|
||||
}
|
||||
@@ -110,9 +110,11 @@ func getNetworkAddrMap(s *mcclient.ClientSession, netId string) (map[string]api.
|
||||
return nil, errors.Wrap(err, "GetSpecific addresses")
|
||||
}
|
||||
addrList := make([]api.SNetworkUsedAddress, 0)
|
||||
err = addrListJson.Unmarshal(&addrList, "addresses")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Unmarshal addreses")
|
||||
if addrListJson.Contains("addresses") {
|
||||
err = addrListJson.Unmarshal(&addrList, "addresses")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Unmarshal addreses")
|
||||
}
|
||||
}
|
||||
addrMap := make(map[string]api.SNetworkUsedAddress)
|
||||
for i := range addrList {
|
||||
|
||||
40
pkg/cloudmon/misc/send.go
Normal file
40
pkg/cloudmon/misc/send.go
Normal file
@@ -0,0 +1,40 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// 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.
|
||||
|
||||
package misc
|
||||
|
||||
import (
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/tsdb"
|
||||
"yunion.io/x/onecloud/pkg/cloudmon/options"
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
"yunion.io/x/onecloud/pkg/util/influxdb"
|
||||
)
|
||||
|
||||
func sendMetrics(sess *mcclient.ClientSession, metrics []influxdb.SMetricData, database string) error {
|
||||
if len(metrics) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
urls, err := tsdb.GetDefaultServiceSourceURLs(sess, options.Options.SessionEndpointType)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "GetServiceURLs")
|
||||
}
|
||||
err = influxdb.SendMetrics(urls, database, metrics, false)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "SendMetrics")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
137
pkg/cloudmon/misc/statusprobe.go
Normal file
137
pkg/cloudmon/misc/statusprobe.go
Normal file
@@ -0,0 +1,137 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// 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.
|
||||
|
||||
package misc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/apis"
|
||||
"yunion.io/x/onecloud/pkg/cloudmon/options"
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/auth"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/modulebase"
|
||||
baseOptions "yunion.io/x/onecloud/pkg/mcclient/options"
|
||||
"yunion.io/x/onecloud/pkg/util/influxdb"
|
||||
)
|
||||
|
||||
func StatusProbe(ctx context.Context, userCred mcclient.TokenCredential, isStart bool) {
|
||||
if options.Options.EnableStatusProbeDebug {
|
||||
log.Debugf("Start resource status probe")
|
||||
}
|
||||
|
||||
if !options.Options.EnableStatusProbe {
|
||||
if options.Options.EnableStatusProbeDebug {
|
||||
log.Debugf("Resource status probe is disabled")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
sess := auth.GetSession(ctx, userCred, options.Options.Region)
|
||||
metrics := make([]influxdb.SMetricData, 0)
|
||||
for _, model := range options.Options.StatusProbeModels {
|
||||
mts, err := doModelStatusProbe(sess, model)
|
||||
if err != nil {
|
||||
log.Errorf("doModelStatusProbe failed: %s", err)
|
||||
}
|
||||
metrics = append(metrics, mts...)
|
||||
}
|
||||
|
||||
err := sendMetrics(sess, metrics, "system")
|
||||
if err != nil {
|
||||
log.Errorf("StatusProbe SendMetrics error: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func doModelStatusProbe(sess *mcclient.ClientSession, modelName string) ([]influxdb.SMetricData, error) {
|
||||
model, err := modulebase.GetModule(sess, modelName)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "GetModule")
|
||||
}
|
||||
|
||||
listOpts := baseOptions.BaseListOptions{}
|
||||
listOpts.Scope = "max"
|
||||
listOpts.SummaryStats = true
|
||||
limit := 0
|
||||
listOpts.Limit = &limit
|
||||
|
||||
results, err := model.List(sess, jsonutils.Marshal(listOpts))
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "List")
|
||||
}
|
||||
|
||||
statusInfoTotal := struct {
|
||||
apis.TotalCountBase
|
||||
StatusInfo []apis.StatusStatisticStatusInfo
|
||||
}{}
|
||||
|
||||
err = results.Totals.Unmarshal(&statusInfoTotal)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Unmarshal statusInfoTotal")
|
||||
}
|
||||
|
||||
log.Infof("statusInfoTotal: %s", jsonutils.Marshal(statusInfoTotal))
|
||||
|
||||
metrics := make([]influxdb.SMetricData, 0)
|
||||
|
||||
totalCount := int64(0)
|
||||
pendingDeletedCount := int64(0)
|
||||
for _, statusInfo := range statusInfoTotal.StatusInfo {
|
||||
metrics = append(metrics, genStatusMetricData(model, statusInfo.Status, statusInfo.TotalCount, statusInfo.PendingDeletedCount))
|
||||
totalCount += statusInfo.TotalCount
|
||||
pendingDeletedCount += statusInfo.PendingDeletedCount
|
||||
}
|
||||
metrics = append(metrics, genStatusMetricData(model, "total", totalCount, pendingDeletedCount))
|
||||
|
||||
if options.Options.EnableStatusProbeDebug {
|
||||
log.Debugf("StatusProbe for model %s metrics: %s", modelName, jsonutils.Marshal(metrics))
|
||||
}
|
||||
|
||||
return metrics, nil
|
||||
}
|
||||
|
||||
func genStatusMetricData(model modulebase.Manager, status string, count int64, pendingDeletedCount int64) influxdb.SMetricData {
|
||||
return influxdb.SMetricData{
|
||||
Name: "status_probe",
|
||||
Tags: influxdb.TKeyValuePairs{
|
||||
influxdb.SKeyValue{
|
||||
Key: "service",
|
||||
Value: model.ServiceType(),
|
||||
},
|
||||
influxdb.SKeyValue{
|
||||
Key: "model",
|
||||
Value: model.GetKeyword(),
|
||||
},
|
||||
influxdb.SKeyValue{
|
||||
Key: "status",
|
||||
Value: status,
|
||||
},
|
||||
},
|
||||
Metrics: influxdb.TKeyValuePairs{
|
||||
influxdb.SKeyValue{
|
||||
Key: "count",
|
||||
Value: fmt.Sprintf("%d", count),
|
||||
},
|
||||
influxdb.SKeyValue{
|
||||
Key: "pending_deleted",
|
||||
Value: fmt.Sprintf("%d", pendingDeletedCount),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,9 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
@@ -26,7 +29,6 @@ import (
|
||||
"yunion.io/x/pkg/errors"
|
||||
"yunion.io/x/pkg/gotypes"
|
||||
"yunion.io/x/pkg/util/httputils"
|
||||
"yunion.io/x/pkg/util/version"
|
||||
"yunion.io/x/pkg/utils"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/apis"
|
||||
@@ -38,6 +40,7 @@ import (
|
||||
"yunion.io/x/onecloud/pkg/mcclient/auth"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/modules/compute"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/modules/identity"
|
||||
baseoptions "yunion.io/x/onecloud/pkg/mcclient/options"
|
||||
"yunion.io/x/onecloud/pkg/util/influxdb"
|
||||
)
|
||||
|
||||
@@ -50,19 +53,73 @@ const (
|
||||
METIRCY_TYPE_PROCESS = "process"
|
||||
)
|
||||
|
||||
func getEndpoints(ctx context.Context, s *mcclient.ClientSession) ([]api.EndpointDetails, error) {
|
||||
resp, err := identity.EndpointsV3.List(s, jsonutils.Marshal(map[string]string{
|
||||
"scope": "system",
|
||||
"enable": "true",
|
||||
"details": "true",
|
||||
"interface": "internal",
|
||||
"limit": "50",
|
||||
}))
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "Endpoints.List")
|
||||
func getEndpoints(s *mcclient.ClientSession) ([]api.EndpointDetails, error) {
|
||||
ret := make([]api.EndpointDetails, 0)
|
||||
params := baseoptions.BaseListOptions{}
|
||||
limit := 1024
|
||||
params.Limit = &limit
|
||||
boolTrue := true
|
||||
params.Details = &boolTrue
|
||||
params.Scope = "system"
|
||||
params.Filter = []string{
|
||||
"interface.equals(internal)",
|
||||
"enabled.equals(1)",
|
||||
}
|
||||
ret := []api.EndpointDetails{}
|
||||
return ret, jsonutils.Update(&ret, resp.Data)
|
||||
|
||||
for {
|
||||
offset := len(ret)
|
||||
params.Offset = &offset
|
||||
resp, err := identity.EndpointsV3.List(s, jsonutils.Marshal(params))
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "Endpoints.List")
|
||||
}
|
||||
for i := range resp.Data {
|
||||
endpoint := api.EndpointDetails{}
|
||||
err := resp.Data[i].Unmarshal(&endpoint)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "Unmarshal")
|
||||
}
|
||||
ret = append(ret, endpoint)
|
||||
}
|
||||
if len(ret) >= resp.Total {
|
||||
break
|
||||
}
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func getHosts(s *mcclient.ClientSession) ([]compute_api.HostDetails, error) {
|
||||
params := compute_api.HostListInput{}
|
||||
boolFalse := false
|
||||
limit := 100
|
||||
params.Limit = &limit
|
||||
params.Brand = []string{compute_api.CLOUD_PROVIDER_ONECLOUD}
|
||||
params.Scope = "system"
|
||||
params.Status = []string{compute_api.HOST_STATUS_RUNNING}
|
||||
params.HostStatus = []string{compute_api.HOST_ONLINE}
|
||||
params.Details = &boolFalse
|
||||
|
||||
hosts := []compute_api.HostDetails{}
|
||||
for {
|
||||
offset := len(hosts)
|
||||
params.Offset = &offset
|
||||
resp, err := compute.Hosts.List(s, jsonutils.Marshal(params))
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "Hosts.List")
|
||||
}
|
||||
for i := range resp.Data {
|
||||
host := compute_api.HostDetails{}
|
||||
err := resp.Data[i].Unmarshal(&host)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "Unmarshal")
|
||||
}
|
||||
hosts = append(hosts, host)
|
||||
}
|
||||
if len(hosts) >= resp.Total {
|
||||
break
|
||||
}
|
||||
}
|
||||
return hosts, nil
|
||||
}
|
||||
|
||||
func CollectServiceMetrics(ctx context.Context, userCred mcclient.TokenCredential, isStart bool) {
|
||||
@@ -77,18 +134,13 @@ func CollectServiceMetrics(ctx context.Context, userCred mcclient.TokenCredentia
|
||||
|
||||
tk := auth.AdminCredential().GetTokenString()
|
||||
err = func() error {
|
||||
endpoints, err := getEndpoints(ctx, s)
|
||||
endpoints, err := getEndpoints(s)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "getEndpoints")
|
||||
}
|
||||
metrics := []influxdb.SMetricData{}
|
||||
for _, ep := range endpoints {
|
||||
if utils.IsInStringArray(ep.ServiceType, apis.NO_RESOURCE_SERVICES) || utils.IsInStringArray(ep.ServiceType, []string{
|
||||
apis.SERVICE_TYPE_IMAGE,
|
||||
apis.SERVICE_TYPE_MONITOR,
|
||||
apis.SERVICE_TYPE_VICTORIA_METRICS,
|
||||
"k8s",
|
||||
}) {
|
||||
if utils.IsInStringArray(ep.ServiceType, apis.EXTERNAL_SERVICES) {
|
||||
continue
|
||||
}
|
||||
url := httputils.JoinPath(ep.Url, "version")
|
||||
@@ -114,52 +166,40 @@ func CollectServiceMetrics(ctx context.Context, userCred mcclient.TokenCredentia
|
||||
}
|
||||
metrics = append(metrics, part...)
|
||||
}
|
||||
return influxdb.SendMetrics(urls, SYSTEM_METRIC_DATABASE, metrics, false)
|
||||
if len(metrics) > 0 {
|
||||
err := influxdb.SendMetrics(urls, SYSTEM_METRIC_DATABASE, metrics, false)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "SendMetrics")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}()
|
||||
if err != nil {
|
||||
log.Errorf("collect service metric error: %v", err)
|
||||
}
|
||||
params := compute_api.HostListInput{}
|
||||
limit := 20
|
||||
params.Limit = &limit
|
||||
params.Brand = []string{compute_api.CLOUD_PROVIDER_ONECLOUD}
|
||||
params.Scope = "system"
|
||||
params.Status = []string{compute_api.HOST_STATUS_RUNNING}
|
||||
details := false
|
||||
params.Details = &details
|
||||
hosts := []compute_api.HostDetails{}
|
||||
for {
|
||||
offset := len(hosts)
|
||||
params.Offset = &offset
|
||||
resp, err := compute.Hosts.List(s, jsonutils.Marshal(params))
|
||||
|
||||
{
|
||||
hosts, err := getHosts(s)
|
||||
if err != nil {
|
||||
return
|
||||
log.Errorf("get hosts error: %v", err)
|
||||
}
|
||||
part := []compute_api.HostDetails{}
|
||||
err = jsonutils.Update(&part, resp.Data)
|
||||
if err != nil {
|
||||
return
|
||||
metrics := []influxdb.SMetricData{}
|
||||
for _, host := range hosts {
|
||||
part := collectHostMetrics(ctx, host, tk)
|
||||
metrics = append(metrics, part...)
|
||||
}
|
||||
hosts = append(hosts, part...)
|
||||
if len(hosts) >= resp.Total {
|
||||
break
|
||||
if len(metrics) > 0 {
|
||||
err := influxdb.SendMetrics(urls, SYSTEM_METRIC_DATABASE, metrics, false)
|
||||
if err != nil {
|
||||
log.Errorf("send host metrics error: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
metrics := []influxdb.SMetricData{}
|
||||
for _, host := range hosts {
|
||||
service := fmt.Sprintf("host-%s", host.Name)
|
||||
part, err := collectWorkerMetrics(ctx, host.ManagerUri, service, version.GetShortString(), tk)
|
||||
if err != nil {
|
||||
log.Errorf("collect host %s metric error: %v", service, err)
|
||||
continue
|
||||
}
|
||||
metrics = append(metrics, part...)
|
||||
}
|
||||
influxdb.SendMetrics(urls, SYSTEM_METRIC_DATABASE, metrics, false)
|
||||
}
|
||||
|
||||
func collectStatsMetrics(ctx context.Context, ep api.EndpointDetails, version, token string) ([]influxdb.SMetricData, error) {
|
||||
statsUrl := httputils.JoinPath(ep.Url, "stats")
|
||||
func collectApiStatsMetrics(ctx context.Context, serviceName string, serviceType string, regionId string, url string, version, token string) ([]influxdb.SMetricData, error) {
|
||||
log.Debugf("collectApiStatsMetrics %s %s %s %s %s", serviceName, serviceType, regionId, url, version)
|
||||
statsUrl := httputils.JoinPath(baseUrlF(url), "stats")
|
||||
hdr := http.Header{}
|
||||
hdr.Set("X-Auth-Token", token)
|
||||
_, ret, err := httputils.JSONRequest(
|
||||
@@ -175,131 +215,19 @@ func collectStatsMetrics(ctx context.Context, ep api.EndpointDetails, version, t
|
||||
return []influxdb.SMetricData{}, nil
|
||||
}
|
||||
|
||||
stats := struct {
|
||||
HttpCode2xx float64 `json:"duration.2XX"`
|
||||
HttpCode4xx float64 `json:"duration.4XX"`
|
||||
HttpCode5xx float64 `json:"duration.5XX"`
|
||||
HitHttpCode2xx int `json:"hit.2XX"`
|
||||
HitHttpCode4xx int `json:"hit.4XX"`
|
||||
HitHttpCode5xx int `json:"hit.5XX"`
|
||||
Paths []struct {
|
||||
HttpCode2xx float64 `json:"duration.2XX"`
|
||||
HttpCode4xx float64 `json:"duration.4XX"`
|
||||
HttpCode5xx float64 `json:"duration.5XX"`
|
||||
HitHttpCode2xx int `json:"hit.2XX"`
|
||||
HitHttpCode4xx int `json:"hit.4XX"`
|
||||
HitHttpCode5xx int `json:"hit.5XX"`
|
||||
Method string
|
||||
Name string
|
||||
Path string
|
||||
} `json:"paths"`
|
||||
}{}
|
||||
stats := sApiHttpStats{}
|
||||
err = ret.Unmarshal(&stats)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "Unmarshal")
|
||||
}
|
||||
result := []influxdb.SMetricData{}
|
||||
metric := influxdb.SMetricData{
|
||||
Name: METIRCY_TYPE_HTTP_REQUST,
|
||||
Timestamp: time.Now(),
|
||||
Tags: []influxdb.SKeyValue{
|
||||
{
|
||||
Key: "version",
|
||||
Value: version,
|
||||
},
|
||||
{
|
||||
Key: "service",
|
||||
Value: ep.ServiceName,
|
||||
},
|
||||
},
|
||||
Metrics: []influxdb.SKeyValue{
|
||||
{
|
||||
Key: "duration.2xx",
|
||||
Value: fmt.Sprintf("%.2f", stats.HttpCode2xx),
|
||||
},
|
||||
{
|
||||
Key: "duration.4xx",
|
||||
Value: fmt.Sprintf("%.2f", stats.HttpCode4xx),
|
||||
},
|
||||
{
|
||||
Key: "duration.5xx",
|
||||
Value: fmt.Sprintf("%.2f", stats.HttpCode5xx),
|
||||
},
|
||||
{
|
||||
Key: "hit.2xx",
|
||||
Value: fmt.Sprintf("%d", stats.HitHttpCode2xx),
|
||||
},
|
||||
{
|
||||
Key: "hit.4xx",
|
||||
Value: fmt.Sprintf("%d", stats.HitHttpCode4xx),
|
||||
},
|
||||
{
|
||||
Key: "hit.5xx",
|
||||
Value: fmt.Sprintf("%d", stats.HitHttpCode5xx),
|
||||
},
|
||||
},
|
||||
}
|
||||
result = append(result, metric)
|
||||
for _, path := range stats.Paths {
|
||||
metric = influxdb.SMetricData{
|
||||
Name: METIRCY_TYPE_HTTP_REQUST,
|
||||
Timestamp: time.Now(),
|
||||
Tags: []influxdb.SKeyValue{
|
||||
{
|
||||
Key: "version",
|
||||
Value: version,
|
||||
},
|
||||
{
|
||||
Key: "service",
|
||||
Value: ep.ServiceName,
|
||||
},
|
||||
{
|
||||
Key: "method",
|
||||
Value: path.Method,
|
||||
},
|
||||
{
|
||||
Key: "path",
|
||||
Value: path.Path,
|
||||
},
|
||||
{
|
||||
Key: "url",
|
||||
Value: path.Name,
|
||||
},
|
||||
},
|
||||
Metrics: []influxdb.SKeyValue{
|
||||
{
|
||||
Key: "duration.2xx",
|
||||
Value: fmt.Sprintf("%.2f", path.HttpCode2xx),
|
||||
},
|
||||
{
|
||||
Key: "duration.4xx",
|
||||
Value: fmt.Sprintf("%.2f", path.HttpCode4xx),
|
||||
},
|
||||
{
|
||||
Key: "duration.5xx",
|
||||
Value: fmt.Sprintf("%.2f", path.HttpCode5xx),
|
||||
},
|
||||
{
|
||||
Key: "hit.2xx",
|
||||
Value: fmt.Sprintf("%d", path.HitHttpCode2xx),
|
||||
},
|
||||
{
|
||||
Key: "hit.4xx",
|
||||
Value: fmt.Sprintf("%d", path.HitHttpCode4xx),
|
||||
},
|
||||
{
|
||||
Key: "hit.5xx",
|
||||
Value: fmt.Sprintf("%d", path.HitHttpCode5xx),
|
||||
},
|
||||
},
|
||||
}
|
||||
result = append(result, metric)
|
||||
}
|
||||
return result, nil
|
||||
|
||||
metrics := updateHttpStatsSnapshot(serviceName, url, time.Now(), stats, serviceType, regionId, version)
|
||||
|
||||
return metrics, nil
|
||||
}
|
||||
|
||||
func collectWorkerMetrics(ctx context.Context, url, service, version, token string) ([]influxdb.SMetricData, error) {
|
||||
statsUrl := httputils.JoinPath(url, "worker_stats")
|
||||
func collectWorkerMetrics(ctx context.Context, url, service, serviceType, regionId, version, token string) ([]influxdb.SMetricData, error) {
|
||||
statsUrl := httputils.JoinPath(baseUrlF(url), "worker_stats")
|
||||
hdr := http.Header{}
|
||||
hdr.Set("X-Auth-Token", token)
|
||||
_, ret, err := httputils.JSONRequest(
|
||||
@@ -344,6 +272,14 @@ func collectWorkerMetrics(ctx context.Context, url, service, version, token stri
|
||||
Key: "service",
|
||||
Value: service,
|
||||
},
|
||||
{
|
||||
Key: "service_type",
|
||||
Value: serviceType,
|
||||
},
|
||||
{
|
||||
Key: "region",
|
||||
Value: regionId,
|
||||
},
|
||||
{
|
||||
Key: "worker_name",
|
||||
Value: worker.Name,
|
||||
@@ -366,6 +302,14 @@ func collectWorkerMetrics(ctx context.Context, url, service, version, token stri
|
||||
Key: "queue_cnt",
|
||||
Value: fmt.Sprintf("%d", worker.QueueCnt),
|
||||
},
|
||||
{
|
||||
Key: "total_workload",
|
||||
Value: fmt.Sprintf("%d", worker.ActiveWorkerCnt+worker.QueueCnt+worker.DetachWorkerCnt),
|
||||
},
|
||||
{
|
||||
Key: "active_workload",
|
||||
Value: fmt.Sprintf("%d", worker.ActiveWorkerCnt+worker.DetachWorkerCnt),
|
||||
},
|
||||
},
|
||||
}
|
||||
result = append(result, metric)
|
||||
@@ -375,7 +319,7 @@ func collectWorkerMetrics(ctx context.Context, url, service, version, token stri
|
||||
}
|
||||
|
||||
func collectDatabaseMetrics(ctx context.Context, ep api.EndpointDetails, version, token string) ([]influxdb.SMetricData, error) {
|
||||
statsUrl := httputils.JoinPath(ep.Url, "db_stats")
|
||||
statsUrl := httputils.JoinPath(baseUrlF(ep.Url), "db_stats")
|
||||
hdr := http.Header{}
|
||||
hdr.Set("X-Auth-Token", token)
|
||||
_, ret, err := httputils.JSONRequest(
|
||||
@@ -462,7 +406,7 @@ func collectDatabaseMetrics(ctx context.Context, ep api.EndpointDetails, version
|
||||
}
|
||||
|
||||
func collectProcessMetrics(ctx context.Context, ep api.EndpointDetails, version, token string) ([]influxdb.SMetricData, error) {
|
||||
statsUrl := httputils.JoinPath(ep.Url, "process_stats")
|
||||
statsUrl := httputils.JoinPath(baseUrlF(ep.Url), "process_stats")
|
||||
hdr := http.Header{}
|
||||
hdr.Set("X-Auth-Token", token)
|
||||
_, ret, err := httputils.JSONRequest(
|
||||
@@ -518,14 +462,28 @@ func collectProcessMetrics(ctx context.Context, ep api.EndpointDetails, version,
|
||||
return []influxdb.SMetricData{metric}, nil
|
||||
}
|
||||
|
||||
func baseUrlF(baseurl string) string {
|
||||
obj, _ := url.Parse(baseurl)
|
||||
lastSlashPos := strings.LastIndex(obj.Path, "/")
|
||||
if lastSlashPos >= 0 {
|
||||
lastSeg := obj.Path[lastSlashPos+1:]
|
||||
verReg := regexp.MustCompile(`^v\d+`)
|
||||
if verReg.MatchString(lastSeg) {
|
||||
obj.Path = obj.Path[:lastSlashPos]
|
||||
}
|
||||
}
|
||||
ret := obj.String()
|
||||
return ret
|
||||
}
|
||||
|
||||
func collectServiceMetrics(ctx context.Context, ep api.EndpointDetails, version, token string) ([]influxdb.SMetricData, error) {
|
||||
ret, errs := []influxdb.SMetricData{}, []error{}
|
||||
stats, err := collectStatsMetrics(ctx, ep, version, token)
|
||||
stats, err := collectApiStatsMetrics(ctx, ep.ServiceName, ep.ServiceType, ep.RegionId, ep.Url, version, token)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
ret = append(ret, stats...)
|
||||
worker, err := collectWorkerMetrics(ctx, ep.Url, ep.ServiceName, version, token)
|
||||
worker, err := collectWorkerMetrics(ctx, ep.Url, ep.ServiceName, ep.ServiceType, ep.RegionId, version, token)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
@@ -542,3 +500,21 @@ func collectServiceMetrics(ctx context.Context, ep api.EndpointDetails, version,
|
||||
ret = append(ret, process...)
|
||||
return ret, errors.NewAggregate(errs)
|
||||
}
|
||||
|
||||
func collectHostMetrics(ctx context.Context, host compute_api.HostDetails, token string) []influxdb.SMetricData {
|
||||
metrics := []influxdb.SMetricData{}
|
||||
service := fmt.Sprintf("host-%s", host.Name)
|
||||
part, err := collectWorkerMetrics(ctx, host.ManagerUri, service, "host", host.Region, host.Version, token)
|
||||
if err != nil {
|
||||
log.Errorf("collect host %s metric error: %v", service, err)
|
||||
} else {
|
||||
metrics = append(metrics, part...)
|
||||
}
|
||||
part, err = collectApiStatsMetrics(ctx, service, "host", host.Region, host.ManagerUri, host.Version, token)
|
||||
if err != nil {
|
||||
log.Errorf("collect host %s metric error: %v", service, err)
|
||||
} else {
|
||||
metrics = append(metrics, part...)
|
||||
}
|
||||
return metrics
|
||||
}
|
||||
|
||||
@@ -37,6 +37,17 @@ type CloudMonOptions struct {
|
||||
CloudAccountCollectMetricsBatchCount int `help:"Cloud Account Collect Metrics Batch Count" default:"10"`
|
||||
CloudResourceCollectMetricsBatchCount int `help:"Cloud Resource Collect Metrics BatchC ount" default:"40"`
|
||||
OracleCloudResourceCollectMetricsBatchCount int `help:"OracleCloud Resource Collect Metrics BatchC ount" default:"1"`
|
||||
|
||||
StatusProbeIntervalMinutes int `help:"Status Probe Interval unit:minute" default:"15"`
|
||||
StatusProbeModels []string `help:"Status Probe Models" default:"compute-servers,compute-hosts"`
|
||||
EnableStatusProbe bool `help:"Enable Status Probe" default:"false"`
|
||||
EnableStatusProbeDebug bool `help:"Enable Status Probe Debug" default:"false"`
|
||||
|
||||
BucketProbeIntervalMinutes int `help:"Bucket Probe Interval unit:minute" default:"15"`
|
||||
EnableBucketProbe bool `help:"Enable Bucket Probe" default:"false"`
|
||||
EnableBucketProbeDebug bool `help:"Enable Bucket Probe Debug" default:"false"`
|
||||
BucketProbeTestKey string `help:"Bucket Probe Test Key" default:"bucket_performance_test_object"`
|
||||
BucketProbeTestSizeMb int `help:"Bucket Probe Test Size" default:"4"`
|
||||
}
|
||||
|
||||
type PingProbeOptions struct {
|
||||
|
||||
@@ -33,6 +33,7 @@ import (
|
||||
"yunion.io/x/onecloud/pkg/cloudmon/options"
|
||||
"yunion.io/x/onecloud/pkg/cloudmon/resources"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/auth"
|
||||
_ "yunion.io/x/onecloud/pkg/mcclient/modules/loader"
|
||||
)
|
||||
|
||||
func StartService() {
|
||||
@@ -57,6 +58,10 @@ func StartService() {
|
||||
|
||||
cron.AddJobAtIntervalsWithStartRun("PingProb", time.Duration(opts.PingProbIntervalHours)*time.Hour, misc.PingProbe, true)
|
||||
|
||||
cron.AddJobAtIntervalsWithStartRun("StatusProbe", time.Duration(opts.StatusProbeIntervalMinutes)*time.Minute, misc.StatusProbe, true)
|
||||
|
||||
cron.AddJobAtIntervalsWithStartRun("BucketProbe", time.Duration(opts.BucketProbeIntervalMinutes)*time.Minute, misc.BucketProbe, true)
|
||||
|
||||
cron.AddJobEveryFewDays("UsageMetricCollect", 1, 23, 10, 10, misc.UsegReport, false)
|
||||
cron.AddJobEveryFewDays("AlertHistoryMetricCollect", 1, 23, 59, 59, misc.AlertHistoryReport, false)
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ import (
|
||||
|
||||
"yunion.io/x/onecloud/pkg/apis"
|
||||
api "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
hostapi "yunion.io/x/onecloud/pkg/apis/host"
|
||||
"yunion.io/x/onecloud/pkg/compute/models"
|
||||
"yunion.io/x/onecloud/pkg/httperrors"
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
@@ -64,8 +65,7 @@ func (d disk) GetType() apis.ContainerVolumeMountType {
|
||||
return apis.CONTAINER_VOLUME_MOUNT_TYPE_DISK
|
||||
}
|
||||
|
||||
func (d disk) validateCreateData(ctx context.Context, userCred mcclient.TokenCredential, vm *apis.ContainerVolumeMount) (*apis.ContainerVolumeMount, error) {
|
||||
disk := vm.Disk
|
||||
func (d disk) validateDiskCreateData(ctx context.Context, userCred mcclient.TokenCredential, disk *apis.ContainerVolumeMountDisk) (*apis.ContainerVolumeMountDisk, error) {
|
||||
if disk == nil {
|
||||
return nil, httperrors.NewNotEmptyError("disk is nil")
|
||||
}
|
||||
@@ -77,6 +77,15 @@ func (d disk) validateCreateData(ctx context.Context, userCred mcclient.TokenCre
|
||||
return nil, httperrors.NewInputParameterError("index is less than 0")
|
||||
}
|
||||
}
|
||||
return disk, nil
|
||||
}
|
||||
|
||||
func (d disk) validateCreateData(ctx context.Context, userCred mcclient.TokenCredential, vm *apis.ContainerVolumeMount) (*apis.ContainerVolumeMount, error) {
|
||||
disk, err := d.validateDiskCreateData(ctx, userCred, vm.Disk)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
vm.Disk = disk
|
||||
return vm, nil
|
||||
}
|
||||
|
||||
@@ -102,31 +111,61 @@ func (d disk) validateCaseInsensitive(disk *models.SDisk, vm *apis.ContainerVolu
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d disk) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, pod *models.SGuest, vm *apis.ContainerVolumeMount) (*apis.ContainerVolumeMount, error) {
|
||||
if _, err := d.validateCreateData(ctx, userCred, vm); err != nil {
|
||||
return nil, err
|
||||
func (d disk) ValidateRootFsCreateData(ctx context.Context, userCred mcclient.TokenCredential, pod *models.SGuest, rootFs *apis.ContainerRootfs) error {
|
||||
disk, err := d.validateDiskCreateData(ctx, userCred, rootFs.Disk)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
disk, _, err = d.validateDiskIndex(ctx, userCred, pod, disk)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rootFs.Disk = disk
|
||||
if rootFs.Disk.Overlay != nil {
|
||||
return httperrors.NewInputParameterError("can't use overlay and root_fs at the same time")
|
||||
}
|
||||
if len(rootFs.Disk.PostOverlay) > 0 {
|
||||
return httperrors.NewInputParameterError("can't use post_overlay and root_fs at the same time")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d disk) ToHostRootFs(rootFs *apis.ContainerRootfs) (*hostapi.ContainerRootfs, error) {
|
||||
diskObj := models.DiskManager.FetchDiskById(rootFs.Disk.Id)
|
||||
if diskObj == nil {
|
||||
return nil, errors.Wrapf(httperrors.ErrNotFound, "fetch disk %s", rootFs.Disk.Id)
|
||||
}
|
||||
disk := rootFs.Disk
|
||||
return &hostapi.ContainerRootfs{
|
||||
Type: rootFs.Type,
|
||||
Disk: &hostapi.ContainerVolumeMountDisk{
|
||||
Index: disk.Index,
|
||||
Id: disk.Id,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d disk) validateDiskIndex(ctx context.Context, userCred mcclient.TokenCredential, pod *models.SGuest, disk *apis.ContainerVolumeMountDisk) (*apis.ContainerVolumeMountDisk, *models.SDisk, error) {
|
||||
disks, err := pod.GetDisks()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "get pod disks")
|
||||
return nil, nil, errors.Wrap(err, "get pod disks")
|
||||
}
|
||||
disk := vm.Disk
|
||||
var diskObj models.SDisk
|
||||
if disk.Index != nil {
|
||||
diskIndex := *disk.Index
|
||||
if diskIndex >= len(disks) {
|
||||
return nil, httperrors.NewInputParameterError("disk.index %d is large than disk size %d", diskIndex, len(disks))
|
||||
return nil, nil, httperrors.NewInputParameterError("disk.index %d is large than disk size %d", diskIndex, len(disks))
|
||||
}
|
||||
diskObj = disks[diskIndex]
|
||||
vm.Disk.Id = diskObj.GetId()
|
||||
disk.Id = diskObj.GetId()
|
||||
// remove index
|
||||
vm.Disk.Index = nil
|
||||
disk.Index = nil
|
||||
if err := d.validateCaseInsensitive(&diskObj, disk); err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
} else {
|
||||
if disk.Id == "" {
|
||||
return nil, httperrors.NewNotEmptyError("disk.id is empty")
|
||||
return nil, nil, httperrors.NewNotEmptyError("disk.id is empty")
|
||||
}
|
||||
foundDisk := false
|
||||
for _, d := range disks {
|
||||
@@ -138,13 +177,26 @@ func (d disk) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCre
|
||||
}
|
||||
}
|
||||
if !foundDisk {
|
||||
return nil, httperrors.NewNotFoundError("not found pod disk by %s", disk.Id)
|
||||
return nil, nil, httperrors.NewNotFoundError("not found pod disk by %s", disk.Id)
|
||||
}
|
||||
if err := d.validateCaseInsensitive(&diskObj, disk); err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
if err := d.validateOverlay(ctx, userCred, vm, &diskObj); err != nil {
|
||||
return disk, &diskObj, nil
|
||||
}
|
||||
|
||||
func (d disk) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, pod *models.SGuest, vm *apis.ContainerVolumeMount) (*apis.ContainerVolumeMount, error) {
|
||||
if _, err := d.validateCreateData(ctx, userCred, vm); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
disk, diskObj, err := d.validateDiskIndex(ctx, userCred, pod, vm.Disk)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
vm.Disk = disk
|
||||
|
||||
if err := d.validateOverlay(ctx, userCred, vm, diskObj); err != nil {
|
||||
return nil, errors.Wrapf(err, "validate overlay")
|
||||
}
|
||||
if err := d.ValidatePostOverlay(ctx, userCred, vm); err != nil {
|
||||
|
||||
@@ -666,6 +666,9 @@ func (self *SKVMGuestDriver) RequestSyncConfigOnHost(ctx context.Context, guest
|
||||
if fw_only, _ := task.GetParams().Bool("fw_only"); fw_only {
|
||||
body.Add(jsonutils.JSONTrue, "fw_only")
|
||||
}
|
||||
if setUefiBootOrder, _ := task.GetParams().Bool("set_uefi_boot_order"); setUefiBootOrder {
|
||||
body.Add(jsonutils.JSONTrue, "set_uefi_boot_order")
|
||||
}
|
||||
url := fmt.Sprintf("%s/servers/%s/sync", host.ManagerUri, guest.Id)
|
||||
header := self.getTaskRequestHeader(task)
|
||||
_, _, err = httputils.JSONRequest(httputils.GetDefaultClient(), ctx, "POST", url, header, body, false)
|
||||
|
||||
@@ -484,7 +484,7 @@ func (drv *SManagedVirtualizedGuestDriver) RequestStartOnHost(ctx context.Contex
|
||||
if guest.BillingType == billing_api.BILLING_TYPE_POSTPAID && jsonutils.QueryBoolean(task.GetParams(), "auto_prepaid", false) {
|
||||
err = ivm.ChangeBillingType(billing_api.BILLING_TYPE_PREPAID)
|
||||
if err != nil && errors.Cause(err) != cloudprovider.ErrNotImplemented {
|
||||
logclient.AddSimpleActionLog(guest, logclient.ACT_VM_CHANGE_BILLING_TYPE, errors.Wrapf(err, billing_api.BILLING_TYPE_PREPAID), userCred, false)
|
||||
logclient.AddSimpleActionLog(guest, logclient.ACT_CHANGE_BILLING_TYPE, errors.Wrapf(err, billing_api.BILLING_TYPE_PREPAID), userCred, false)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -985,7 +985,7 @@ func (drv *SManagedVirtualizedGuestDriver) RequestStopOnHost(ctx context.Context
|
||||
if opts.StopCharging && guest.BillingType == billing_api.BILLING_TYPE_PREPAID {
|
||||
err = ivm.ChangeBillingType(billing_api.BILLING_TYPE_POSTPAID)
|
||||
if err != nil && errors.Cause(err) != cloudprovider.ErrNotImplemented {
|
||||
logclient.AddSimpleActionLog(guest, logclient.ACT_VM_CHANGE_BILLING_TYPE, errors.Wrapf(err, billing_api.BILLING_TYPE_POSTPAID), task.GetUserCred(), false)
|
||||
logclient.AddSimpleActionLog(guest, logclient.ACT_CHANGE_BILLING_TYPE, errors.Wrapf(err, billing_api.BILLING_TYPE_POSTPAID), task.GetUserCred(), false)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -76,6 +76,8 @@ func (self *SQcloudGuestDriver) GetStorageTypes() []string {
|
||||
api.STORAGE_LOCAL_BASIC,
|
||||
api.STORAGE_LOCAL_SSD,
|
||||
api.STORAGE_CLOUD_HSSD,
|
||||
api.STORAGE_CLOUD_BSSD,
|
||||
api.STORAGE_CLOUD_TSSD,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,7 +141,7 @@ func (self *SQcloudGuestDriver) ValidateCreateData(ctx context.Context, userCred
|
||||
if sysDisk.SizeMb > 1024*1024 {
|
||||
return nil, fmt.Errorf("The %s system disk size must be less than 1024GB", sysDisk.Backend)
|
||||
}
|
||||
case api.STORAGE_LOCAL_PRO, api.STORAGE_CLOUD_HSSD: //https://cloud.tencent.com/document/product/362/2353
|
||||
case api.STORAGE_LOCAL_PRO: //https://cloud.tencent.com/document/product/362/2353
|
||||
return nil, fmt.Errorf("storage %s can not be system disk", sysDisk.Backend)
|
||||
}
|
||||
|
||||
@@ -154,7 +156,7 @@ func (self *SQcloudGuestDriver) ValidateCreateData(ctx context.Context, userCred
|
||||
if disk.SizeMb < 10*1024 || disk.SizeMb > 32000*1024 {
|
||||
return nil, httperrors.NewInputParameterError("The %s disk size must be in the range of 10GB ~ 32000GB", disk.Backend)
|
||||
}
|
||||
case api.STORAGE_CLOUD_SSD, api.STORAGE_CLOUD_HSSD:
|
||||
case api.STORAGE_CLOUD_SSD, api.STORAGE_CLOUD_HSSD, api.STORAGE_CLOUD_BSSD, api.STORAGE_CLOUD_TSSD:
|
||||
if disk.SizeMb < 20*1024 || disk.SizeMb > 32000*1024 {
|
||||
return nil, httperrors.NewInputParameterError("The %s disk size must be in the range of 20GB ~ 32000GB", disk.Backend)
|
||||
}
|
||||
@@ -199,7 +201,7 @@ func (qcloud *SQcloudGuestDriver) ValidateGuestChangeConfigInput(ctx context.Con
|
||||
if newDisk.SizeMb < 10*1024 || newDisk.SizeMb > 32000*1024 {
|
||||
return nil, httperrors.NewInputParameterError("The %s disk size must be in the range of 10GB ~ 32000GB", newDisk.Backend)
|
||||
}
|
||||
case api.STORAGE_CLOUD_SSD, api.STORAGE_CLOUD_HSSD:
|
||||
case api.STORAGE_CLOUD_SSD, api.STORAGE_CLOUD_HSSD, api.STORAGE_CLOUD_BSSD, api.STORAGE_CLOUD_TSSD:
|
||||
if newDisk.SizeMb < 20*1024 || newDisk.SizeMb > 32000*1024 {
|
||||
return nil, httperrors.NewInputParameterError("The %s disk size must be in the range of 20GB ~ 32000GB", newDisk.Backend)
|
||||
}
|
||||
@@ -273,12 +275,16 @@ func (self *SQcloudGuestDriver) GetInstanceCapability() cloudprovider.SInstanceC
|
||||
cloudprovider.StorageInfo{StorageType: api.STORAGE_CLOUD_BASIC, MaxSizeGb: 16000, MinSizeGb: 10, StepSizeGb: 10, Resizable: true},
|
||||
cloudprovider.StorageInfo{StorageType: api.STORAGE_CLOUD_PREMIUM, MaxSizeGb: 16000, MinSizeGb: 50, StepSizeGb: 10, Resizable: true},
|
||||
cloudprovider.StorageInfo{StorageType: api.STORAGE_CLOUD_SSD, MaxSizeGb: 16000, MinSizeGb: 100, StepSizeGb: 10, Resizable: true},
|
||||
cloudprovider.StorageInfo{StorageType: api.STORAGE_CLOUD_HSSD, MaxSizeGb: 32000, MinSizeGb: 20, StepSizeGb: 10, Resizable: true},
|
||||
cloudprovider.StorageInfo{StorageType: api.STORAGE_CLOUD_HSSD, MaxSizeGb: 32000, MinSizeGb: 20, StepSizeGb: 1, Resizable: true},
|
||||
cloudprovider.StorageInfo{StorageType: api.STORAGE_CLOUD_BSSD, MaxSizeGb: 32000, MinSizeGb: 20, StepSizeGb: 1, Resizable: true},
|
||||
cloudprovider.StorageInfo{StorageType: api.STORAGE_CLOUD_TSSD, MaxSizeGb: 32000, MinSizeGb: 20, StepSizeGb: 1, Resizable: true},
|
||||
},
|
||||
SysDisk: []cloudprovider.StorageInfo{
|
||||
cloudprovider.StorageInfo{StorageType: api.STORAGE_CLOUD_BASIC, MaxSizeGb: 500, MinSizeGb: 50, StepSizeGb: 10, Resizable: false},
|
||||
cloudprovider.StorageInfo{StorageType: api.STORAGE_CLOUD_PREMIUM, MaxSizeGb: 1024, MinSizeGb: 50, StepSizeGb: 10, Resizable: false},
|
||||
cloudprovider.StorageInfo{StorageType: api.STORAGE_CLOUD_SSD, MaxSizeGb: 500, MinSizeGb: 50, StepSizeGb: 10, Resizable: false},
|
||||
cloudprovider.StorageInfo{StorageType: api.STORAGE_CLOUD_SSD, MaxSizeGb: 500, MinSizeGb: 50, StepSizeGb: 1, Resizable: false},
|
||||
cloudprovider.StorageInfo{StorageType: api.STORAGE_CLOUD_BSSD, MaxSizeGb: 32000, MinSizeGb: 20, StepSizeGb: 1, Resizable: true},
|
||||
cloudprovider.StorageInfo{StorageType: api.STORAGE_CLOUD_TSSD, MaxSizeGb: 32000, MinSizeGb: 20, StepSizeGb: 1, Resizable: true},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -230,11 +230,11 @@ func (self *SKVMHostDriver) CheckAndSetCacheImage(ctx context.Context, userCred
|
||||
return err
|
||||
}
|
||||
|
||||
srcHost, err := srcHostCacheImage.GetHost()
|
||||
/*srcHost, err := srcHostCacheImage.GetHost()
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Get storage cached image %s host", srcHostCacheImage.GetId())
|
||||
}
|
||||
input.SrcUrl = fmt.Sprintf("%s/download/images/%s", srcHost.ManagerUri, input.ImageId)
|
||||
input.SrcUrl = fmt.Sprintf("%s/download/images/%s", srcHost.ManagerUri, input.ImageId)*/
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/disks/image_cache", host.ManagerUri)
|
||||
|
||||
@@ -60,7 +60,7 @@ func (self *SQcloudHostDriver) ValidateDiskSize(storage *models.SStorage, sizeGb
|
||||
min, max = 50, 16000
|
||||
case api.STORAGE_CLOUD_SSD:
|
||||
min, max = 100, 16000
|
||||
case api.STORAGE_CLOUD_HSSD:
|
||||
case api.STORAGE_CLOUD_HSSD, api.STORAGE_CLOUD_BSSD, api.STORAGE_CLOUD_TSSD:
|
||||
min, max = 20, 320000
|
||||
default:
|
||||
return fmt.Errorf("Not support create or resize %s disk", storage.StorageType)
|
||||
|
||||
@@ -92,6 +92,8 @@ type SBucket struct {
|
||||
ObjectCntLimit int `nullable:"false" default:"0" list:"user"`
|
||||
|
||||
AccessUrls jsonutils.JSONObject `nullable:"true" list:"user"`
|
||||
|
||||
EnablePerfMon bool `default:"false" list:"user" update:"user" create:"optional"`
|
||||
}
|
||||
|
||||
func (manager *SBucketManager) SetHandlerProcessTimeout(info *appsrv.SHandlerInfo, r *http.Request) time.Duration {
|
||||
|
||||
@@ -75,6 +75,9 @@ type SCapabilities struct {
|
||||
DisabledModelartsPoolsBrands []string `json:",allowempty"`
|
||||
ModelartsPoolsBrands []string `json:",allowempty"`
|
||||
|
||||
DisabledDnsBrands []string `json:",allowempty"`
|
||||
DnsBrands []string `json:",allowempty"`
|
||||
|
||||
ContainerBrands []string `json:",allowempty"`
|
||||
DisabledContainerBrands []string `json:",allowempty"`
|
||||
|
||||
@@ -119,6 +122,9 @@ type SCapabilities struct {
|
||||
ReadOnlyModelartsPoolsBrands []string `json:",allowempty"`
|
||||
ReadOnlyDisabledModelartsPoolsBrands []string `json:",allowempty"`
|
||||
|
||||
ReadOnlyDnsBrands []string `json:",allowempty"`
|
||||
ReadOnlyDisabledDnsBrands []string `json:",allowempty"`
|
||||
|
||||
ReadOnlyContainerBrands []string `json:",allowempty"`
|
||||
ReadOnlyDisabledContainerBrands []string `json:",allowempty"`
|
||||
|
||||
@@ -422,6 +428,7 @@ func getBrands(region *SCloudregion, domainId string, capa *SCapabilities) {
|
||||
capa.SecurityGroupBrands = append(capa.SecurityGroupBrands, api.ONECLOUD_BRAND_ONECLOUD)
|
||||
capa.ComputeEngineBrands = append(capa.ComputeEngineBrands, api.ONECLOUD_BRAND_ONECLOUD)
|
||||
capa.SnapshotPolicyBrands = append(capa.SnapshotPolicyBrands, api.ONECLOUD_BRAND_ONECLOUD)
|
||||
capa.DnsBrands = append(capa.DnsBrands, api.ONECLOUD_BRAND_ONECLOUD)
|
||||
} else if utils.IsInStringArray(api.HYPERVISOR_POD, capa.Hypervisors) {
|
||||
capa.Brands = append(capa.Brands, api.ONECLOUD_BRAND_ONECLOUD)
|
||||
capa.ComputeEngineBrands = append(capa.ComputeEngineBrands, api.ONECLOUD_BRAND_ONECLOUD)
|
||||
@@ -519,6 +526,8 @@ func getBrands(region *SCloudregion, domainId string, capa *SCapabilities) {
|
||||
appendBrand(&capa.SnapshotPolicyBrands, &capa.DisabledSnapshotPolicyBrands, &capa.ReadOnlySnapshotPolicyBrands, &capa.ReadOnlyDisabledSnapshotPolicyBrands, brand, capability, enabled, readOnly)
|
||||
case cloudprovider.CLOUD_CAPABILITY_MODELARTES:
|
||||
appendBrand(&capa.ModelartsPoolsBrands, &capa.DisabledModelartsPoolsBrands, &capa.ReadOnlyModelartsPoolsBrands, &capa.ReadOnlyDisabledModelartsPoolsBrands, brand, capability, enabled, readOnly)
|
||||
case cloudprovider.CLOUD_CAPABILITY_DNSZONE:
|
||||
appendBrand(&capa.DnsBrands, &capa.DisabledDnsBrands, &capa.ReadOnlyDnsBrands, &capa.ReadOnlyDisabledDnsBrands, brand, capability, enabled, readOnly)
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,12 +89,27 @@ func GetContainerVolumeMountDriverWithError(typ apis.ContainerVolumeMountType) (
|
||||
return getContainerDriverWithError[apis.ContainerVolumeMountType, IContainerVolumeMountDriver](containerVolumeDrivers, typ)
|
||||
}
|
||||
|
||||
func GetContainerRootFsDriverWithError(typ apis.ContainerVolumeMountType) (IContainerRootFsDriver, error) {
|
||||
return getContainerDriverWithError[apis.ContainerVolumeMountType, IContainerRootFsDriver](containerVolumeDrivers, typ)
|
||||
}
|
||||
|
||||
func GetContainerRootFsDriver(typ apis.ContainerVolumeMountType) IContainerRootFsDriver {
|
||||
return getContainerDriver[apis.ContainerVolumeMountType, IContainerRootFsDriver](containerVolumeDrivers, typ)
|
||||
}
|
||||
|
||||
type IContainerVolumeMountDriver interface {
|
||||
GetType() apis.ContainerVolumeMountType
|
||||
ValidatePodCreateData(ctx context.Context, userCred mcclient.TokenCredential, vm *apis.ContainerVolumeMount, input *api.ServerCreateInput) error
|
||||
ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, pod *SGuest, vm *apis.ContainerVolumeMount) (*apis.ContainerVolumeMount, error)
|
||||
}
|
||||
|
||||
type IContainerRootFsDriver interface {
|
||||
IContainerVolumeMountDriver
|
||||
|
||||
ToHostRootFs(rootFs *apis.ContainerRootfs) (*hostapi.ContainerRootfs, error)
|
||||
ValidateRootFsCreateData(ctx context.Context, userCred mcclient.TokenCredential, pod *SGuest, rootFs *apis.ContainerRootfs) error
|
||||
}
|
||||
|
||||
type IContainerVolumeMountDiskDriver interface {
|
||||
IContainerVolumeMountDriver
|
||||
|
||||
|
||||
@@ -178,6 +178,9 @@ func (m *SContainerManager) ValidateSpec(ctx context.Context, userCred mcclient.
|
||||
}
|
||||
|
||||
if pod != nil {
|
||||
if err := m.ValidateSpecRootFs(ctx, userCred, pod, spec, ctr); err != nil {
|
||||
return errors.Wrap(err, "ValidateSpecRootFs")
|
||||
}
|
||||
if err := m.ValidateSpecVolumeMounts(ctx, userCred, pod, spec, ctr); err != nil {
|
||||
return errors.Wrap(err, "ValidateSpecVolumeMounts")
|
||||
}
|
||||
@@ -231,6 +234,21 @@ func (m *SContainerManager) ValidateSpecDevice(ctx context.Context, userCred mcc
|
||||
return drv.ValidateCreateData(ctx, userCred, pod, dev)
|
||||
}
|
||||
|
||||
func (m *SContainerManager) ValidateSpecRootFs(ctx context.Context, userCred mcclient.TokenCredential, pod *SGuest, spec *api.ContainerSpec, ctr *SContainer) error {
|
||||
if spec.RootFs == nil {
|
||||
return nil
|
||||
}
|
||||
rootFs := spec.RootFs
|
||||
drv, err := GetContainerRootFsDriverWithError(rootFs.Type)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "get container volume mount driver %q", rootFs.Type)
|
||||
}
|
||||
if err := drv.ValidateRootFsCreateData(ctx, userCred, pod, rootFs); err != nil {
|
||||
return errors.Wrapf(err, "validate %s create data", drv.GetType())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *SContainerManager) ValidateSpecVolumeMounts(ctx context.Context, userCred mcclient.TokenCredential, pod *SGuest, spec *api.ContainerSpec, ctr *SContainer) error {
|
||||
relation, err := m.GetVolumeMountRelations(pod, spec)
|
||||
if err != nil {
|
||||
@@ -461,6 +479,23 @@ func (c *SContainer) GetVolumeMounts() []*apis.ContainerVolumeMount {
|
||||
return c.Spec.VolumeMounts
|
||||
}
|
||||
|
||||
type ContainerRootFsRelation struct {
|
||||
RootFs *apis.ContainerRootfs
|
||||
pod *SGuest
|
||||
}
|
||||
|
||||
func (rr *ContainerRootFsRelation) ToHostRootFs() (*hostapi.ContainerRootfs, error) {
|
||||
drv, err := GetContainerRootFsDriverWithError(rr.RootFs.Type)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "get container root fs driver %q", rr.RootFs.Type)
|
||||
}
|
||||
rootFs, err := drv.ToHostRootFs(rr.RootFs)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "to host root fs")
|
||||
}
|
||||
return rootFs, nil
|
||||
}
|
||||
|
||||
type ContainerVolumeMountRelation struct {
|
||||
VolumeMount *apis.ContainerVolumeMount
|
||||
|
||||
@@ -547,6 +582,13 @@ func (vm *ContainerVolumeMountRelation) ToHostMount(ctx context.Context, userCre
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (m *SContainerManager) GetRootFsRelation(pod *SGuest, spec *api.ContainerSpec) (*ContainerRootFsRelation, error) {
|
||||
return &ContainerRootFsRelation{
|
||||
RootFs: spec.RootFs,
|
||||
pod: pod,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (m *SContainerManager) GetVolumeMountRelations(pod *SGuest, spec *api.ContainerSpec) ([]*ContainerVolumeMountRelation, error) {
|
||||
relation := make([]*ContainerVolumeMountRelation, len(spec.VolumeMounts))
|
||||
for idx, vm := range spec.VolumeMounts {
|
||||
@@ -559,6 +601,10 @@ func (m *SContainerManager) GetVolumeMountRelations(pod *SGuest, spec *api.Conta
|
||||
return relation, nil
|
||||
}
|
||||
|
||||
func (c *SContainer) GetRootFsRelation() (*ContainerRootFsRelation, error) {
|
||||
return GetContainerManager().GetRootFsRelation(c.GetPod(), c.Spec)
|
||||
}
|
||||
|
||||
func (c *SContainer) GetVolumeMountRelations() ([]*ContainerVolumeMountRelation, error) {
|
||||
return GetContainerManager().GetVolumeMountRelations(c.GetPod(), c.Spec)
|
||||
}
|
||||
@@ -716,7 +762,27 @@ func (m *SContainerManager) ConvertVolumeMountRelationToSpec(ctx context.Context
|
||||
return mounts, nil
|
||||
}
|
||||
|
||||
func (m *SContainerManager) ConvertRootFsRelationToSpec(ctx context.Context, userCred mcclient.TokenCredential, relation *ContainerRootFsRelation) (*hostapi.ContainerRootfs, error) {
|
||||
if relation.RootFs == nil {
|
||||
return nil, nil
|
||||
}
|
||||
rootFs, err := relation.ToHostRootFs()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "ToHostRootFs")
|
||||
}
|
||||
return rootFs, nil
|
||||
}
|
||||
|
||||
func (c *SContainer) ToHostContainerSpec(ctx context.Context, userCred mcclient.TokenCredential) (*hostapi.ContainerSpec, error) {
|
||||
rootFsRelation, err := c.GetRootFsRelation()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "GetRootFsRelation")
|
||||
}
|
||||
rootFs, err := GetContainerManager().ConvertRootFsRelationToSpec(ctx, userCred, rootFsRelation)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "ConvertRootFsRelationToSpec")
|
||||
}
|
||||
|
||||
vmRelation, err := c.GetVolumeMountRelations()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "GetVolumeMountRelations")
|
||||
@@ -737,6 +803,7 @@ func (c *SContainer) ToHostContainerSpec(ctx context.Context, userCred mcclient.
|
||||
spec := c.Spec.ContainerSpec
|
||||
hSpec := &hostapi.ContainerSpec{
|
||||
ContainerSpec: spec,
|
||||
Rootfs: rootFs,
|
||||
VolumeMounts: mounts,
|
||||
Devices: ctrDevs,
|
||||
}
|
||||
@@ -817,11 +884,32 @@ func (c *SContainer) PerformSaveVolumeMountImage(ctx context.Context, userCred m
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "ToHostMount")
|
||||
}
|
||||
|
||||
cleanupDirPath := func(dirPath string) string {
|
||||
nPath := ""
|
||||
pathSegs := strings.Split(dirPath, "/")
|
||||
for _, seg := range pathSegs {
|
||||
if len(seg) > 0 {
|
||||
nPath = filepath.Join(nPath, seg)
|
||||
}
|
||||
}
|
||||
return nPath
|
||||
}
|
||||
|
||||
cleanupDirPaths := func(dirPaths []string) []string {
|
||||
for i := range dirPaths {
|
||||
dirPaths[i] = cleanupDirPath(dirPaths[i])
|
||||
}
|
||||
return dirPaths
|
||||
}
|
||||
|
||||
hostInput := &hostapi.ContainerSaveVolumeMountToImageInput{
|
||||
ImageId: imageId,
|
||||
VolumeMountIndex: input.Index,
|
||||
VolumeMount: hvm,
|
||||
VolumeMountDirs: input.Dirs,
|
||||
|
||||
VolumeMountDirs: cleanupDirPaths(input.Dirs),
|
||||
VolumeMountPrefix: cleanupDirPath(input.DirPrefix),
|
||||
}
|
||||
|
||||
return hostInput, c.StartSaveVolumeMountImage(ctx, userCred, hostInput, "")
|
||||
|
||||
@@ -2616,9 +2616,8 @@ func (manager *SDiskManager) FetchCustomizeColumns(
|
||||
rows[i].Brand = "Unknown"
|
||||
rows[i].Provider = "Unknown"
|
||||
}
|
||||
if len(rows[i].ExternalId) == 0 {
|
||||
//rows[i].Iops = iops
|
||||
//rows[i].Throughput = bps
|
||||
// 仅kvm使用
|
||||
if len(rows[i].ManagerId) == 0 {
|
||||
disk.Iops = iops
|
||||
disk.Throughput = bps
|
||||
}
|
||||
@@ -3339,3 +3338,29 @@ func (disk *SDisk) resetDiskinfo(
|
||||
db.OpsLog.LogEvent(disk, db.ACT_UPDATE, notes, userCred)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (disk *SDisk) PerformChangeBillingType(ctx context.Context, userCred mcclient.TokenCredential, _ jsonutils.JSONObject, input *api.DiskChangeBillingTypeInput) (jsonutils.JSONObject, error) {
|
||||
if !utils.IsInStringArray(disk.Status, []string{api.DISK_READY}) {
|
||||
return nil, httperrors.NewServerStatusError("Cannot change disk billing type in status %s", disk.Status)
|
||||
}
|
||||
if len(input.BillingType) == 0 {
|
||||
return nil, httperrors.NewMissingParameterError("billing_type")
|
||||
}
|
||||
if !utils.IsInStringArray(input.BillingType, []string{billing_api.BILLING_TYPE_POSTPAID, billing_api.BILLING_TYPE_PREPAID}) {
|
||||
return nil, httperrors.NewInputParameterError("invalid billing_type %s", input.BillingType)
|
||||
}
|
||||
if disk.BillingType == input.BillingType {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, disk.StartChangeBillingTypeTask(ctx, userCred, "")
|
||||
}
|
||||
|
||||
func (disk *SDisk) StartChangeBillingTypeTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
|
||||
disk.SetStatus(ctx, userCred, apis.STATUS_CHANGE_BILLING_TYPE, "")
|
||||
kwargs := jsonutils.NewDict()
|
||||
task, err := taskman.TaskManager.NewTask(ctx, "DiskChangeBillingTypeTask", disk, userCred, kwargs, parentTaskId, "", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return task.ScheduleRun(nil)
|
||||
}
|
||||
|
||||
@@ -76,6 +76,8 @@ type SDnsRecord struct {
|
||||
DnsValue string `width:"256" charset:"ascii" nullable:"false" list:"user" update:"user" create:"required"`
|
||||
TTL int64 `nullable:"false" list:"user" update:"user" create:"required" json:"ttl"`
|
||||
MxPriority int64 `nullable:"false" list:"user" update:"user" create:"optional"`
|
||||
// cloudflare 特有
|
||||
Proxied tristate.TriState `default:"false" list:"user" create:"optional"`
|
||||
|
||||
// 解析线路类型
|
||||
PolicyType string `width:"36" charset:"ascii" nullable:"false" list:"user" update:"user" create:"optional"`
|
||||
@@ -491,6 +493,7 @@ func (self *SDnsRecord) syncWithDnsRecord(ctx context.Context, userCred mcclient
|
||||
diff, err := db.Update(self, func() error {
|
||||
self.Name = ext.GetDnsName()
|
||||
self.Enabled = tristate.NewFromBool(ext.GetEnabled())
|
||||
self.Proxied = tristate.NewFromBool(ext.IsProxied())
|
||||
self.Status = ext.GetStatus()
|
||||
self.TTL = ext.GetTTL()
|
||||
self.MxPriority = ext.GetMxPriority()
|
||||
@@ -525,6 +528,7 @@ func (self *SDnsZone) newFromCloudDnsRecord(ctx context.Context, userCred mcclie
|
||||
record.Name = ext.GetDnsName()
|
||||
record.Status = ext.GetStatus()
|
||||
record.Enabled = tristate.NewFromBool(ext.GetEnabled())
|
||||
record.Proxied = tristate.NewFromBool(ext.IsProxied())
|
||||
record.TTL = ext.GetTTL()
|
||||
record.MxPriority = ext.GetMxPriority()
|
||||
record.DnsType = string(ext.GetDnsType())
|
||||
|
||||
@@ -2435,8 +2435,7 @@ func (self *SGuest) attachIsolatedDevice(ctx context.Context, userCred mcclient.
|
||||
if len(dev.GuestId) > 0 {
|
||||
return fmt.Errorf("Isolated device already attached to another guest: %s", dev.GuestId)
|
||||
}
|
||||
if dev.HostId !=
|
||||
self.HostId {
|
||||
if dev.HostId != self.HostId {
|
||||
return fmt.Errorf("Isolated device and guest are not located in the same host")
|
||||
}
|
||||
drv, _ := self.GetDriver()
|
||||
@@ -3466,7 +3465,7 @@ func (self *SGuest) SetBackupGuestStatus(userCred mcclient.TokenCredential, stat
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *SGuest) SetStatusFromHost(ctx context.Context, userCred mcclient.TokenCredential, resp api.HostUploadGuestStatusResponse, hasParentTask bool, originStatus string) error {
|
||||
func (g *SGuest) SetStatusFromHost(ctx context.Context, userCred mcclient.TokenCredential, resp api.HostUploadGuestStatusInput, hasParentTask bool, originStatus string) error {
|
||||
statusStr := resp.Status
|
||||
switch statusStr {
|
||||
case cloudprovider.CloudVMStatusRunning:
|
||||
@@ -3490,7 +3489,9 @@ func (g *SGuest) SetStatusFromHost(ctx context.Context, userCred mcclient.TokenC
|
||||
statusStr = originStatus
|
||||
}
|
||||
}
|
||||
input := resp.PerformStatusInput
|
||||
input := api.ServerPerformStatusInput{
|
||||
PerformStatusInput: resp.PerformStatusInput,
|
||||
}
|
||||
input.Status = statusStr
|
||||
if _, err := g.PerformStatus(ctx, userCred, nil, input); err != nil {
|
||||
return errors.Wrapf(err, "perform status of %s", jsonutils.Marshal(resp))
|
||||
@@ -3498,7 +3499,7 @@ func (g *SGuest) SetStatusFromHost(ctx context.Context, userCred mcclient.TokenC
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *SGuestManager) PerformUploadStatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input *api.HostUploadGuestsStatusResponse) (*api.GuestUploadStatusesResponse, error) {
|
||||
func (m *SGuestManager) PerformUploadStatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input *api.HostUploadGuestsStatusInput) (*api.GuestUploadStatusesResponse, error) {
|
||||
out := &api.GuestUploadStatusesResponse{
|
||||
Guests: make(map[string]*api.GuestUploadStatusResponse),
|
||||
}
|
||||
@@ -3545,7 +3546,7 @@ func (m *SGuestManager) PerformUploadStatus(ctx context.Context, userCred mcclie
|
||||
}
|
||||
|
||||
// 同步状态
|
||||
func (self *SGuest) PerformStatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformStatusInput) (jsonutils.JSONObject, error) {
|
||||
func (self *SGuest) PerformStatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.ServerPerformStatusInput) (jsonutils.JSONObject, error) {
|
||||
if input.HostId != "" && self.BackupHostId != "" && input.HostId == self.BackupHostId {
|
||||
// perform status called from slave guest
|
||||
return nil, self.SetBackupGuestStatus(userCred, input.Status, input.Reason)
|
||||
@@ -3563,7 +3564,7 @@ func (self *SGuest) PerformStatus(ctx context.Context, userCred mcclient.TokenCr
|
||||
}
|
||||
|
||||
preStatus := self.Status
|
||||
_, err := self.SVirtualResourceBase.PerformStatus(ctx, userCred, query, input)
|
||||
_, err := self.SVirtualResourceBase.PerformStatus(ctx, userCred, query, input.PerformStatusInput)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "SVirtualResourceBase.PerformStatus")
|
||||
}
|
||||
@@ -3604,6 +3605,15 @@ func (self *SGuest) PerformStatus(ctx context.Context, userCred mcclient.TokenCr
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
for cId, cStatus := range input.Containers {
|
||||
ctr, err := GetContainerManager().FetchById(cId)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "GetContainerManager(%s)", cId)
|
||||
}
|
||||
if _, err := ctr.(*SContainer).PerformStatus(ctx, userCred, query, *cStatus); err != nil {
|
||||
return nil, errors.Wrapf(err, "PerformStatus(%s) of container", cId)
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@@ -6394,6 +6404,14 @@ func (self *SGuest) PerformSetBootIndex(ctx context.Context, userCred mcclient.T
|
||||
}
|
||||
}
|
||||
|
||||
if self.Bios == api.VM_BOOT_MODE_UEFI {
|
||||
data := jsonutils.NewDict()
|
||||
data.Set("set_uefi_boot_order", jsonutils.JSONTrue)
|
||||
if err := self.startSyncTask(ctx, userCred, false, "", data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@@ -6757,7 +6775,7 @@ func (g *SGuest) PerformChangeBillingType(ctx context.Context, userCred mcclient
|
||||
}
|
||||
|
||||
func (self *SGuest) StartChangeBillingTypeTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
|
||||
self.SetStatus(ctx, userCred, api.VM_CHANGE_BILLING_TYPE, "")
|
||||
self.SetStatus(ctx, userCred, apis.STATUS_CHANGE_BILLING_TYPE, "")
|
||||
kwargs := jsonutils.NewDict()
|
||||
task, err := taskman.TaskManager.NewTask(ctx, "GuestChangeBillingTypeTask", self, userCred, kwargs, parentTaskId, "", nil)
|
||||
if err != nil {
|
||||
@@ -6765,3 +6783,8 @@ func (self *SGuest) StartChangeBillingTypeTask(ctx context.Context, userCred mcc
|
||||
}
|
||||
return task.ScheduleRun(nil)
|
||||
}
|
||||
|
||||
func (self *SGuest) PerformDisableAutoMergeSnapshots(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
|
||||
disableAutoMergeSnapshot := jsonutils.QueryBoolean(data, "disable_auto_merge_snapshot", false)
|
||||
return nil, self.SetMetadata(ctx, api.VM_METADATA_DISABLE_AUTO_MERGE_SNAPSHOT, disableAutoMergeSnapshot, userCred)
|
||||
}
|
||||
|
||||
@@ -71,7 +71,15 @@ func (manager *SGuestManager) FetchCustomizeColumns(
|
||||
gds := fetchGuestDisksInfo(guestIds)
|
||||
if gds != nil {
|
||||
for i := range rows {
|
||||
rows[i].DisksInfo, _ = gds[guestIds[i]]
|
||||
rows[i].DisksInfo = []api.GuestDiskInfo{}
|
||||
if disks, ok := gds[guestIds[i]]; ok {
|
||||
for j := range disks {
|
||||
if len(rows[i].ManagerId) > 0 {
|
||||
disks[j].Iops = disks[j].DiskIops
|
||||
}
|
||||
rows[i].DisksInfo = append(rows[i].DisksInfo, disks[j].GuestDiskInfo)
|
||||
}
|
||||
}
|
||||
rows[i].DiskCount = len(rows[i].DisksInfo)
|
||||
shortDescs := []string{}
|
||||
for _, info := range rows[i].DisksInfo {
|
||||
@@ -368,12 +376,17 @@ type sGustDiskSize struct {
|
||||
DiskCount int
|
||||
}
|
||||
|
||||
type sGuestDiskInfo struct {
|
||||
type GuestDiskInfo struct {
|
||||
DiskIops int
|
||||
api.GuestDiskInfo
|
||||
}
|
||||
|
||||
type sGuestDiskInfo struct {
|
||||
GuestDiskInfo
|
||||
GuestId string
|
||||
}
|
||||
|
||||
func fetchGuestDisksInfo(guestIds []string) map[string][]api.GuestDiskInfo {
|
||||
func fetchGuestDisksInfo(guestIds []string) map[string][]GuestDiskInfo {
|
||||
disks := DiskManager.Query().SubQuery()
|
||||
guestdisks := GuestdiskManager.Query().SubQuery()
|
||||
storages := StorageManager.Query().SubQuery()
|
||||
@@ -392,6 +405,8 @@ func fetchGuestDisksInfo(guestIds []string) map[string][]api.GuestDiskInfo {
|
||||
storages.Field("medium_type"),
|
||||
storages.Field("storage_type"),
|
||||
guestdisks.Field("iops"),
|
||||
disks.Field("iops").Label("disk_iops"),
|
||||
disks.Field("throughput"),
|
||||
guestdisks.Field("bps"),
|
||||
disks.Field("template_id").Label("image_id"),
|
||||
guestdisks.Field("guest_id"),
|
||||
@@ -405,17 +420,18 @@ func fetchGuestDisksInfo(guestIds []string) map[string][]api.GuestDiskInfo {
|
||||
gds := []sGuestDiskInfo{}
|
||||
err := q.All(&gds)
|
||||
if err != nil {
|
||||
log.Errorf("fetchGuestDisksInfo: %v", err)
|
||||
return nil
|
||||
}
|
||||
imageIds := []string{}
|
||||
ret := map[string][]api.GuestDiskInfo{}
|
||||
ret := map[string][]GuestDiskInfo{}
|
||||
for i := range gds {
|
||||
if len(gds[i].ImageId) > 0 {
|
||||
imageIds = append(imageIds, gds[i].ImageId)
|
||||
}
|
||||
_, ok := ret[gds[i].GuestId]
|
||||
if !ok {
|
||||
ret[gds[i].GuestId] = []api.GuestDiskInfo{}
|
||||
ret[gds[i].GuestId] = []GuestDiskInfo{}
|
||||
}
|
||||
ret[gds[i].GuestId] = append(ret[gds[i].GuestId], gds[i].GuestDiskInfo)
|
||||
}
|
||||
|
||||
227
pkg/compute/models/hostfilejoints.go
Normal file
227
pkg/compute/models/hostfilejoints.go
Normal file
@@ -0,0 +1,227 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// 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.
|
||||
|
||||
package models
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/pkg/errors"
|
||||
"yunion.io/x/pkg/utils"
|
||||
"yunion.io/x/sqlchemy"
|
||||
|
||||
computeapi "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db"
|
||||
"yunion.io/x/onecloud/pkg/httperrors"
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
)
|
||||
|
||||
type SHostFileJontsManager struct {
|
||||
db.SModelBaseManager
|
||||
}
|
||||
|
||||
var HostFileJointsManager *SHostFileJontsManager
|
||||
|
||||
func init() {
|
||||
HostFileJointsManager = &SHostFileJontsManager{
|
||||
SModelBaseManager: db.NewModelBaseManager(
|
||||
SHostFileJoint{},
|
||||
"hostfilejoints_tbl",
|
||||
"hostfilejoint",
|
||||
"hostfilejoints",
|
||||
),
|
||||
}
|
||||
HostFileJointsManager.SetVirtualObject(HostFileJointsManager)
|
||||
}
|
||||
|
||||
// +onecloud:model-api-gen
|
||||
type SHostFileJoint struct {
|
||||
db.SModelBase
|
||||
|
||||
HostId string `width:"128" charset:"ascii" nullable:"false" primary:"true"`
|
||||
HostFileId string `width:"128" charset:"ascii" nullable:"false" primary:"true"`
|
||||
Deleted bool `nullable:"false"`
|
||||
}
|
||||
|
||||
func (host *SHost) PerformSetHostFiles(
|
||||
ctx context.Context,
|
||||
userCred mcclient.TokenCredential,
|
||||
query jsonutils.JSONObject,
|
||||
input computeapi.HostSetHostFilesInput,
|
||||
) (jsonutils.JSONObject, error) {
|
||||
hostFileIds := make([]string, 0)
|
||||
for _, hostFileName := range input.HostFiles {
|
||||
hostFileObj, err := HostFileManager.FetchByIdOrName(ctx, userCred, hostFileName)
|
||||
if err != nil {
|
||||
if errors.Cause(err) == sql.ErrNoRows {
|
||||
return nil, httperrors.NewResourceNotFoundError2(HostFileManager.Keyword(), hostFileName)
|
||||
}
|
||||
return nil, errors.Wrap(err, "HostFileManager.FetchByIdOrName")
|
||||
}
|
||||
hostFile := hostFileObj.(*SHostFile)
|
||||
if hostFile.DomainId != host.DomainId {
|
||||
domains := hostFile.GetSharedDomains()
|
||||
if !utils.IsInArray(host.DomainId, domains) {
|
||||
return nil, errors.Wrapf(httperrors.ErrNoPermission, "host file %s not accessible to host %s", hostFile.Name, host.Name)
|
||||
}
|
||||
}
|
||||
hostFileIds = append(hostFileIds, hostFileObj.GetId())
|
||||
}
|
||||
|
||||
err := HostFileJointsManager.setHostFiles(ctx, userCred, host.Id, hostFileIds)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "HostFileJontsManager.setHostFiles")
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (manager *SHostFileJontsManager) getHostFiles(hostId string) ([]SHostFileJoint, error) {
|
||||
q := manager.Query().Equals("host_id", hostId)
|
||||
hostFiles := make([]SHostFileJoint, 0)
|
||||
err := db.FetchModelObjects(manager, q, &hostFiles)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "db.FetchModelObjects")
|
||||
}
|
||||
return hostFiles, nil
|
||||
}
|
||||
|
||||
func (manager *SHostFileJontsManager) setHostFiles(
|
||||
ctx context.Context,
|
||||
userCred mcclient.TokenCredential,
|
||||
hostId string,
|
||||
hostFileIds []string,
|
||||
) error {
|
||||
hostFiles, err := manager.getHostFiles(hostId)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "manager.getHostFiles")
|
||||
}
|
||||
|
||||
existingIds := make(map[string]bool)
|
||||
|
||||
for i := range hostFiles {
|
||||
existingIds[hostFiles[i].HostFileId] = true
|
||||
if utils.IsInStringArray(hostFiles[i].HostFileId, hostFileIds) {
|
||||
hostFiles[i].Deleted = false
|
||||
} else {
|
||||
hostFiles[i].Deleted = true
|
||||
}
|
||||
}
|
||||
|
||||
for i := range hostFileIds {
|
||||
if _, ok := existingIds[hostFileIds[i]]; !ok {
|
||||
hostFileJoint := SHostFileJoint{
|
||||
HostId: hostId,
|
||||
HostFileId: hostFileIds[i],
|
||||
Deleted: false,
|
||||
}
|
||||
hostFileJoint.SetModelManager(manager, &hostFileJoint)
|
||||
hostFiles = append(hostFiles, hostFileJoint)
|
||||
}
|
||||
}
|
||||
|
||||
errs := make([]error, 0)
|
||||
for i := range hostFiles {
|
||||
err := manager.TableSpec().InsertOrUpdate(ctx, &hostFiles[i])
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
|
||||
if len(errs) > 0 {
|
||||
return errors.NewAggregate(errs)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *SHost) getHostFiles() ([]computeapi.SHostFile, error) {
|
||||
q := HostFileManager.Query()
|
||||
jointQ := HostFileJointsManager.Query().Equals("host_id", h.Id).SubQuery()
|
||||
q = q.Join(jointQ, sqlchemy.Equals(q.Field("id"), jointQ.Field("host_file_id")))
|
||||
|
||||
hostFiles := make([]computeapi.SHostFile, 0)
|
||||
|
||||
err := q.All(&hostFiles)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "q.All")
|
||||
}
|
||||
|
||||
return hostFiles, nil
|
||||
}
|
||||
|
||||
func fetchHostHostFiles(hostIds []string) (map[string][]string, error) {
|
||||
q := HostFileJointsManager.Query().In("host_id", hostIds)
|
||||
hostFilesQ := HostFileManager.Query().SubQuery()
|
||||
q = q.Join(hostFilesQ, sqlchemy.Equals(q.Field("host_file_id"), hostFilesQ.Field("id")))
|
||||
q = q.AppendField(q.Field("host_id"))
|
||||
q = q.AppendField(hostFilesQ.Field("name"))
|
||||
|
||||
results := make([]struct {
|
||||
HostId string
|
||||
Name string
|
||||
}, 0)
|
||||
err := q.All(&results)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "q.All")
|
||||
}
|
||||
|
||||
hostFiles := make(map[string][]string)
|
||||
for _, result := range results {
|
||||
hostFiles[result.HostId] = append(hostFiles[result.HostId], result.Name)
|
||||
}
|
||||
|
||||
return hostFiles, nil
|
||||
}
|
||||
|
||||
func fetchHostFilesHosts(hostFileIds []string) (map[string][]string, error) {
|
||||
q := HostFileJointsManager.Query().In("host_file_id", hostFileIds)
|
||||
hostQ := HostManager.Query().SubQuery()
|
||||
q = q.Join(hostQ, sqlchemy.Equals(q.Field("host_id"), hostQ.Field("id")))
|
||||
q = q.AppendField(q.Field("host_file_id"))
|
||||
q = q.AppendField(hostQ.Field("name"))
|
||||
|
||||
results := make([]struct {
|
||||
HostFileId string
|
||||
Name string
|
||||
}, 0)
|
||||
err := q.All(&results)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "q.All")
|
||||
}
|
||||
|
||||
hostFiles := make(map[string][]string)
|
||||
for _, result := range results {
|
||||
hostFiles[result.HostFileId] = append(hostFiles[result.HostFileId], result.Name)
|
||||
}
|
||||
|
||||
return hostFiles, nil
|
||||
}
|
||||
|
||||
func (host *SHost) GetDetailsHostFiles(
|
||||
ctx context.Context,
|
||||
userCred mcclient.TokenCredential,
|
||||
query jsonutils.JSONObject,
|
||||
) (jsonutils.JSONObject, error) {
|
||||
hostFiles, err := host.getHostFiles()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "GetHostFiles")
|
||||
}
|
||||
|
||||
hostFilesObj := jsonutils.NewDict()
|
||||
hostFilesObj.Add(jsonutils.Marshal(hostFiles), "host_files")
|
||||
return hostFilesObj, nil
|
||||
}
|
||||
151
pkg/compute/models/hostfiles.go
Normal file
151
pkg/compute/models/hostfiles.go
Normal file
@@ -0,0 +1,151 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// 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.
|
||||
|
||||
package models
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/errors"
|
||||
"yunion.io/x/sqlchemy"
|
||||
|
||||
api "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
computeapi "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db"
|
||||
"yunion.io/x/onecloud/pkg/httperrors"
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
"yunion.io/x/onecloud/pkg/util/stringutils2"
|
||||
)
|
||||
|
||||
type SHostFileManager struct {
|
||||
db.SInfrasResourceBaseManager
|
||||
}
|
||||
|
||||
var HostFileManager *SHostFileManager
|
||||
|
||||
func init() {
|
||||
HostFileManager = &SHostFileManager{
|
||||
SInfrasResourceBaseManager: db.NewInfrasResourceBaseManager(
|
||||
SHostFile{},
|
||||
"hostfiles_tbl",
|
||||
"hostfile",
|
||||
"hostfiles",
|
||||
),
|
||||
}
|
||||
HostFileManager.SetVirtualObject(HostFileManager)
|
||||
}
|
||||
|
||||
// +onecloud:model-api-gen
|
||||
type SHostFile struct {
|
||||
db.SInfrasResourceBase
|
||||
|
||||
Type computeapi.HostFileType `width:"64" charset:"ascii" nullable:"false" list:"domain" create:"domain_required"`
|
||||
Path string `width:"256" charset:"utf8" nullable:"true" list:"domain" update:"domain" create:"domain_optional"`
|
||||
Content string `charset:"utf8" nullable:"true" get:"domain" update:"domain" create:"domain_optional"`
|
||||
}
|
||||
|
||||
func (manager *SHostFileManager) ValidateCreateData(
|
||||
ctx context.Context,
|
||||
userCred mcclient.TokenCredential,
|
||||
ownerId mcclient.IIdentityProvider,
|
||||
query jsonutils.JSONObject,
|
||||
input computeapi.HostFileCreateInput,
|
||||
) (computeapi.HostFileCreateInput, error) {
|
||||
var err error
|
||||
|
||||
input.InfrasResourceBaseCreateInput, err = manager.SInfrasResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.InfrasResourceBaseCreateInput)
|
||||
if err != nil {
|
||||
return input, errors.Wrap(err, "SInfrasResourceBaseManager.ValidateCreateData")
|
||||
}
|
||||
|
||||
if len(input.Type) == 0 {
|
||||
return input, httperrors.NewInputParameterError("Type is required")
|
||||
}
|
||||
|
||||
return input, nil
|
||||
}
|
||||
|
||||
func (manager *SHostFileManager) ValidateUpdateData(
|
||||
ctx context.Context,
|
||||
userCred mcclient.TokenCredential,
|
||||
ownerId mcclient.IIdentityProvider,
|
||||
query jsonutils.JSONObject,
|
||||
input computeapi.HostFileUpdateInput,
|
||||
) (computeapi.HostFileUpdateInput, error) {
|
||||
return input, nil
|
||||
}
|
||||
|
||||
func (manager *SHostFileManager) ListItemFilter(
|
||||
ctx context.Context,
|
||||
q *sqlchemy.SQuery,
|
||||
userCred mcclient.TokenCredential,
|
||||
query computeapi.HostFileListInput,
|
||||
) (*sqlchemy.SQuery, error) {
|
||||
var err error
|
||||
|
||||
q, err = manager.SInfrasResourceBaseManager.ListItemFilter(ctx, q, userCred, query.InfrasResourceBaseListInput)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "SInfrasResourceBaseManager.ListItemFilter")
|
||||
}
|
||||
|
||||
if len(query.Type) > 0 {
|
||||
q = q.In("type", query.Type)
|
||||
}
|
||||
|
||||
if len(query.Path) > 0 {
|
||||
q = q.Equals("path", query.Path)
|
||||
}
|
||||
|
||||
return q, nil
|
||||
}
|
||||
|
||||
func (manager *SHostFileManager) FetchCustomizeColumns(
|
||||
ctx context.Context,
|
||||
userCred mcclient.TokenCredential,
|
||||
query jsonutils.JSONObject,
|
||||
objs []interface{},
|
||||
fields stringutils2.SSortedStrings,
|
||||
isList bool,
|
||||
) []api.HostFileDetails {
|
||||
rows := make([]api.HostFileDetails, len(objs))
|
||||
infrasRows := manager.SInfrasResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
|
||||
hostFileIds := make([]string, 0, len(objs))
|
||||
for i := range rows {
|
||||
rows[i] = api.HostFileDetails{
|
||||
InfrasResourceBaseDetails: infrasRows[i],
|
||||
}
|
||||
hostFileIds = append(hostFileIds, objs[i].(*SHostFile).Id)
|
||||
}
|
||||
hostFiles, err := fetchHostFilesHosts(hostFileIds)
|
||||
if err != nil {
|
||||
log.Errorf("fetchHostFilesHosts error: %v", err)
|
||||
}
|
||||
for i := range rows {
|
||||
rows[i].Hosts = hostFiles[hostFileIds[i]]
|
||||
}
|
||||
return rows
|
||||
}
|
||||
|
||||
func (hostfile *SHostFile) ValidateDeleteCondition(ctx context.Context, info api.HostFileDetails) error {
|
||||
err := hostfile.SInfrasResourceBase.ValidateDeleteCondition(ctx, jsonutils.Marshal(info))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "SInfrasResourceBase.ValidateDeleteCondition")
|
||||
}
|
||||
if len(info.Hosts) > 0 {
|
||||
return httperrors.NewNotEmptyError("hostfile is used by hosts")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -3801,22 +3801,28 @@ func (manager *SHostManager) FetchCustomizeColumns(
|
||||
schedtags, err := fetchHostSchedtags(hostIds)
|
||||
if err != nil {
|
||||
log.Errorf("fetchHostSchedtags error: %v", err)
|
||||
return rows
|
||||
// return rows
|
||||
}
|
||||
|
||||
storages, err := fetchHostStorages(hostIds)
|
||||
if err != nil {
|
||||
log.Errorf("host storages error: %v", err)
|
||||
return rows
|
||||
// return rows
|
||||
}
|
||||
|
||||
nics, err := fetchHostNics(hostIds)
|
||||
if err != nil {
|
||||
log.Errorf("fetchHostNics error: %v", err)
|
||||
return rows
|
||||
// return rows
|
||||
}
|
||||
|
||||
guestCnts := manager.FetchGuestCnt(hostIds)
|
||||
|
||||
hostFiles, err := fetchHostHostFiles(hostIds)
|
||||
if err != nil {
|
||||
log.Errorf("fetchHostHostFiles error: %v", err)
|
||||
}
|
||||
|
||||
for i := range rows {
|
||||
cnt, ok := guestCnts[hostIds[i]]
|
||||
if ok {
|
||||
@@ -3919,6 +3925,7 @@ func (manager *SHostManager) FetchCustomizeColumns(
|
||||
rows[i].Schedtags, _ = schedtags[hostIds[i]]
|
||||
rows[i].NicInfo, _ = nics[hostIds[i]]
|
||||
rows[i].NicCount = len(rows[i].NicInfo)
|
||||
rows[i].HostFiles = hostFiles[hostIds[i]]
|
||||
|
||||
if hideCpuTypoInfo {
|
||||
sysInfo, ok := hosts[i].SysInfo.(*jsonutils.JSONDict)
|
||||
@@ -4973,14 +4980,19 @@ func (hh *SHost) PerformPing(ctx context.Context, userCred mcclient.TokenCredent
|
||||
dependSvcs := []string{"ntpd", "kafka", apis.SERVICE_TYPE_INFLUXDB, apis.SERVICE_TYPE_VICTORIA_METRICS, "elasticsearch", "opentsdb"}
|
||||
catalog := auth.GetCatalogData(dependSvcs, options.Options.Region)
|
||||
if catalog == nil {
|
||||
return nil, fmt.Errorf("Get catalog error")
|
||||
return nil, errors.Wrap(errors.ErrServer, "Get catalog error")
|
||||
}
|
||||
result.Set("catalog", catalog)
|
||||
if storages, err := hh.GetStoragesByMasterHost(); err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "get storages by master host")
|
||||
} else {
|
||||
result.Set("master_host_storages", jsonutils.NewStringArray(storages))
|
||||
}
|
||||
hostFiles, err := hh.getHostFiles()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "get host files")
|
||||
}
|
||||
result.Set("host_files", jsonutils.Marshal(hostFiles))
|
||||
|
||||
appParams := appsrv.AppContextGetParams(ctx)
|
||||
if appParams != nil {
|
||||
|
||||
@@ -36,7 +36,10 @@ type SSecurityGroupResourceBase struct {
|
||||
SecgroupId string `width:"36" charset:"ascii" nullable:"false" create:"required" index:"true" list:"user" json:"secgroup_id"`
|
||||
}
|
||||
|
||||
type SSecurityGroupResourceBaseManager struct{}
|
||||
type SSecurityGroupResourceBaseManager struct {
|
||||
SCloudregionResourceBaseManager
|
||||
SManagedResourceBaseManager
|
||||
}
|
||||
|
||||
func ValidateSecurityGroupResourceInput(ctx context.Context, userCred mcclient.TokenCredential, query api.SecgroupResourceInput) (*SSecurityGroup, api.SecgroupResourceInput, error) {
|
||||
secgrpObj, err := SecurityGroupManager.FetchByIdOrName(ctx, userCred, query.SecgroupId)
|
||||
@@ -78,16 +81,34 @@ func (manager *SSecurityGroupResourceBaseManager) FetchCustomizeColumns(
|
||||
}
|
||||
secgrpIds[i] = base.SecgroupId
|
||||
}
|
||||
secgrpNames, err := db.FetchIdNameMap2(SecurityGroupManager, secgrpIds)
|
||||
|
||||
groups := make(map[string]SSecurityGroup)
|
||||
err := db.FetchStandaloneObjectsByIds(SecurityGroupManager, secgrpIds, groups)
|
||||
if err != nil {
|
||||
log.Errorf("FetchIdNameMap2 fail %s", err)
|
||||
return rows
|
||||
log.Errorf("FetchStandaloneObjectsByIds fail %s", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
regionList := make([]interface{}, len(rows))
|
||||
managerList := make([]interface{}, len(rows))
|
||||
for i := range rows {
|
||||
if name, ok := secgrpNames[secgrpIds[i]]; ok {
|
||||
rows[i].Secgroup = name
|
||||
rows[i] = api.SecurityGroupResourceInfo{}
|
||||
if group, ok := groups[secgrpIds[i]]; ok {
|
||||
rows[i].Secgroup = group.Name
|
||||
rows[i].CloudregionId = group.CloudregionId
|
||||
rows[i].ManagerId = group.ManagerId
|
||||
}
|
||||
regionList[i] = &SCloudregionResourceBase{rows[i].CloudregionId}
|
||||
managerList[i] = &SManagedResourceBase{rows[i].ManagerId}
|
||||
}
|
||||
|
||||
regionRows := manager.SCloudregionResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, regionList, fields, isList)
|
||||
managerRows := manager.SManagedResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, managerList, fields, isList)
|
||||
for i := range rows {
|
||||
rows[i].CloudregionResourceInfo = regionRows[i]
|
||||
rows[i].ManagedResourceInfo = managerRows[i]
|
||||
}
|
||||
|
||||
return rows
|
||||
}
|
||||
|
||||
@@ -104,10 +125,27 @@ func (manager *SSecurityGroupResourceBaseManager) ListItemFilter(
|
||||
}
|
||||
q = q.Equals("secgroup_id", secgrpObj.GetId())
|
||||
}
|
||||
|
||||
if len(query.SecgroupName) > 0 {
|
||||
sq := SecurityGroupManager.Query("id").Like("name", "%"+query.SecgroupName+"%")
|
||||
q = q.In("secgroup_id", sq.SubQuery())
|
||||
}
|
||||
|
||||
var err error
|
||||
subq := SecurityGroupManager.Query("id").Snapshot()
|
||||
subq, err = manager.SManagedResourceBaseManager.ListItemFilter(ctx, subq, userCred, query.ManagedResourceListInput)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "SManagedResourceBaseManager.ListItemFilter")
|
||||
}
|
||||
|
||||
subq, err = manager.SCloudregionResourceBaseManager.ListItemFilter(ctx, subq, userCred, query.RegionalFilterListInput)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "SCloudregionResourceBaseManager.ListItemFilter")
|
||||
}
|
||||
if subq.IsAltered() {
|
||||
q = q.Filter(sqlchemy.In(q.Field("secgroup_id"), subq.SubQuery()))
|
||||
}
|
||||
|
||||
return q, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -122,7 +122,8 @@ type SServerSku struct {
|
||||
|
||||
func (manager *SServerSkuManager) FetchUniqValues(ctx context.Context, data jsonutils.JSONObject) jsonutils.JSONObject {
|
||||
regionId, _ := data.GetString("cloudregion_id")
|
||||
return jsonutils.Marshal(map[string]string{"cloudregion_id": regionId})
|
||||
zoneId, _ := data.GetString("zone_id")
|
||||
return jsonutils.Marshal(map[string]string{"cloudregion_id": regionId, "zone_id": zoneId})
|
||||
}
|
||||
|
||||
func (manager *SServerSkuManager) FilterByUniqValues(q *sqlchemy.SQuery, values jsonutils.JSONObject) *sqlchemy.SQuery {
|
||||
@@ -130,6 +131,10 @@ func (manager *SServerSkuManager) FilterByUniqValues(q *sqlchemy.SQuery, values
|
||||
if len(regionId) > 0 {
|
||||
q = q.Equals("cloudregion_id", regionId)
|
||||
}
|
||||
zoneId, _ := values.GetString("zone_id")
|
||||
if len(zoneId) > 0 {
|
||||
q = q.Equals("zone_id", zoneId)
|
||||
}
|
||||
return q
|
||||
}
|
||||
|
||||
@@ -351,8 +356,6 @@ func (self *SServerSkuManager) ValidateCreateData(ctx context.Context, userCred
|
||||
if input.Provider == api.CLOUD_PROVIDER_ONECLOUD {
|
||||
} else if utils.IsInStringArray(input.Provider, api.PRIVATE_CLOUD_PROVIDERS) {
|
||||
input.Status = api.SkuStatusCreating
|
||||
} else {
|
||||
return input, httperrors.NewUnsupportOperationError("Not support create public cloud sku")
|
||||
}
|
||||
|
||||
input.LocalCategory = input.InstanceTypeCategory
|
||||
|
||||
@@ -1694,6 +1694,19 @@ func (manager *SStorageManager) InitializeData() error {
|
||||
}
|
||||
}
|
||||
}
|
||||
sq := CloudproviderManager.Query("id").Equals("provider", api.CLOUD_PROVIDER_ALIYUN).SubQuery()
|
||||
q = manager.Query().NotEquals("medium_type", api.DISK_TYPE_SSD).In("manager_id", sq)
|
||||
storages = make([]SStorage, 0)
|
||||
err = db.FetchModelObjects(manager, q, &storages)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for i := range storages {
|
||||
db.Update(&storages[i], func() error {
|
||||
storages[i].MediumType = api.DISK_TYPE_SSD
|
||||
return nil
|
||||
})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
33
pkg/compute/regiondrivers/cloudflare.go
Normal file
33
pkg/compute/regiondrivers/cloudflare.go
Normal file
@@ -0,0 +1,33 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// 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.
|
||||
|
||||
package regiondrivers
|
||||
|
||||
import (
|
||||
api "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
"yunion.io/x/onecloud/pkg/compute/models"
|
||||
)
|
||||
|
||||
type SCloudflareRegionDriver struct {
|
||||
SManagedVirtualizationRegionDriver
|
||||
}
|
||||
|
||||
func init() {
|
||||
driver := SCloudflareRegionDriver{}
|
||||
models.RegisterRegionDriver(&driver)
|
||||
}
|
||||
|
||||
func (self *SCloudflareRegionDriver) GetProvider() string {
|
||||
return api.CLOUD_PROVIDER_CLOUDFLARE
|
||||
}
|
||||
@@ -29,7 +29,6 @@ import (
|
||||
randutil "yunion.io/x/pkg/util/rand"
|
||||
"yunion.io/x/pkg/util/regutils"
|
||||
"yunion.io/x/pkg/util/secrules"
|
||||
"yunion.io/x/pkg/util/sets"
|
||||
"yunion.io/x/pkg/utils"
|
||||
"yunion.io/x/sqlchemy"
|
||||
|
||||
@@ -888,7 +887,12 @@ func (self *SKVMRegionDriver) RequestSyncDiskStatus(ctx context.Context, userCre
|
||||
originStatus, _ := task.GetParams().GetString("origin_status")
|
||||
status, _ := res.GetString("status")
|
||||
if status == api.DISK_EXIST {
|
||||
if sets.NewString(api.DISK_UNKNOWN, api.DISK_REBUILD_FAILED).Has(originStatus) {
|
||||
if utils.IsInArray(originStatus, []string{
|
||||
api.DISK_UNKNOWN,
|
||||
api.DISK_REBUILD_FAILED,
|
||||
api.DISK_ATTACHING,
|
||||
api.DISK_DETACHING,
|
||||
}) {
|
||||
diskStatus = api.DISK_READY
|
||||
} else {
|
||||
diskStatus = originStatus
|
||||
|
||||
@@ -106,6 +106,8 @@ func InitHandlers(app *appsrv.Application) {
|
||||
|
||||
models.SnapshotPolicyDiskManager,
|
||||
models.LoadbalancerSecurityGroupManager,
|
||||
|
||||
models.HostFileJointsManager,
|
||||
} {
|
||||
db.RegisterModelManager(manager)
|
||||
}
|
||||
@@ -249,6 +251,8 @@ func InitHandlers(app *appsrv.Application) {
|
||||
models.SSLCertificateManager,
|
||||
|
||||
baremetalmodels.BaremetalProfileManager,
|
||||
|
||||
models.HostFileManager,
|
||||
} {
|
||||
db.RegisterModelManager(manager)
|
||||
handler := db.NewModelHandler(manager)
|
||||
|
||||
95
pkg/compute/tasks/disk/disk_change_billing_type_task.go
Normal file
95
pkg/compute/tasks/disk/disk_change_billing_type_task.go
Normal file
@@ -0,0 +1,95 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// 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.
|
||||
|
||||
package disk
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/cloudmux/pkg/cloudprovider"
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/apis"
|
||||
billing_api "yunion.io/x/onecloud/pkg/apis/billing"
|
||||
api "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
|
||||
"yunion.io/x/onecloud/pkg/compute/models"
|
||||
"yunion.io/x/onecloud/pkg/util/logclient"
|
||||
)
|
||||
|
||||
type DiskChangeBillingTypeTask struct {
|
||||
SDiskBaseTask
|
||||
}
|
||||
|
||||
func init() {
|
||||
taskman.RegisterTask(DiskChangeBillingTypeTask{})
|
||||
}
|
||||
|
||||
func (self *DiskChangeBillingTypeTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
|
||||
disk := obj.(*models.SDisk)
|
||||
|
||||
idisk, err := disk.GetIDisk(ctx)
|
||||
if err != nil {
|
||||
self.taskFail(ctx, disk, errors.Wrapf(err, "GetIDisk"))
|
||||
return
|
||||
}
|
||||
|
||||
billType := ""
|
||||
switch disk.BillingType {
|
||||
case billing_api.BILLING_TYPE_POSTPAID:
|
||||
billType = billing_api.BILLING_TYPE_PREPAID
|
||||
case billing_api.BILLING_TYPE_PREPAID:
|
||||
billType = billing_api.BILLING_TYPE_POSTPAID
|
||||
}
|
||||
|
||||
err = idisk.ChangeBillingType(billType)
|
||||
if err != nil {
|
||||
if errors.Cause(err) == cloudprovider.ErrNotImplemented {
|
||||
disk.SetStatus(ctx, self.GetUserCred(), api.DISK_READY, "")
|
||||
self.SetStageComplete(ctx, nil)
|
||||
return
|
||||
}
|
||||
self.taskFail(ctx, disk, errors.Wrapf(err, "ChangeBillingType"))
|
||||
return
|
||||
}
|
||||
|
||||
idisk.Refresh()
|
||||
|
||||
db.Update(disk, func() error {
|
||||
disk.BillingType = billType
|
||||
disk.ExpiredAt = time.Time{}
|
||||
if disk.BillingType == billing_api.BILLING_TYPE_PREPAID {
|
||||
disk.AutoRenew = idisk.IsAutoRenew()
|
||||
disk.ExpiredAt = idisk.GetExpiredAt()
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
self.taskComplete(ctx, disk)
|
||||
}
|
||||
|
||||
func (self *DiskChangeBillingTypeTask) taskComplete(ctx context.Context, disk *models.SDisk) {
|
||||
disk.SetStatus(ctx, self.GetUserCred(), api.DISK_READY, "")
|
||||
logclient.AddActionLogWithStartable(self, disk, logclient.ACT_CHANGE_BILLING_TYPE, disk.BillingType, self.UserCred, true)
|
||||
self.SetStageComplete(ctx, nil)
|
||||
}
|
||||
|
||||
func (self *DiskChangeBillingTypeTask) taskFail(ctx context.Context, disk *models.SDisk, err error) {
|
||||
disk.SetStatus(ctx, self.GetUserCred(), apis.STATUS_CHANGE_BILLING_TYPE_FAILED, "")
|
||||
logclient.AddActionLogWithStartable(self, disk, logclient.ACT_CHANGE_BILLING_TYPE, err, self.UserCred, false)
|
||||
self.SetStageFailed(ctx, jsonutils.NewString(err.Error()))
|
||||
}
|
||||
@@ -69,6 +69,7 @@ func (self *DnsRecordCreateTask) OnInit(ctx context.Context, obj db.IStandaloneM
|
||||
Enabled: record.Enabled.Bool(),
|
||||
DnsType: cloudprovider.TDnsType(record.DnsType),
|
||||
DnsValue: record.DnsValue,
|
||||
Proxied: record.Proxied.Bool(),
|
||||
Ttl: record.TTL,
|
||||
MxPriority: record.MxPriority,
|
||||
PolicyType: cloudprovider.TDnsPolicyType(record.PolicyType),
|
||||
|
||||
@@ -76,6 +76,7 @@ func (self *DnsRecordUpdateTask) OnInit(ctx context.Context, obj db.IStandaloneM
|
||||
DnsValue: record.DnsValue,
|
||||
DnsType: cloudprovider.TDnsType(record.DnsType),
|
||||
Enabled: record.Enabled.Bool(),
|
||||
Proxied: record.Proxied.Bool(),
|
||||
Ttl: record.TTL,
|
||||
MxPriority: record.MxPriority,
|
||||
PolicyType: cloudprovider.TDnsPolicyType(record.PolicyType),
|
||||
|
||||
@@ -88,8 +88,9 @@ func (self *BaremetalServerSyncStatusTask) OnGuestStatusTaskComplete(ctx context
|
||||
}
|
||||
|
||||
func (self *BaremetalServerSyncStatusTask) OnGuestStatusTaskCompleteFailed(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
|
||||
input := apis.PerformStatusInput{
|
||||
Status: api.VM_UNKNOWN,
|
||||
input := api.ServerPerformStatusInput{
|
||||
PerformStatusInput: apis.PerformStatusInput{
|
||||
Status: api.VM_UNKNOWN},
|
||||
}
|
||||
guest.PerformStatus(ctx, self.UserCred, nil, input)
|
||||
}
|
||||
@@ -97,8 +98,10 @@ func (self *BaremetalServerSyncStatusTask) OnGuestStatusTaskCompleteFailed(ctx c
|
||||
func (self *BaremetalServerSyncStatusTask) OnGetStatusFail(ctx context.Context, guest *models.SGuest) {
|
||||
kwargs := jsonutils.NewDict()
|
||||
kwargs.Set("status", jsonutils.NewString(api.VM_UNKNOWN))
|
||||
input := apis.PerformStatusInput{
|
||||
Status: api.VM_UNKNOWN,
|
||||
input := api.ServerPerformStatusInput{
|
||||
PerformStatusInput: apis.PerformStatusInput{
|
||||
Status: api.VM_UNKNOWN,
|
||||
},
|
||||
}
|
||||
guest.PerformStatus(ctx, self.UserCred, nil, input)
|
||||
self.SetStageComplete(ctx, nil)
|
||||
|
||||
@@ -19,7 +19,7 @@ import (
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
|
||||
api "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
"yunion.io/x/onecloud/pkg/apis"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
|
||||
"yunion.io/x/onecloud/pkg/compute/models"
|
||||
@@ -49,12 +49,12 @@ func (self *GuestChangeBillingTypeTask) OnInit(ctx context.Context, obj db.IStan
|
||||
}
|
||||
|
||||
func (self *GuestChangeBillingTypeTask) OnGuestChangeBillingTypeTaskComplete(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
|
||||
logclient.AddActionLogWithStartable(self, guest, logclient.ACT_VM_CHANGE_BILLING_TYPE, guest.BillingType, self.UserCred, false)
|
||||
logclient.AddActionLogWithStartable(self, guest, logclient.ACT_CHANGE_BILLING_TYPE, guest.BillingType, self.UserCred, false)
|
||||
self.SetStageComplete(ctx, nil)
|
||||
}
|
||||
|
||||
func (self *GuestChangeBillingTypeTask) OnGuestChangeBillingTypeTaskCompleteFailed(ctx context.Context, guest *models.SGuest, reason jsonutils.JSONObject) {
|
||||
guest.SetStatus(ctx, self.GetUserCred(), api.VM_CHANGE_BILLING_TYPE_FAILED, "")
|
||||
logclient.AddActionLogWithStartable(self, guest, logclient.ACT_VM_CHANGE_BILLING_TYPE, reason.String(), self.UserCred, false)
|
||||
guest.SetStatus(ctx, self.GetUserCred(), apis.STATUS_CHANGE_BILLING_TYPE_FAILED, "")
|
||||
logclient.AddActionLogWithStartable(self, guest, logclient.ACT_CHANGE_BILLING_TYPE, reason.String(), self.UserCred, false)
|
||||
self.SetStageFailed(ctx, reason)
|
||||
}
|
||||
|
||||
@@ -24,10 +24,12 @@ import (
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
billing_api "yunion.io/x/onecloud/pkg/apis/billing"
|
||||
api "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
|
||||
"yunion.io/x/onecloud/pkg/compute/models"
|
||||
"yunion.io/x/onecloud/pkg/util/logclient"
|
||||
)
|
||||
|
||||
type GuestCreateDiskTask struct {
|
||||
@@ -211,12 +213,12 @@ func (self *ManagedGuestCreateDiskTask) OnManagedDiskPrepared(ctx context.Contex
|
||||
|
||||
for _, d := range disks {
|
||||
diskId := d.DiskId
|
||||
iDisk, err := models.DiskManager.FetchById(diskId)
|
||||
_disk, err := models.DiskManager.FetchById(diskId)
|
||||
if err != nil {
|
||||
self.SetStageFailed(ctx, jsonutils.NewString(err.Error()))
|
||||
return
|
||||
}
|
||||
disk := iDisk.(*models.SDisk)
|
||||
disk := _disk.(*models.SDisk)
|
||||
if disk.Status != api.DISK_READY {
|
||||
self.SetStageFailed(ctx, jsonutils.NewString(fmt.Sprintf("disk %s is not ready(status=%s)", disk.Id, disk.Status)))
|
||||
return
|
||||
@@ -240,7 +242,28 @@ func (self *ManagedGuestCreateDiskTask) OnManagedDiskPrepared(ctx context.Contex
|
||||
self.SetStageFailed(ctx, jsonutils.NewString(fmt.Sprintf("Attach Disk to guest fail error: %v", err)))
|
||||
return
|
||||
}
|
||||
|
||||
time.Sleep(time.Second * 5)
|
||||
|
||||
if guest.BillingType == billing_api.BILLING_TYPE_PREPAID {
|
||||
idisk, err := disk.GetIDisk(ctx)
|
||||
if err != nil {
|
||||
if errors.Cause(err) != cloudprovider.ErrNotFound {
|
||||
logclient.AddActionLogWithStartable(self, guest, logclient.ACT_CHANGE_BILLING_TYPE, errors.Wrapf(err, "GetIDisk %s", disk.ExternalId), self.UserCred, false)
|
||||
continue
|
||||
}
|
||||
}
|
||||
err = idisk.ChangeBillingType(guest.BillingType)
|
||||
if err != nil {
|
||||
logclient.AddActionLogWithStartable(self, guest, logclient.ACT_CHANGE_BILLING_TYPE, errors.Wrapf(err, "ChangeBillingType %s", disk.ExternalId), self.UserCred, false)
|
||||
continue
|
||||
}
|
||||
|
||||
db.Update(disk, func() error {
|
||||
disk.BillingType = guest.BillingType
|
||||
return nil
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
self.SetStageComplete(ctx, nil)
|
||||
|
||||
@@ -108,7 +108,7 @@ func (self *GuestSyncConfTask) StartRestartNetworkTask(ctx context.Context, gues
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = drv.QgaRequestGuestPing(ctx, self.GetTaskRequestHeader(), host, guest, false, &api.ServerQgaTimeoutInput{Timeout: 1000})
|
||||
err = drv.QgaRequestGuestPing(ctx, self.GetTaskRequestHeader(), host, guest, false, &api.ServerQgaTimeoutInput{Timeout: 1})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "qga guest-ping")
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ func (self *GuestSyncstatusTask) getOriginStatus() string {
|
||||
func (self *GuestSyncstatusTask) OnGetStatusComplete(ctx context.Context, obj db.IStandaloneModel, body jsonutils.JSONObject) {
|
||||
guest := obj.(*models.SGuest)
|
||||
log.Debugf("OnGetStatusSucc guest %s(%s) status %s", guest.Name, guest.Id, body)
|
||||
resp := new(api.HostUploadGuestStatusResponse)
|
||||
resp := new(api.HostUploadGuestStatusInput)
|
||||
body.Unmarshal(resp)
|
||||
if err := guest.SetStatusFromHost(ctx, self.GetUserCred(), *resp, self.HasParentTask(), self.getOriginStatus()); err != nil {
|
||||
log.Warningf("SetStatusFromHost for guest %s error: %v", guest.GetId(), err)
|
||||
|
||||
@@ -81,6 +81,11 @@ func (t *PodStopTask) OnContainerStopped(ctx context.Context, pod *models.SGuest
|
||||
task.ScheduleRun(nil)
|
||||
}
|
||||
|
||||
func (t *PodStopTask) OnContainerStoppedFailed(ctx context.Context, pod *models.SGuest, data jsonutils.JSONObject) {
|
||||
pod.SetStatus(ctx, t.GetUserCred(), api.POD_STATUS_STOP_CONTAINER_FAILED, data.String())
|
||||
t.SetStageFailed(ctx, data)
|
||||
}
|
||||
|
||||
func (t *PodStopTask) OnPodStopped(ctx context.Context, pod *models.SGuest, data jsonutils.JSONObject) {
|
||||
pod.SetStatus(ctx, t.GetUserCred(), api.VM_READY, "")
|
||||
t.SetStageComplete(ctx, nil)
|
||||
|
||||
8
pkg/hostman/container/snapshot_service/constants.go
Normal file
8
pkg/hostman/container/snapshot_service/constants.go
Normal file
@@ -0,0 +1,8 @@
|
||||
package snapshot_service
|
||||
|
||||
const (
|
||||
DefaultRootDir = "/opt/yunion/containerd/io.yunion.containerd.host-overlay-snapshotter"
|
||||
SocksFileName = "grpc.socks"
|
||||
LabelServerId = "containerd.io/snapshot/host-overlay.server-id"
|
||||
LabelContainerId = "containerd.io/snapshot/host-overlay.container-id"
|
||||
)
|
||||
1
pkg/hostman/container/snapshot_service/doc.go
Normal file
1
pkg/hostman/container/snapshot_service/doc.go
Normal file
@@ -0,0 +1 @@
|
||||
package snapshot_service // import "yunion.io/x/onecloud/pkg/hostman/container/snapshot_service"
|
||||
150
pkg/hostman/container/snapshot_service/snapshot_service.go
Normal file
150
pkg/hostman/container/snapshot_service/snapshot_service.go
Normal file
@@ -0,0 +1,150 @@
|
||||
package snapshot_service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
snapshotsapi "github.com/containerd/containerd/api/services/snapshots/v1"
|
||||
"github.com/containerd/containerd/contrib/snapshotservice"
|
||||
"github.com/containerd/containerd/mount"
|
||||
"github.com/containerd/containerd/snapshots"
|
||||
"github.com/containerd/containerd/snapshots/overlay"
|
||||
"google.golang.org/grpc"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/errors"
|
||||
)
|
||||
|
||||
func StartService(guestMan IGuestManager, root string) error {
|
||||
sn, err := NewSnapshotter(guestMan, root)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "NewSnapshotter")
|
||||
}
|
||||
svc := snapshotservice.FromSnapshotter(sn)
|
||||
rpc := grpc.NewServer()
|
||||
snapshotsapi.RegisterSnapshotsServer(rpc, svc)
|
||||
socksPath := path.Join(root, SocksFileName)
|
||||
if err := os.RemoveAll(socksPath); err != nil {
|
||||
return errors.Wrapf(err, "RemoveAll %s", socksPath)
|
||||
}
|
||||
listener, err := net.Listen("unix", socksPath)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Listen %s", socksPath)
|
||||
}
|
||||
return rpc.Serve(listener)
|
||||
}
|
||||
|
||||
type IGuestManager interface {
|
||||
GetContainerManager(serverId string) (ISnapshotContainerManager, error)
|
||||
}
|
||||
|
||||
type ISnapshotContainerManager interface {
|
||||
GetRootFsMountPath(ctx context.Context, containerId string) (string, error)
|
||||
}
|
||||
|
||||
func NewSnapshotter(guestMan IGuestManager, root string, opts ...overlay.Opt) (snapshots.Snapshotter, error) {
|
||||
sn, err := overlay.NewSnapshotter(root, opts...)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "NewSnapshotter")
|
||||
}
|
||||
return &overlayRootFsUpperSnapshotter{
|
||||
Snapshotter: sn,
|
||||
guestMan: guestMan,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type overlayRootFsUpperSnapshotter struct {
|
||||
snapshots.Snapshotter
|
||||
guestMan IGuestManager
|
||||
}
|
||||
|
||||
func (s *overlayRootFsUpperSnapshotter) Mounts(ctx context.Context, key string) ([]mount.Mount, error) {
|
||||
info, err := s.Snapshotter.Stat(ctx, key)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "Stat with %s", key)
|
||||
}
|
||||
infoJson := jsonutils.Marshal(info)
|
||||
log.Infof("mount request info: %s", infoJson.String())
|
||||
mounts, err := s.Snapshotter.Mounts(ctx, key)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "Mounts with %s", key)
|
||||
}
|
||||
mounts, err = s.changeUpper(ctx, key, mounts)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "Mounts.changeUpper with %s", key)
|
||||
}
|
||||
return mounts, nil
|
||||
}
|
||||
|
||||
func (s *overlayRootFsUpperSnapshotter) Prepare(ctx context.Context, key string, parent string, opts ...snapshots.Opt) ([]mount.Mount, error) {
|
||||
mounts, err := s.Snapshotter.Prepare(ctx, key, parent, opts...)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "Prepare with %s", key)
|
||||
}
|
||||
mounts, err = s.changeUpper(ctx, key, mounts)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "Prepare.changeUpper with %s", key)
|
||||
}
|
||||
return mounts, nil
|
||||
}
|
||||
|
||||
func (s *overlayRootFsUpperSnapshotter) View(ctx context.Context, key string, parent string, opts ...snapshots.Opt) ([]mount.Mount, error) {
|
||||
mounts, err := s.Snapshotter.View(ctx, key, parent, opts...)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "View with %s", key)
|
||||
}
|
||||
mounts, err = s.changeUpper(ctx, key, mounts)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "View.changeUpper with %s", key)
|
||||
}
|
||||
return mounts, nil
|
||||
}
|
||||
|
||||
func (s *overlayRootFsUpperSnapshotter) changeUpper(ctx context.Context, key string, mounts []mount.Mount) ([]mount.Mount, error) {
|
||||
if len(mounts) != 1 || mounts[0].Type != "overlay" {
|
||||
return mounts, nil
|
||||
}
|
||||
info, err := s.Snapshotter.Stat(ctx, key)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "Stat with %s", key)
|
||||
}
|
||||
serverId, ok := info.Labels[LabelServerId]
|
||||
if !ok || serverId == "" {
|
||||
return mounts, nil
|
||||
}
|
||||
containerId, ok := info.Labels[LabelContainerId]
|
||||
if !ok || containerId == "" {
|
||||
return mounts, nil
|
||||
}
|
||||
ctrMan, err := s.guestMan.GetContainerManager(serverId)
|
||||
if err != nil {
|
||||
return mounts, errors.Wrapf(err, "GetContainerManager with %s", serverId)
|
||||
}
|
||||
rootFsPath, err := ctrMan.GetRootFsMountPath(ctx, containerId)
|
||||
if err != nil {
|
||||
return mounts, errors.Wrapf(err, "GetRootFsMountPath with %s, %s", serverId, containerId)
|
||||
}
|
||||
upperPath := path.Join(rootFsPath, "upper")
|
||||
workPath := path.Join(rootFsPath, "work")
|
||||
for _, dir := range []string{upperPath, workPath} {
|
||||
if err := os.MkdirAll(dir, 0755); err != nil {
|
||||
return mounts, errors.Wrapf(err, "MkdirAll %s", dir)
|
||||
}
|
||||
}
|
||||
|
||||
upperDirKey := "upperdir="
|
||||
workDirKey := "workdir="
|
||||
for i, o := range mounts[0].Options {
|
||||
if strings.HasPrefix(o, upperDirKey) {
|
||||
mounts[0].Options[i] = upperDirKey + upperPath
|
||||
}
|
||||
if strings.HasPrefix(o, workDirKey) {
|
||||
mounts[0].Options[i] = workDirKey + workPath
|
||||
}
|
||||
}
|
||||
return mounts, nil
|
||||
}
|
||||
@@ -25,6 +25,7 @@ import (
|
||||
"yunion.io/x/onecloud/pkg/apis"
|
||||
computeapi "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
"yunion.io/x/onecloud/pkg/hostman/container/prober/results"
|
||||
"yunion.io/x/onecloud/pkg/hostman/guestman/pod/statusman"
|
||||
"yunion.io/x/onecloud/pkg/hostman/hostutils"
|
||||
)
|
||||
|
||||
@@ -49,6 +50,44 @@ func (m *manager) SetContainerStartup(podId string, containerId string, started
|
||||
status = computeapi.CONTAINER_STATUS_NET_FAILED
|
||||
}
|
||||
}
|
||||
|
||||
input := &statusman.PodStatusUpdateRequest{
|
||||
Id: podId,
|
||||
Pod: pod.(statusman.IPod),
|
||||
Status: computeapi.VM_RUNNING,
|
||||
Reason: result.Reason,
|
||||
ContainerStatuses: map[string]*statusman.ContainerStatus{
|
||||
containerId: {Status: status},
|
||||
},
|
||||
}
|
||||
|
||||
if err := statusman.GetManager().UpdateStatus(input); err != nil {
|
||||
err = errors.Wrapf(err, "set container(%s/%s) status failed, input: %s", podId, containerId, jsonutils.Marshal(input.ToServerPerformStatusInput()))
|
||||
log.Warningf(err.Error())
|
||||
errMsg := []string{
|
||||
"can't set container status",
|
||||
}
|
||||
for _, msg := range errMsg {
|
||||
if strings.Contains(err.Error(), msg) {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return errors.Wrap(err, "update container status")
|
||||
} else {
|
||||
log.Infof("set container(%s/%s) status to %s", podId, containerId, jsonutils.Marshal(input).String())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *manager) SetContainerStartupOld(podId string, containerId string, started bool, result results.ProbeResult, pod results.IPod) error {
|
||||
status := computeapi.CONTAINER_STATUS_PROBE_FAILED
|
||||
if started {
|
||||
status = computeapi.CONTAINER_STATUS_RUNNING
|
||||
} else {
|
||||
if result.IsNetFailedError() && pod.IsRunning() {
|
||||
status = computeapi.CONTAINER_STATUS_NET_FAILED
|
||||
}
|
||||
}
|
||||
input := &computeapi.ContainerPerformStatusInput{
|
||||
PerformStatusInput: apis.PerformStatusInput{
|
||||
Status: status,
|
||||
|
||||
@@ -54,9 +54,15 @@ func (p postOverlayHostPath) Mount(d diskPostOverlay, pod volume_mount.IPodInfo,
|
||||
return errors.Wrapf(err, "get post overlay mountpoint for container %s", ctrId)
|
||||
}
|
||||
|
||||
return mountutils.MountOverlayWithFeatures(ov.HostLowerDir, upperDir, workDir, mergedDir, &mountutils.MountOverlayFeatures{
|
||||
if err := mountutils.MountOverlayWithFeatures(ov.HostLowerDir, upperDir, workDir, mergedDir, &mountutils.MountOverlayFeatures{
|
||||
MetaCopy: true,
|
||||
})
|
||||
}); err != nil {
|
||||
return errors.Wrapf(err, "mount overlay dir for container %s", ctrId)
|
||||
}
|
||||
if err := volume_mount.ChangeDirOwnerDirectly(mergedDir, ov.FsUser, ov.FsGroup); err != nil {
|
||||
return errors.Wrapf(err, "change dir owner")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p postOverlayHostPath) Unmount(d diskPostOverlay, pod volume_mount.IPodInfo, ctrId string, vm *hostapi.ContainerVolumeMount, ov *apis.ContainerVolumeMountDiskPostOverlay, useLazy bool, cleanLayers bool) error {
|
||||
|
||||
@@ -61,6 +61,8 @@ func (i postOverlayImage) convertToDiskOV(ov *apis.ContainerVolumeMountDiskPostO
|
||||
return &apis.ContainerVolumeMountDiskPostOverlay{
|
||||
HostLowerDir: []string{hostPath},
|
||||
ContainerTargetDir: ctrPath,
|
||||
FsUser: ov.FsUser,
|
||||
FsGroup: ov.FsGroup,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -47,12 +47,19 @@ func ChangeDirOwner(pod IPodInfo, drv IVolumeMount, ctrId string, vol *hostapi.C
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "GetRuntimeMountHostPath")
|
||||
}
|
||||
return ChangeDirOwnerDirectly(hostPath, vol.FsUser, vol.FsGroup)
|
||||
}
|
||||
|
||||
func ChangeDirOwnerDirectly(hostPath string, fsUser, fsGroup *int64) error {
|
||||
args := ""
|
||||
if vol.FsUser != nil {
|
||||
args = fmt.Sprintf("%d", *vol.FsUser)
|
||||
if fsUser != nil {
|
||||
args = fmt.Sprintf("%d", *fsUser)
|
||||
}
|
||||
if vol.FsGroup != nil {
|
||||
args = fmt.Sprintf("%s:%d", args, *vol.FsGroup)
|
||||
if fsGroup != nil {
|
||||
args = fmt.Sprintf("%s:%d", args, *fsGroup)
|
||||
}
|
||||
if args == "" {
|
||||
return nil
|
||||
}
|
||||
out, err := procutils.NewRemoteCommandAsFarAsPossible("chown", args, hostPath).Output()
|
||||
if err != nil {
|
||||
|
||||
@@ -65,8 +65,8 @@ func DoDeployGuestFs(rootfs fsdriver.IRootFsDriver, guestDesc *deployapi.GuestDe
|
||||
hn = guestDesc.Name
|
||||
domain = guestDesc.Domain
|
||||
gid = guestDesc.Uuid
|
||||
nics = fsdriver.ToServerNics(guestDesc.Nics)
|
||||
nicsStandby = fsdriver.ToServerNics(guestDesc.NicsStandby)
|
||||
nics = fsdriver.ToServerNics(guestDesc, guestDesc.Nics)
|
||||
nicsStandby = fsdriver.ToServerNics(guestDesc, guestDesc.NicsStandby)
|
||||
partition = rootfs.GetPartition()
|
||||
releaseInfo = rootfs.GetReleaseInfo(partition)
|
||||
)
|
||||
|
||||
@@ -959,8 +959,16 @@ func (d *sDebianLikeRootFs) DeployNetworkingScripts(rootFs IDiskPartition, nics
|
||||
cmds.WriteString(" netmask 255.255.255.255\n")
|
||||
cmds.WriteString("\n")
|
||||
} else if nicDesc.Manual {
|
||||
netmask := netutils2.Netlen2Mask(int(nicDesc.Masklen))
|
||||
ifname := nicDesc.Name
|
||||
cmds.WriteString(fmt.Sprintf("iface %s inet static\n", nicDesc.Name))
|
||||
if nicDesc.VlanInterface {
|
||||
cmds.WriteString("\n")
|
||||
ifname = fmt.Sprintf("%s.%d", nicDesc.Name, nicDesc.Vlan)
|
||||
cmds.WriteString(fmt.Sprintf("auto %s\n", ifname))
|
||||
cmds.WriteString(fmt.Sprintf("iface %s inet static\n", ifname))
|
||||
}
|
||||
|
||||
netmask := netutils2.Netlen2Mask(int(nicDesc.Masklen))
|
||||
cmds.WriteString(fmt.Sprintf(" address %s\n", nicDesc.Ip))
|
||||
cmds.WriteString(fmt.Sprintf(" netmask %s\n", netmask))
|
||||
cmds.WriteString(fmt.Sprintf(" hwaddress ether %s\n", nicDesc.Mac))
|
||||
@@ -990,7 +998,7 @@ func (d *sDebianLikeRootFs) DeployNetworkingScripts(rootFs IDiskPartition, nics
|
||||
}
|
||||
cmds.WriteString("\n")
|
||||
if len(nicDesc.Ip6) > 0 {
|
||||
cmds.WriteString(fmt.Sprintf("iface %s inet6 static\n", nicDesc.Name))
|
||||
cmds.WriteString(fmt.Sprintf("iface %s inet6 static\n", ifname))
|
||||
cmds.WriteString(fmt.Sprintf(" address %s\n", nicDesc.Ip6))
|
||||
cmds.WriteString(fmt.Sprintf(" netmask %d\n", nicDesc.Masklen6))
|
||||
if len(nicDesc.Gateway6) > 0 && nicDesc.Ip == mainIp {
|
||||
@@ -1426,54 +1434,60 @@ func (r *sRedhatLikeRootFs) deployNetworkingScripts(rootFs IDiskPartition, nics
|
||||
cmds.WriteString(netutils2.PSEUDO_VIP)
|
||||
cmds.WriteString("\n")
|
||||
} else if nicDesc.Manual {
|
||||
netmask := netutils2.Netlen2Mask(int(nicDesc.Masklen))
|
||||
cmds.WriteString("BOOTPROTO=none\n")
|
||||
cmds.WriteString("NETMASK=")
|
||||
cmds.WriteString(netmask)
|
||||
cmds.WriteString("\n")
|
||||
cmds.WriteString("IPADDR=")
|
||||
cmds.WriteString(nicDesc.Ip)
|
||||
cmds.WriteString("\n")
|
||||
if len(nicDesc.Gateway) > 0 && nicDesc.Ip == mainIp {
|
||||
cmds.WriteString("GATEWAY=")
|
||||
cmds.WriteString(nicDesc.Gateway)
|
||||
if nicDesc.VlanInterface {
|
||||
if err := r.deployVlanNetworkingScripts(rootFs, scriptPath, mainIp, nicCnt, nicDesc); err != nil {
|
||||
return errors.Wrap(err, "deployVlanNetworkingScripts")
|
||||
}
|
||||
} else {
|
||||
netmask := netutils2.Netlen2Mask(int(nicDesc.Masklen))
|
||||
cmds.WriteString("NETMASK=")
|
||||
cmds.WriteString(netmask)
|
||||
cmds.WriteString("\n")
|
||||
}
|
||||
var routes = make([][]string, 0)
|
||||
routes = netutils2.AddNicRoutes(routes, nicDesc, mainIp, nicCnt)
|
||||
var rtbl strings.Builder
|
||||
for _, r := range routes {
|
||||
rtbl.WriteString(r[0])
|
||||
rtbl.WriteString(" via ")
|
||||
rtbl.WriteString(r[1])
|
||||
rtbl.WriteString(" dev ")
|
||||
rtbl.WriteString(nicDesc.Name)
|
||||
rtbl.WriteString("\n")
|
||||
}
|
||||
rtblStr := rtbl.String()
|
||||
if len(rtblStr) > 0 {
|
||||
var fn = fmt.Sprintf("%s/route-%s", scriptPath, nicDesc.Name)
|
||||
if err := rootFs.FilePutContents(fn, rtblStr, false, false); err != nil {
|
||||
return err
|
||||
cmds.WriteString("IPADDR=")
|
||||
cmds.WriteString(nicDesc.Ip)
|
||||
cmds.WriteString("\n")
|
||||
if len(nicDesc.Gateway) > 0 && nicDesc.Ip == mainIp {
|
||||
cmds.WriteString("GATEWAY=")
|
||||
cmds.WriteString(nicDesc.Gateway)
|
||||
cmds.WriteString("\n")
|
||||
}
|
||||
}
|
||||
dnslist := netutils2.GetNicDns(nicDesc)
|
||||
if len(dnslist) > 0 {
|
||||
cmds.WriteString("PEERDNS=yes\n")
|
||||
for i := 0; i < len(dnslist); i++ {
|
||||
cmds.WriteString(fmt.Sprintf("DNS%d=%s\n", i+1, dnslist[i]))
|
||||
var routes = make([][]string, 0)
|
||||
routes = netutils2.AddNicRoutes(routes, nicDesc, mainIp, nicCnt)
|
||||
var rtbl strings.Builder
|
||||
for _, r := range routes {
|
||||
rtbl.WriteString(r[0])
|
||||
rtbl.WriteString(" via ")
|
||||
rtbl.WriteString(r[1])
|
||||
rtbl.WriteString(" dev ")
|
||||
rtbl.WriteString(nicDesc.Name)
|
||||
rtbl.WriteString("\n")
|
||||
}
|
||||
if len(nicDesc.Domain) > 0 {
|
||||
cmds.WriteString(fmt.Sprintf("DOMAIN=%s\n", nicDesc.Domain))
|
||||
rtblStr := rtbl.String()
|
||||
if len(rtblStr) > 0 {
|
||||
var fn = fmt.Sprintf("%s/route-%s", scriptPath, nicDesc.Name)
|
||||
if err := rootFs.FilePutContents(fn, rtblStr, false, false); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(nicDesc.Ip6) > 0 {
|
||||
cmds.WriteString("IPV6INIT=yes\n")
|
||||
cmds.WriteString("DHCPV6C=no\n")
|
||||
cmds.WriteString("IPV6_AUTOCONF=no\n")
|
||||
cmds.WriteString(fmt.Sprintf("IPV6ADDR=%s/%d\n", nicDesc.Ip6, nicDesc.Masklen6))
|
||||
if len(nicDesc.Gateway6) > 0 {
|
||||
cmds.WriteString(fmt.Sprintf("IPV6_DEFAULTGW=%s\n", nicDesc.Gateway6))
|
||||
dnslist := netutils2.GetNicDns(nicDesc)
|
||||
if len(dnslist) > 0 {
|
||||
cmds.WriteString("PEERDNS=yes\n")
|
||||
for i := 0; i < len(dnslist); i++ {
|
||||
cmds.WriteString(fmt.Sprintf("DNS%d=%s\n", i+1, dnslist[i]))
|
||||
}
|
||||
if len(nicDesc.Domain) > 0 {
|
||||
cmds.WriteString(fmt.Sprintf("DOMAIN=%s\n", nicDesc.Domain))
|
||||
}
|
||||
}
|
||||
if len(nicDesc.Ip6) > 0 {
|
||||
cmds.WriteString("IPV6INIT=yes\n")
|
||||
cmds.WriteString("DHCPV6C=no\n")
|
||||
cmds.WriteString("IPV6_AUTOCONF=no\n")
|
||||
cmds.WriteString(fmt.Sprintf("IPV6ADDR=%s/%d\n", nicDesc.Ip6, nicDesc.Masklen6))
|
||||
if len(nicDesc.Gateway6) > 0 {
|
||||
cmds.WriteString(fmt.Sprintf("IPV6_DEFAULTGW=%s\n", nicDesc.Gateway6))
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -1499,6 +1513,75 @@ func (r *sRedhatLikeRootFs) deployNetworkingScripts(rootFs IDiskPartition, nics
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *sRedhatLikeRootFs) deployVlanNetworkingScripts(rootFs IDiskPartition, scriptPath, mainIp string, nicCnt int, nicDesc *types.SServerNic) error {
|
||||
if nicDesc.Vlan <= 1 {
|
||||
return nil
|
||||
}
|
||||
var cmds strings.Builder
|
||||
cmds.WriteString("BOOTPROTO=none\n")
|
||||
cmds.WriteString(fmt.Sprintf("DEVICE=%s.%d\n", nicDesc.Name, nicDesc.Vlan))
|
||||
cmds.WriteString(fmt.Sprintf("NAME=%s.%d\n", nicDesc.Name, nicDesc.Vlan))
|
||||
cmds.WriteString("ONBOOT=yes\n")
|
||||
if r.isNetworkManagerEnabled(rootFs) {
|
||||
cmds.WriteString("NM_CONTROLLED=yes\n")
|
||||
} else {
|
||||
cmds.WriteString("NM_CONTROLLED=no\n")
|
||||
}
|
||||
cmds.WriteString("USERCTL=no\n")
|
||||
if nicDesc.Mtu > 0 {
|
||||
cmds.WriteString(fmt.Sprintf("MTU=%d\n", nicDesc.Mtu))
|
||||
}
|
||||
|
||||
netmask := netutils2.Netlen2Mask(int(nicDesc.Masklen))
|
||||
cmds.WriteString("NETMASK=")
|
||||
cmds.WriteString(netmask)
|
||||
cmds.WriteString("\n")
|
||||
cmds.WriteString("IPADDR=")
|
||||
cmds.WriteString(nicDesc.Ip)
|
||||
cmds.WriteString("\n")
|
||||
if len(nicDesc.Gateway) > 0 && nicDesc.Ip == mainIp {
|
||||
cmds.WriteString("GATEWAY=")
|
||||
cmds.WriteString(nicDesc.Gateway)
|
||||
cmds.WriteString("\n")
|
||||
}
|
||||
var routes = make([][]string, 0)
|
||||
routes = netutils2.AddNicRoutes(routes, nicDesc, mainIp, nicCnt)
|
||||
var rtbl strings.Builder
|
||||
for _, r := range routes {
|
||||
rtbl.WriteString(r[0])
|
||||
rtbl.WriteString(" via ")
|
||||
rtbl.WriteString(r[1])
|
||||
rtbl.WriteString(" dev ")
|
||||
rtbl.WriteString(fmt.Sprintf("%s.%d", nicDesc.Name, nicDesc.Vlan))
|
||||
rtbl.WriteString("\n")
|
||||
}
|
||||
rtblStr := rtbl.String()
|
||||
if len(rtblStr) > 0 {
|
||||
var fn = fmt.Sprintf("%s/route-%s", scriptPath, nicDesc.Name)
|
||||
if err := rootFs.FilePutContents(fn, rtblStr, false, false); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
dnslist := netutils2.GetNicDns(nicDesc)
|
||||
if len(dnslist) > 0 {
|
||||
cmds.WriteString("PEERDNS=yes\n")
|
||||
for i := 0; i < len(dnslist); i++ {
|
||||
cmds.WriteString(fmt.Sprintf("DNS%d=%s\n", i+1, dnslist[i]))
|
||||
}
|
||||
if len(nicDesc.Domain) > 0 {
|
||||
cmds.WriteString(fmt.Sprintf("DOMAIN=%s\n", nicDesc.Domain))
|
||||
}
|
||||
}
|
||||
cmds.WriteString("VLAN=yes\n")
|
||||
|
||||
var fn = fmt.Sprintf("%s/ifcfg-%s.%d", scriptPath, nicDesc.Name, nicDesc.Vlan)
|
||||
log.Debugf("%s: %s", fn, cmds.String())
|
||||
if err := rootFs.FilePutContents(fn, cmds.String(), false, false); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *sRedhatLikeRootFs) DeployStandbyNetworkingScripts(rootFs IDiskPartition, nics, nicsStandby []*types.SServerNic) error {
|
||||
if err := r.sLinuxRootFs.DeployStandbyNetworkingScripts(rootFs, nics, nicsStandby); err != nil {
|
||||
return err
|
||||
|
||||
@@ -35,12 +35,29 @@ func newNetplanNetwork(allNics []*types.SServerNic, bondNics []*types.SServerNic
|
||||
nicCnt := len(allNics) - len(bondNics)
|
||||
for _, nic := range allNics {
|
||||
nicConf := getNetplanEthernetConfig(nic, false, mainIp, nicCnt)
|
||||
|
||||
if nicConf == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
network.AddEthernet(nic.Name, nicConf)
|
||||
if nic.VlanInterface {
|
||||
ifname := fmt.Sprintf("%s.%d", nic.Name, nic.Vlan)
|
||||
vlanConfig := &netplan.VlanConfig{
|
||||
EthernetConfig: *nicConf,
|
||||
Link: nic.Name,
|
||||
Id: nic.Vlan,
|
||||
}
|
||||
network.AddVlan(ifname, vlanConfig)
|
||||
|
||||
ethConfig := &netplan.EthernetConfig{
|
||||
DHCP4: false,
|
||||
DHCP6: false,
|
||||
MacAddress: nic.Mac,
|
||||
Match: netplan.NewEthernetConfigMatchMac(nic.Mac),
|
||||
}
|
||||
network.AddEthernet(nic.Name, ethConfig)
|
||||
} else {
|
||||
network.AddEthernet(nic.Name, nicConf)
|
||||
}
|
||||
}
|
||||
|
||||
for _, bondNic := range bondNics {
|
||||
|
||||
@@ -46,7 +46,7 @@ func findTeamingNic(nics []*types.SServerNic, mac string) *types.SServerNic {
|
||||
return nil
|
||||
}
|
||||
|
||||
func ToServerNics(nics []*deployapi.Nic) []*types.SServerNic {
|
||||
func ToServerNics(guestDesc *deployapi.GuestDesc, nics []*deployapi.Nic) []*types.SServerNic {
|
||||
ret := make([]*types.SServerNic, len(nics))
|
||||
for i := 0; i < len(nics); i++ {
|
||||
domain := nics[i].Domain
|
||||
@@ -84,6 +84,9 @@ func ToServerNics(nics []*deployapi.Nic) []*types.SServerNic {
|
||||
Masklen6: int(nics[i].Masklen6),
|
||||
Gateway6: nics[i].Gateway6,
|
||||
}
|
||||
if guestDesc.Hypervisor == computeapi.HYPERVISOR_BAREMETAL && ret[i].Vlan > 1 {
|
||||
ret[i].VlanInterface = true
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
@@ -85,6 +85,73 @@ func (r *sSuseLikeRootFs) enableBondingModule(rootFs IDiskPartition, bondNics []
|
||||
return rootFs.FilePutContents("/etc/modprobe.d/bonding.conf", content.String(), false, false)
|
||||
}
|
||||
|
||||
func (r *sSuseLikeRootFs) deployVlanNetworkingScripts(rootFs IDiskPartition, scriptPath, mainIp string, nicCnt int, nicDesc *types.SServerNic) error {
|
||||
var cmds strings.Builder
|
||||
var ifname = fmt.Sprintf("%s.%d", nicDesc.Name, nicDesc.Vlan)
|
||||
cmds.WriteString("STARTMODE=auto\n")
|
||||
if nicDesc.Mtu > 0 {
|
||||
cmds.WriteString(fmt.Sprintf("MTU=%d\n", nicDesc.Mtu))
|
||||
}
|
||||
cmds.WriteString("BOOTPROTO=static\n")
|
||||
cmds.WriteString(fmt.Sprintf("IPADDR=%s/%d\n", nicDesc.Ip, nicDesc.Masklen))
|
||||
|
||||
if len(nicDesc.Ip6) > 0 {
|
||||
cmds.WriteString("IPV6INIT=yes\n")
|
||||
cmds.WriteString("IPV6_AUTOCONF=no\n")
|
||||
cmds.WriteString(fmt.Sprintf("IPADDR_V6=%s/%d\n", nicDesc.Ip6, nicDesc.Masklen6))
|
||||
}
|
||||
|
||||
cmds.WriteString(fmt.Sprintf("VLAN_ID=%d\n", nicDesc.Vlan))
|
||||
cmds.WriteString(fmt.Sprintf("ETHERDEVICE=%s\n", nicDesc.Name))
|
||||
|
||||
var routes = make([][]string, 0)
|
||||
var dnsSrv []string
|
||||
routes = netutils2.AddNicRoutes(routes, nicDesc, mainIp, nicCnt)
|
||||
if len(nicDesc.Gateway) > 0 && nicDesc.Ip == mainIp {
|
||||
routes = append(routes, []string{
|
||||
"default",
|
||||
nicDesc.Gateway,
|
||||
})
|
||||
}
|
||||
if len(nicDesc.Gateway6) > 0 && nicDesc.Ip == mainIp {
|
||||
routes = append(routes, []string{
|
||||
"default",
|
||||
nicDesc.Gateway6,
|
||||
})
|
||||
}
|
||||
var rtbl strings.Builder
|
||||
for _, r := range routes {
|
||||
rtbl.WriteString(r[0])
|
||||
rtbl.WriteString(" ")
|
||||
rtbl.WriteString(r[1])
|
||||
rtbl.WriteString(" - ")
|
||||
rtbl.WriteString(nicDesc.Name)
|
||||
rtbl.WriteString("\n")
|
||||
}
|
||||
rtblStr := rtbl.String()
|
||||
if len(rtblStr) > 0 {
|
||||
var fn = fmt.Sprintf("/etc/sysconfig/network/ifroute-%s", ifname)
|
||||
if err := rootFs.FilePutContents(fn, rtblStr, false, false); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
dnslist := netutils2.GetNicDns(nicDesc)
|
||||
for i := 0; i < len(dnslist); i++ {
|
||||
if !utils.IsInArray(dnslist[i], dnsSrv) {
|
||||
dnsSrv = append(dnsSrv, dnslist[i])
|
||||
}
|
||||
}
|
||||
|
||||
var fn = fmt.Sprintf("/etc/sysconfig/network/ifcfg-%s", ifname)
|
||||
log.Debugf("%s: %s", fn, cmds.String())
|
||||
if err := rootFs.FilePutContents(fn, cmds.String(), false, false); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *sSuseLikeRootFs) deployNetworkingScripts(rootFs IDiskPartition, nics []*types.SServerNic) error {
|
||||
if err := r.sLinuxRootFs.DeployNetworkingScripts(rootFs, nics); err != nil {
|
||||
return err
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/hostman/guestman/desc"
|
||||
deployapi "yunion.io/x/onecloud/pkg/hostman/hostdeployer/apis"
|
||||
"yunion.io/x/onecloud/pkg/hostman/monitor"
|
||||
"yunion.io/x/onecloud/pkg/httperrors"
|
||||
@@ -107,7 +108,6 @@ func (m *SGuestManager) QgaSetNetwork(ctx context.Context, params interface{}) (
|
||||
Gateway: input.Gateway,
|
||||
}
|
||||
|
||||
//func (m *SGuestManager) QgaSetNetwork(netmod *monitor.NetworkModify, sid string, execTimeout int) (string, error) {
|
||||
guest, err := m.checkAndInitGuestQga(input.Sid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -144,3 +144,15 @@ func (m *SGuestManager) QgaGetOsInfo(sid string) (jsonutils.JSONObject, error) {
|
||||
}
|
||||
return jsonutils.Marshal(res), nil
|
||||
}
|
||||
|
||||
func (guest *SKVMGuestInstance) QgaAddNicsConfigure(addNics []*desc.SGuestNetwork) error {
|
||||
if guest.guestAgent == nil {
|
||||
if err := guest.InitQga(); err != nil {
|
||||
return errors.Wrap(err, "init qga")
|
||||
}
|
||||
}
|
||||
if err := guest.guestAgent.GuestPing(1); err != nil {
|
||||
return errors.Wrap(err, "Qga ping")
|
||||
}
|
||||
return guest.guestAgent.QgaDeployNics(deployapi.GuestNicsToServerNics(addNics))
|
||||
}
|
||||
|
||||
@@ -41,12 +41,14 @@ import (
|
||||
hostapi "yunion.io/x/onecloud/pkg/apis/host"
|
||||
"yunion.io/x/onecloud/pkg/appsrv"
|
||||
"yunion.io/x/onecloud/pkg/hostman/container/prober"
|
||||
"yunion.io/x/onecloud/pkg/hostman/container/snapshot_service"
|
||||
"yunion.io/x/onecloud/pkg/hostman/guestman/arch"
|
||||
"yunion.io/x/onecloud/pkg/hostman/guestman/desc"
|
||||
fwd "yunion.io/x/onecloud/pkg/hostman/guestman/forwarder"
|
||||
fwdpb "yunion.io/x/onecloud/pkg/hostman/guestman/forwarder/api"
|
||||
"yunion.io/x/onecloud/pkg/hostman/guestman/pod/pleg"
|
||||
"yunion.io/x/onecloud/pkg/hostman/guestman/pod/runtime"
|
||||
"yunion.io/x/onecloud/pkg/hostman/guestman/pod/statusman"
|
||||
"yunion.io/x/onecloud/pkg/hostman/guestman/types"
|
||||
deployapi "yunion.io/x/onecloud/pkg/hostman/hostdeployer/apis"
|
||||
"yunion.io/x/onecloud/pkg/hostman/hostinfo/hostconsts"
|
||||
@@ -144,6 +146,7 @@ func NewGuestManager(host hostutils.IHost, serversPath string, workerCnt int) (*
|
||||
return nil, errors.Wrap(err, "mkdir qemu log dir")
|
||||
}
|
||||
if manager.host.IsContainerHost() {
|
||||
statusman.GetManager().Start()
|
||||
manager.startContainerProbeManager()
|
||||
runtimeMan, err := runtime.NewRuntimeManager(manager.GetCRI())
|
||||
if err != nil {
|
||||
@@ -153,10 +156,32 @@ func NewGuestManager(host hostutils.IHost, serversPath string, workerCnt int) (*
|
||||
manager.containerRuntimeManager = runtimeMan
|
||||
manager.pleg = pleg.NewGenericPLEG(runtimeMan, pleg.ChannelCapacity, pleg.RelistPeriod, manager.podCache, clock.RealClock{})
|
||||
manager.pleg.Start()
|
||||
go func() {
|
||||
if err := manager.startContainerdSnapshotService(); err != nil {
|
||||
log.Fatalf("start containerd snapshot service: %s", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
return manager, nil
|
||||
}
|
||||
|
||||
func (h *SGuestManager) startContainerdSnapshotService() error {
|
||||
root := filepath.Join(options.HostOptions.ServersPath, "containerd_snapshots")
|
||||
err := snapshot_service.StartService(h, root)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "new snapshot service")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *SGuestManager) GetContainerManager(serverId string) (snapshot_service.ISnapshotContainerManager, error) {
|
||||
pod, ok := h.GetServer(serverId)
|
||||
if !ok {
|
||||
return nil, errors.Wrapf(httperrors.ErrNotFound, "server %s not found", serverId)
|
||||
}
|
||||
return pod.(snapshot_service.ISnapshotContainerManager), nil
|
||||
}
|
||||
|
||||
func (m *SGuestManager) startContainerSyncLoop() {
|
||||
if m.host.IsContainerHost() {
|
||||
go func() {
|
||||
@@ -1072,7 +1097,8 @@ func (m *SGuestManager) GuestSync(ctx context.Context, params interface{}) (json
|
||||
}
|
||||
|
||||
fwOnly := jsonutils.QueryBoolean(syncParams.Body, "fw_only", false)
|
||||
return guest.SyncConfig(ctx, guestDesc, fwOnly)
|
||||
setUefiBootOrder := jsonutils.QueryBoolean(syncParams.Body, "set_uefi_boot_order", false)
|
||||
return guest.SyncConfig(ctx, guestDesc, fwOnly, setUefiBootOrder)
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
@@ -1782,8 +1808,8 @@ func (m *SGuestManager) GetGuestTrafficRecord(sid string) (map[string]compute.SN
|
||||
func (m *SGuestManager) UploadGuestsStatus(ctx context.Context, i interface{}) (jsonutils.JSONObject, error) {
|
||||
input := i.(*compute.HostUploadGuestsStatusRequest)
|
||||
errs := []error{}
|
||||
resp := &compute.HostUploadGuestsStatusResponse{
|
||||
Guests: make(map[string]*compute.HostUploadGuestStatusResponse, 0),
|
||||
resp := &compute.HostUploadGuestsStatusInput{
|
||||
Guests: make(map[string]*compute.HostUploadGuestStatusInput, 0),
|
||||
}
|
||||
reason := "upload guest status by host"
|
||||
for _, id := range input.GuestIds {
|
||||
@@ -1813,10 +1839,10 @@ func (m *SGuestManager) UploadGuestsStatus(ctx context.Context, i interface{}) (
|
||||
return ret, err
|
||||
}
|
||||
|
||||
func (m *SGuestManager) ProbeGuestInitStatus(sid string) *compute.HostUploadGuestStatusResponse {
|
||||
func (m *SGuestManager) ProbeGuestInitStatus(sid string) *compute.HostUploadGuestStatusInput {
|
||||
guest, _ := m.GetServer(sid)
|
||||
status := m.getStatus(sid)
|
||||
resp := &compute.HostUploadGuestStatusResponse{
|
||||
resp := &compute.HostUploadGuestStatusInput{
|
||||
PerformStatusInput: apis.PerformStatusInput{
|
||||
Status: status,
|
||||
BlockJobsCount: -1,
|
||||
|
||||
@@ -615,11 +615,34 @@ type SGuestNetworkSyncTask struct {
|
||||
addNics []*desc.SGuestNetwork
|
||||
errors []error
|
||||
|
||||
addNicMacs []string
|
||||
addNicConfs []*monitor.NetworkModify
|
||||
|
||||
callback func(...error)
|
||||
}
|
||||
|
||||
func (n *SGuestNetworkSyncTask) Start(callback func(...error)) {
|
||||
n.callback = callback
|
||||
if len(n.addNics) > 0 {
|
||||
nics := make([]*desc.SGuestNetwork, 0)
|
||||
nics = append(nics, n.guest.Desc.Nics...)
|
||||
nics = append(nics, n.addNics...)
|
||||
if err := n.guest.QgaAddNicsConfigure(nics); err != nil {
|
||||
log.Errorf("QgaAddNicsConfigure failed %s", err)
|
||||
} else {
|
||||
addNicMacs := make([]string, 0)
|
||||
addNicConfs := make([]*monitor.NetworkModify, 0)
|
||||
for i := range n.addNics {
|
||||
addNicMacs = append(addNicMacs, n.addNics[i].Mac)
|
||||
addNicConfs = append(addNicConfs, &monitor.NetworkModify{
|
||||
Ipmask: fmt.Sprintf("%s/%d", n.addNics[i].Ip, n.addNics[i].Masklen),
|
||||
Gateway: n.addNics[i].Gateway,
|
||||
})
|
||||
}
|
||||
n.addNicMacs = addNicMacs
|
||||
n.addNicConfs = addNicConfs
|
||||
}
|
||||
}
|
||||
n.syncNetworkConf()
|
||||
}
|
||||
|
||||
@@ -633,10 +656,59 @@ func (n *SGuestNetworkSyncTask) syncNetworkConf() {
|
||||
n.addNics = n.addNics[:len(n.addNics)-1]
|
||||
n.addNic(nic)
|
||||
} else {
|
||||
if len(n.addNicMacs) > 0 {
|
||||
// try restart added nics, wait for added nic ready
|
||||
time.Sleep(3 * time.Second)
|
||||
if err := n.qgaRestartAddedNics(); err != nil {
|
||||
log.Errorf("failed qgaRestartAddedNics")
|
||||
}
|
||||
}
|
||||
|
||||
n.callback(n.errors...)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *SGuestNetworkSyncTask) qgaRestartAddedNics() error {
|
||||
err := n.qgaGetAddedNicDevs()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for i := range n.addNicConfs {
|
||||
if n.addNicConfs[i].Device != "" {
|
||||
err = n.guest.guestAgent.QgaRestartNetwork(n.addNicConfs[i])
|
||||
if err != nil {
|
||||
log.Errorf("Failed QgaRestartNetwork %s %s", n.addNicConfs[i].Device, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *SGuestNetworkSyncTask) qgaGetAddedNicDevs() error {
|
||||
data, err := n.guest.guestAgent.QgaGetNetwork()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "QgaGetNetwork")
|
||||
}
|
||||
var parsedData []api.IfnameDetail
|
||||
ifnames, err := jsonutils.Parse(data)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "parse qga network output %s", data)
|
||||
}
|
||||
err = ifnames.Unmarshal(&parsedData)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unmarshal ifnames")
|
||||
}
|
||||
for i := range n.addNicMacs {
|
||||
for j := range parsedData {
|
||||
if n.addNicMacs[i] == parsedData[j].HardwareAddress {
|
||||
n.addNicConfs[i].Device = parsedData[j].Name
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *SGuestNetworkSyncTask) removeNic(nic *desc.SGuestNetwork) {
|
||||
callback := func(res string) {
|
||||
if len(res) > 0 && !strings.Contains(res, "not found") {
|
||||
@@ -794,7 +866,7 @@ func (n *SGuestNetworkSyncTask) onDeviceAdd(nic *desc.SGuestNetwork) {
|
||||
func NewGuestNetworkSyncTask(
|
||||
guest *SKVMGuestInstance, delNics, addNics []*desc.SGuestNetwork,
|
||||
) *SGuestNetworkSyncTask {
|
||||
return &SGuestNetworkSyncTask{guest, delNics, addNics, make([]error, 0), nil}
|
||||
return &SGuestNetworkSyncTask{guest, delNics, addNics, make([]error, 0), nil, nil, nil}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -44,12 +44,14 @@ import (
|
||||
"yunion.io/x/onecloud/pkg/hostman/container/lifecycle"
|
||||
"yunion.io/x/onecloud/pkg/hostman/container/prober"
|
||||
proberesults "yunion.io/x/onecloud/pkg/hostman/container/prober/results"
|
||||
"yunion.io/x/onecloud/pkg/hostman/container/snapshot_service"
|
||||
"yunion.io/x/onecloud/pkg/hostman/container/status"
|
||||
"yunion.io/x/onecloud/pkg/hostman/container/volume_mount"
|
||||
"yunion.io/x/onecloud/pkg/hostman/container/volume_mount/disk"
|
||||
_ "yunion.io/x/onecloud/pkg/hostman/container/volume_mount/disk"
|
||||
"yunion.io/x/onecloud/pkg/hostman/guestman/desc"
|
||||
"yunion.io/x/onecloud/pkg/hostman/guestman/pod/runtime"
|
||||
"yunion.io/x/onecloud/pkg/hostman/guestman/pod/statusman"
|
||||
deployapi "yunion.io/x/onecloud/pkg/hostman/hostdeployer/apis"
|
||||
"yunion.io/x/onecloud/pkg/hostman/hostinfo"
|
||||
"yunion.io/x/onecloud/pkg/hostman/hostutils"
|
||||
@@ -189,7 +191,7 @@ func (h startStatHelper) removeStatFile(fp string) error {
|
||||
if !fileutils2.Exists(fp) {
|
||||
return nil
|
||||
}
|
||||
if err := os.Remove(fp); err != nil {
|
||||
if err := os.Remove(fp); err != nil && !strings.Contains(err.Error(), "no such file or directory") {
|
||||
return errors.Wrapf(err, "remove file %s", fp)
|
||||
}
|
||||
return nil
|
||||
@@ -345,13 +347,13 @@ func (s *sPodGuestInstance) getStatus(ctx context.Context, defaultStatus string)
|
||||
continue
|
||||
}
|
||||
if cs != nil {
|
||||
status = GetPodStatusByContainerStatus(status, cStatus)
|
||||
status = GetPodStatusByContainerStatus(status, cStatus, s.IsPrimaryContainer(c.Id))
|
||||
}
|
||||
}
|
||||
return status
|
||||
}
|
||||
|
||||
func (s *sPodGuestInstance) GetUploadStatus(ctx context.Context, reason string) (*computeapi.HostUploadGuestStatusResponse, error) {
|
||||
func (s *sPodGuestInstance) GetUploadStatus(ctx context.Context, reason string) (*computeapi.HostUploadGuestStatusInput, error) {
|
||||
// sync pod status
|
||||
var status = computeapi.VM_READY
|
||||
if s.IsRunning() {
|
||||
@@ -361,12 +363,12 @@ func (s *sPodGuestInstance) GetUploadStatus(ctx context.Context, reason string)
|
||||
if err := s.expectedStatus.SetStatus(status); err != nil {
|
||||
log.Warningf("set expected status to %s, reason: %s, err: %s", status, reason, err.Error())
|
||||
}
|
||||
if status == computeapi.VM_READY {
|
||||
/*if status == computeapi.VM_READY {
|
||||
// remove pod
|
||||
if err := s.stopPod(ctx, 5); err != nil {
|
||||
log.Warningf("stop cri pod when sync status: %s: %v", s.Id, err)
|
||||
}
|
||||
}
|
||||
}*/
|
||||
// sync container's status
|
||||
cStatuss := make(map[string]*computeapi.ContainerPerformStatusInput)
|
||||
for _, c := range s.containers {
|
||||
@@ -408,7 +410,7 @@ func (s *sPodGuestInstance) GetUploadStatus(ctx context.Context, reason string)
|
||||
}
|
||||
}
|
||||
cStatuss[c.Id] = ctrStatusInput
|
||||
status = GetPodStatusByContainerStatus(status, cStatus)
|
||||
status = GetPodStatusByContainerStatus(status, cStatus, s.IsPrimaryContainer(c.Id))
|
||||
}
|
||||
if len(errs) > 0 {
|
||||
log.Errorf("get upload status error: %v", errors.NewAggregate(errs))
|
||||
@@ -421,14 +423,14 @@ func (s *sPodGuestInstance) GetUploadStatus(ctx context.Context, reason string)
|
||||
HostId: hostinfo.Instance().HostId,
|
||||
}
|
||||
|
||||
return &computeapi.HostUploadGuestStatusResponse{
|
||||
return &computeapi.HostUploadGuestStatusInput{
|
||||
PerformStatusInput: *statusInput,
|
||||
Containers: cStatuss,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *sPodGuestInstance) UploadStatus(ctx context.Context, reason string) error {
|
||||
resp, err := s.GetUploadStatus(ctx, reason)
|
||||
/*resp, err := s.GetUploadStatus(ctx, reason)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "get upload status of pod: %s", reason)
|
||||
}
|
||||
@@ -444,11 +446,35 @@ func (s *sPodGuestInstance) UploadStatus(ctx context.Context, reason string) err
|
||||
|
||||
if _, err := hostutils.UpdateServerStatus(ctx, s.Id, &resp.PerformStatusInput); err != nil {
|
||||
errs = append(errs, errors.Wrapf(err, "failed update guest status"))
|
||||
}*/
|
||||
// return errors.NewAggregate(errs)
|
||||
|
||||
resp, err := s.GetUploadStatus(ctx, reason)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "get upload status of pod: %s", reason)
|
||||
}
|
||||
return errors.NewAggregate(errs)
|
||||
containerStatuses := make(map[string]*statusman.ContainerStatus)
|
||||
for ctrId, cStatus := range resp.Containers {
|
||||
containerStatuses[ctrId] = &statusman.ContainerStatus{
|
||||
Status: cStatus.Status,
|
||||
RestartCount: cStatus.RestartCount,
|
||||
StartedAt: cStatus.StartedAt,
|
||||
LastFinishedAt: cStatus.LastFinishedAt,
|
||||
}
|
||||
}
|
||||
if err := statusman.GetManager().UpdateStatus(&statusman.PodStatusUpdateRequest{
|
||||
Id: s.Id,
|
||||
Pod: s,
|
||||
Status: resp.Status,
|
||||
ContainerStatuses: containerStatuses,
|
||||
Reason: reason,
|
||||
}); err != nil {
|
||||
return errors.Wrapf(err, "update status of pod: %s", reason)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *sPodGuestInstance) PostUploadStatus(resp *computeapi.HostUploadGuestStatusResponse, reason string) {
|
||||
func (s *sPodGuestInstance) PostUploadStatus(resp *computeapi.HostUploadGuestStatusInput, reason string) {
|
||||
for ctrId, cStatus := range resp.Containers {
|
||||
s.markContainerProbeDirty(cStatus.Status, ctrId, reason)
|
||||
}
|
||||
@@ -534,11 +560,11 @@ func (s *sPodGuestInstance) IsContainerRunning(ctx context.Context, ctrId string
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (s *sPodGuestInstance) probeGuestStatus(ctx context.Context, resp *computeapi.HostUploadGuestStatusResponse) {
|
||||
func (s *sPodGuestInstance) probeGuestStatus(ctx context.Context, resp *computeapi.HostUploadGuestStatusInput) {
|
||||
resp.Status = s.getStatus(ctx, resp.Status)
|
||||
}
|
||||
|
||||
func (s *sPodGuestInstance) HandleGuestStatus(ctx context.Context, resp *computeapi.HostUploadGuestStatusResponse) (jsonutils.JSONObject, error) {
|
||||
func (s *sPodGuestInstance) HandleGuestStatus(ctx context.Context, resp *computeapi.HostUploadGuestStatusInput) (jsonutils.JSONObject, error) {
|
||||
s.probeGuestStatus(ctx, resp)
|
||||
hostutils.TaskComplete(ctx, jsonutils.Marshal(resp))
|
||||
return nil, nil
|
||||
@@ -602,7 +628,68 @@ func (s *sPodGuestInstance) GetDisks() []*desc.SGuestDisk {
|
||||
return s.GetDesc().Disks
|
||||
}
|
||||
|
||||
func (s *sPodGuestInstance) ConvertRootFsToVolumeMount(rootFs *hostapi.ContainerRootfs) *hostapi.ContainerVolumeMount {
|
||||
return &hostapi.ContainerVolumeMount{
|
||||
Type: rootFs.Type,
|
||||
Disk: rootFs.Disk,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *sPodGuestInstance) mountRootFs(ctrId string, rootFs *hostapi.ContainerRootfs) error {
|
||||
drv := volume_mount.GetDriver(rootFs.Type)
|
||||
vol := &hostapi.ContainerVolumeMount{
|
||||
Type: rootFs.Type,
|
||||
Disk: rootFs.Disk,
|
||||
}
|
||||
if err := drv.Mount(s, ctrId, vol); err != nil {
|
||||
return errors.Wrapf(err, "mount root fs %s, ctrId %s", jsonutils.Marshal(rootFs), ctrId)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *sPodGuestInstance) umountRootFs(ctrId string, rootFs *hostapi.ContainerRootfs) error {
|
||||
drv := volume_mount.GetDriver(rootFs.Type)
|
||||
vol := &hostapi.ContainerVolumeMount{
|
||||
Type: rootFs.Type,
|
||||
Disk: rootFs.Disk,
|
||||
}
|
||||
if err := drv.Unmount(s, ctrId, vol); err != nil {
|
||||
return errors.Wrapf(err, "unmount root fs %s, ctrId %s", jsonutils.Marshal(rootFs), ctrId)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *sPodGuestInstance) getRootFsMountPath(ctrId string) (string, error) {
|
||||
ctr := s.GetContainerById(ctrId)
|
||||
if ctr == nil {
|
||||
return "", errors.Wrapf(httperrors.ErrNotFound, "not found container %s", ctrId)
|
||||
}
|
||||
rootFs := ctr.Spec.Rootfs
|
||||
if rootFs == nil {
|
||||
return "", errors.Wrapf(httperrors.ErrNotFound, "not found root fs %s", ctrId)
|
||||
}
|
||||
vol := s.ConvertRootFsToVolumeMount(rootFs)
|
||||
drv := volume_mount.GetDriver(vol.Type)
|
||||
hostPath, err := drv.GetRuntimeMountHostPath(s, ctrId, vol)
|
||||
if err != nil {
|
||||
return "", errors.Wrapf(err, "get runtime mount host path %s, ctrId %s", jsonutils.Marshal(vol), ctrId)
|
||||
}
|
||||
return hostPath, nil
|
||||
}
|
||||
|
||||
func (s *sPodGuestInstance) GetRootFsMountPath(ctx context.Context, ctrId string) (string, error) {
|
||||
return s.getRootFsMountPath(ctrId)
|
||||
}
|
||||
|
||||
func (s *sPodGuestInstance) mountPodVolumes() error {
|
||||
for _, ctr := range s.GetDesc().Containers {
|
||||
if ctr.Spec.Rootfs == nil {
|
||||
continue
|
||||
}
|
||||
if err := s.mountRootFs(ctr.Id, ctr.Spec.Rootfs); err != nil {
|
||||
return errors.Wrapf(err, "mount root fs %s, ctrId %s", jsonutils.Marshal(ctr.Spec.Rootfs), ctr.Id)
|
||||
}
|
||||
}
|
||||
for ctrId, vols := range s.getContainerVolumeMounts() {
|
||||
for _, vol := range vols {
|
||||
drv := volume_mount.GetDriver(vol.Type)
|
||||
@@ -621,6 +708,14 @@ func (s *sPodGuestInstance) mountPodVolumes() error {
|
||||
}
|
||||
|
||||
func (s *sPodGuestInstance) umountPodVolumes() error {
|
||||
for _, ctr := range s.GetDesc().Containers {
|
||||
if ctr.Spec.Rootfs == nil {
|
||||
continue
|
||||
}
|
||||
if err := s.umountRootFs(ctr.Id, ctr.Spec.Rootfs); err != nil {
|
||||
return errors.Wrapf(err, "umount root fs %s, ctrId %s", jsonutils.Marshal(ctr.Spec.Rootfs), ctr.Id)
|
||||
}
|
||||
}
|
||||
for ctrId, vols := range s.getContainerVolumeMounts() {
|
||||
for _, vol := range vols {
|
||||
if err := volume_mount.GetDriver(vol.Type).Unmount(s, ctrId, vol); err != nil {
|
||||
@@ -771,14 +866,20 @@ func newLocalDirtyPodStartTask(ctx context.Context, userCred mcclient.TokenCrede
|
||||
}
|
||||
|
||||
func (t *localDirtyPodStartTask) Run() {
|
||||
if t.pod.isPodDirtyShutdown() {
|
||||
/*if t.pod.isPodDirtyShutdown() {
|
||||
log.Infof("start dirty pod locally (%s/%s)", t.pod.Id, t.pod.GetName())
|
||||
if _, err := t.pod.startPod(t.ctx, t.userCred); err != nil {
|
||||
log.Errorf("start dirty pod(%s/%s) err: %s", t.pod.GetId(), t.pod.GetName(), err.Error())
|
||||
}
|
||||
}
|
||||
}*/
|
||||
for _, ctr := range t.pod.GetContainers() {
|
||||
if t.pod.isContainerDirtyShutdown(ctr.Id) {
|
||||
if !t.pod.IsRunning() {
|
||||
log.Infof("start dirty pod locally (%s/%s)", t.pod.Id, t.pod.GetName())
|
||||
if _, err := t.pod.startPod(t.ctx, t.userCred); err != nil {
|
||||
log.Errorf("start dirty pod(%s/%s) err: %s", t.pod.GetId(), t.pod.GetName(), err.Error())
|
||||
}
|
||||
}
|
||||
log.Infof("start dirty container locally (%s/%s/%s/%s)", t.pod.Id, t.pod.GetName(), ctr.Id, ctr.Name)
|
||||
if _, err := t.pod.StartLocalContainer(t.ctx, t.userCred, ctr.Id); err != nil {
|
||||
log.Errorf("start dirty container %s err: %s", ctr.Id, err.Error())
|
||||
@@ -1069,7 +1170,7 @@ func (s *sPodGuestInstance) PostLoad(m *SGuestManager) error {
|
||||
return LoadGuestCpuset(m, s)
|
||||
}
|
||||
|
||||
func (s *sPodGuestInstance) SyncConfig(ctx context.Context, guestDesc *desc.SGuestDesc, fwOnly bool) (jsonutils.JSONObject, error) {
|
||||
func (s *sPodGuestInstance) SyncConfig(ctx context.Context, guestDesc *desc.SGuestDesc, fwOnly, setUefiBootOrder bool) (jsonutils.JSONObject, error) {
|
||||
if err := SaveDesc(s, guestDesc); err != nil {
|
||||
return nil, errors.Wrap(err, "SaveDesc")
|
||||
}
|
||||
@@ -1739,6 +1840,10 @@ func (s *sPodGuestInstance) createContainer(ctx context.Context, userCred mcclie
|
||||
ctrCfg.Linux.SecurityContext.NamespaceOptions.Pid = runtimeapi.NamespaceMode_TARGET
|
||||
ctrCfg.Linux.SecurityContext.NamespaceOptions.TargetId = s.GetCRIId()
|
||||
}*/
|
||||
if spec.Rootfs != nil {
|
||||
ctrCfg.Labels[snapshot_service.LabelServerId] = s.GetId()
|
||||
ctrCfg.Labels[snapshot_service.LabelContainerId] = ctrId
|
||||
}
|
||||
|
||||
// inherit security context
|
||||
if spec.SecurityContext != nil {
|
||||
@@ -2075,6 +2180,10 @@ func (s *sPodGuestInstance) getContainerStatus(ctx context.Context, ctrId string
|
||||
return status, cs, nil
|
||||
}
|
||||
|
||||
func (s *sPodGuestInstance) MarkContainerProbeDirty(ctrStatus string, ctrId string, reason string) {
|
||||
s.markContainerProbeDirty(ctrStatus, ctrId, reason)
|
||||
}
|
||||
|
||||
func (s *sPodGuestInstance) markContainerProbeDirty(status, ctrId string, reason string) {
|
||||
if status == computeapi.CONTAINER_STATUS_PROBING {
|
||||
reason = fmt.Sprintf("status is probing: %s", reason)
|
||||
@@ -2203,6 +2312,9 @@ func (s *sPodGuestInstance) tarGzDir(input *hostapi.ContainerSaveVolumeMountToIm
|
||||
dirPath = strings.Join(input.VolumeMountDirs, " ")
|
||||
}
|
||||
cmd := fmt.Sprintf("tar -czf %s -C %s %s", outputFp, hostPath, dirPath)
|
||||
if input.VolumeMountPrefix != "" {
|
||||
cmd += fmt.Sprintf(" --transform 's,^,%s/,'", input.VolumeMountPrefix)
|
||||
}
|
||||
if out, err := procutils.NewRemoteCommandAsFarAsPossible("sh", "-c", cmd).Output(); err != nil {
|
||||
return "", errors.Wrapf(err, "%s: %s", cmd, out)
|
||||
}
|
||||
@@ -2460,7 +2572,7 @@ func (s *sPodGuestInstance) tarHostDir(srcDir, targetPath string,
|
||||
if len(includeFiles) > 0 {
|
||||
includeStr = strings.Join(includeFiles, " ")
|
||||
}
|
||||
cmd := fmt.Sprintf("%s --warning=no-file-changed --ignore-failed-read -cf %s -C %s %s", baseCmd, targetPath, srcDir, includeStr)
|
||||
cmd := fmt.Sprintf("%s --ignore-failed-read -cf %s -C %s %s", baseCmd, targetPath, srcDir, includeStr)
|
||||
log.Infof("[%s] tar cmd: %s", s.GetName(), cmd)
|
||||
if out, err := procutils.NewRemoteCommandAsFarAsPossible("sh", "-c", cmd).Output(); err != nil {
|
||||
outErr := errors.Wrapf(err, "%s: %s", cmd, out)
|
||||
|
||||
1
pkg/hostman/guestman/pod/statusman/doc.go
Normal file
1
pkg/hostman/guestman/pod/statusman/doc.go
Normal file
@@ -0,0 +1 @@
|
||||
package statusman // import "yunion.io/x/onecloud/pkg/hostman/guestman/pod/statusman"
|
||||
157
pkg/hostman/guestman/pod/statusman/pod_state.go
Normal file
157
pkg/hostman/guestman/pod/statusman/pod_state.go
Normal file
@@ -0,0 +1,157 @@
|
||||
package statusman
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/apis"
|
||||
computeapi "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
"yunion.io/x/onecloud/pkg/hostman/hostutils"
|
||||
)
|
||||
|
||||
var (
|
||||
statusManager IPodStatusManager
|
||||
)
|
||||
|
||||
func init() {
|
||||
statusManager = newPodStatusManager()
|
||||
}
|
||||
|
||||
func GetManager() IPodStatusManager {
|
||||
return statusManager
|
||||
}
|
||||
|
||||
type IPodStatusManager interface {
|
||||
UpdateStatus(req *PodStatusUpdateRequest) error
|
||||
Start()
|
||||
Stop()
|
||||
}
|
||||
|
||||
type ContainerStatus struct {
|
||||
Status string
|
||||
RestartCount int
|
||||
StartedAt *time.Time
|
||||
LastFinishedAt *time.Time
|
||||
}
|
||||
|
||||
type IPod interface {
|
||||
MarkContainerProbeDirty(ctrStatus string, ctrId string, reason string)
|
||||
}
|
||||
|
||||
type PodStatusUpdateRequest struct {
|
||||
Id string
|
||||
Pod IPod
|
||||
Status string
|
||||
ContainerStatuses map[string]*ContainerStatus
|
||||
Reason string
|
||||
Result chan error `json:"-"`
|
||||
}
|
||||
|
||||
func (r PodStatusUpdateRequest) ToServerPerformStatusInput() *computeapi.ServerPerformStatusInput {
|
||||
powerState := computeapi.VM_POWER_STATES_OFF
|
||||
if r.Status == computeapi.VM_RUNNING {
|
||||
powerState = computeapi.VM_POWER_STATES_ON
|
||||
}
|
||||
guestStatus := &computeapi.ServerPerformStatusInput{
|
||||
PerformStatusInput: apis.PerformStatusInput{
|
||||
Status: r.Status,
|
||||
PowerStates: powerState,
|
||||
Reason: r.Reason,
|
||||
},
|
||||
Containers: make(map[string]*computeapi.ContainerPerformStatusInput),
|
||||
}
|
||||
for ctrId, ctrStatus := range r.ContainerStatuses {
|
||||
guestStatus.Containers[ctrId] = &computeapi.ContainerPerformStatusInput{
|
||||
PerformStatusInput: apis.PerformStatusInput{
|
||||
Status: ctrStatus.Status,
|
||||
Reason: r.Reason,
|
||||
},
|
||||
RestartCount: ctrStatus.RestartCount,
|
||||
StartedAt: ctrStatus.StartedAt,
|
||||
LastFinishedAt: ctrStatus.LastFinishedAt,
|
||||
}
|
||||
}
|
||||
|
||||
return guestStatus
|
||||
}
|
||||
|
||||
func (r PodStatusUpdateRequest) ToHostUploadGuestsStatusInput() *computeapi.HostUploadGuestsStatusInput {
|
||||
id := r.Id
|
||||
guestStatus := &computeapi.HostUploadGuestStatusInput{
|
||||
PerformStatusInput: apis.PerformStatusInput{
|
||||
Status: r.Status,
|
||||
Reason: r.Reason,
|
||||
},
|
||||
Containers: make(map[string]*computeapi.ContainerPerformStatusInput),
|
||||
}
|
||||
for ctrId, ctrStatus := range r.ContainerStatuses {
|
||||
guestStatus.Containers[ctrId] = &computeapi.ContainerPerformStatusInput{
|
||||
PerformStatusInput: apis.PerformStatusInput{
|
||||
Status: ctrStatus.Status,
|
||||
Reason: r.Reason,
|
||||
},
|
||||
RestartCount: ctrStatus.RestartCount,
|
||||
StartedAt: ctrStatus.StartedAt,
|
||||
LastFinishedAt: ctrStatus.LastFinishedAt,
|
||||
}
|
||||
}
|
||||
|
||||
return &computeapi.HostUploadGuestsStatusInput{
|
||||
Guests: map[string]*computeapi.HostUploadGuestStatusInput{
|
||||
id: guestStatus,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type podStatusManager struct {
|
||||
updateChan chan *PodStatusUpdateRequest
|
||||
stopChan chan struct{}
|
||||
}
|
||||
|
||||
func newPodStatusManager() IPodStatusManager {
|
||||
return &podStatusManager{
|
||||
updateChan: make(chan *PodStatusUpdateRequest),
|
||||
stopChan: make(chan struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
func (m *podStatusManager) Start() {
|
||||
go m.processLoop()
|
||||
}
|
||||
|
||||
func (m *podStatusManager) Stop() {
|
||||
close(m.stopChan)
|
||||
}
|
||||
|
||||
func (m *podStatusManager) UpdateStatus(req *PodStatusUpdateRequest) error {
|
||||
result := make(chan error, 1)
|
||||
req.Result = result
|
||||
m.updateChan <- req
|
||||
return <-result
|
||||
}
|
||||
|
||||
func (m *podStatusManager) processLoop() {
|
||||
for {
|
||||
select {
|
||||
case <-m.stopChan:
|
||||
return
|
||||
case req := <-m.updateChan:
|
||||
err := m.handleUpdate(req)
|
||||
req.Result <- err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *podStatusManager) handleUpdate(req *PodStatusUpdateRequest) error {
|
||||
input := req.ToServerPerformStatusInput()
|
||||
if _, err := hostutils.UpdateServerContainersStatus(context.Background(), req.Id, input); err != nil {
|
||||
return errors.Wrapf(err, "update server containers status")
|
||||
}
|
||||
for ctrId, ctrStatus := range input.Containers {
|
||||
// 同步容器状态可能会出现 probing 状态,所以需要 mark 成 dirty,等待 probe manager 重新探测容器状态
|
||||
req.Pod.MarkContainerProbeDirty(ctrStatus.Status, ctrId, input.Reason)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -232,12 +232,15 @@ func (t *localPodRestartTask) Dump() string {
|
||||
return fmt.Sprintf("pod restart task %s/%s", t.pod.GetId(), t.pod.GetName())
|
||||
}
|
||||
|
||||
func GetPodStatusByContainerStatus(status string, cStatus string) string {
|
||||
func GetPodStatusByContainerStatus(status string, cStatus string, isPrimary bool) string {
|
||||
if cStatus == computeapi.CONTAINER_STATUS_CRASH_LOOP_BACK_OFF {
|
||||
status = computeapi.POD_STATUS_CRASH_LOOP_BACK_OFF
|
||||
}
|
||||
if cStatus == computeapi.CONTAINER_STATUS_EXITED && status != computeapi.VM_READY {
|
||||
status = computeapi.POD_STATUS_CONTAINER_EXITED
|
||||
if isPrimary {
|
||||
status = computeapi.VM_READY
|
||||
}
|
||||
}
|
||||
return status
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import (
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/errors"
|
||||
"yunion.io/x/pkg/util/sets"
|
||||
|
||||
computeapi "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
hostapi "yunion.io/x/onecloud/pkg/apis/host"
|
||||
@@ -130,6 +131,10 @@ func (m *SGuestManager) startContainer(obj *sPodGuestInstance, ctr *hostapi.Cont
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *SGuestManager) GetPleg() pleg.PodLifecycleEventGenerator {
|
||||
return m.pleg
|
||||
}
|
||||
|
||||
func (m *SGuestManager) syncContainerLoop(plegCh chan *pleg.PodLifecycleEvent) {
|
||||
log.Infof("start sync container loop")
|
||||
for {
|
||||
@@ -145,7 +150,7 @@ func (m *SGuestManager) syncContainerLoopIteration(plegCh chan *pleg.PodLifecycl
|
||||
log.Warningf("can not find pod manager by %s", jsonutils.Marshal(e))
|
||||
return
|
||||
}
|
||||
if podMan.(*sPodGuestInstance).isPodDirtyShutdown() {
|
||||
if podMan.(*sPodGuestInstance).IsDirtyShutdown() {
|
||||
log.Infof("pod %s is dirty shutdown, waiting it to started", podMan.GetName())
|
||||
return
|
||||
}
|
||||
@@ -181,7 +186,7 @@ func (m *SGuestManager) syncContainerLoopIteration(plegCh chan *pleg.PodLifecycl
|
||||
if ctrObj != nil {
|
||||
ccStatus, _, _ = podMan.GetContainerStatus(ctx, ctrObj.Id)
|
||||
}
|
||||
if !isInternalStopped || ccStatus == computeapi.CONTAINER_STATUS_EXITED {
|
||||
if !isInternalStopped && sets.NewString(computeapi.CONTAINER_STATUS_EXITED, computeapi.CONTAINER_STATUS_CRASH_LOOP_BACK_OFF).Has(ccStatus) {
|
||||
podStatus, err := m.podCache.Get(e.Id)
|
||||
if err != nil {
|
||||
log.Errorf("get pod %s status error: %v", e.Id, err)
|
||||
@@ -208,7 +213,7 @@ func (m *SGuestManager) syncContainerLoopIteration(plegCh chan *pleg.PodLifecycl
|
||||
}
|
||||
log.Infof("sync pod %s container %s status: %s", e.Id, ctrCriId, reason)
|
||||
// 如果是 primary container 退出,就退出其他容器
|
||||
if ctrObj != nil && podMan.IsPrimaryContainer(ctrObj.Id) && ccStatus == computeapi.CONTAINER_STATUS_EXITED {
|
||||
if ctrObj != nil && !isInternalStopped && podMan.IsPrimaryContainer(ctrObj.Id) && ccStatus == computeapi.CONTAINER_STATUS_EXITED {
|
||||
reason = fmt.Sprintf("stop all containers when primary container %s exited", ctrObj.Name)
|
||||
if err := podMan.StopAll(context.Background()); err != nil {
|
||||
log.Errorf("stop all pod containers error: %s", err.Error())
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user