Compare commits

...

21 Commits

Author SHA1 Message Date
Zexi Li
97acf6086c Automated cherry pick of #22729: Monitor worker alert (#22731)
* fix(monitor): GetMetricMeasurement 接口只查询过去30m的数据

避免数据过多导致 victoria-metrics 报错

* fix(monitor): wildchar of alert group by field
2025-06-18 14:25:53 +08:00
Zexi Li
78abadcc7b fix: panic when there is no secondary IP on the host. (#22727)
Co-authored-by: glzjin <glzjin2015@gmail.com>
2025-06-17 11:15:11 +08:00
wanyaoqi
e748d8e94a fix(region,host): add auto merge snapshots options, preallocation options (#22714) 2025-06-13 15:19:59 +08:00
Zexi Li
b401b032bb fix(host): dirty shutdown pod is not auto started (#22704) 2025-06-10 10:18:22 +08:00
Jian Qiu
6607ffc3f1 fix: remove cgo deps for ioctl (#22702)
Co-authored-by: Qiu Jian <qiujian@yunionyun.com>
2025-06-07 08:42:25 +08:00
Jian Qiu
2fe1d0e788 fix: http perf stats monitor (#22690)
Co-authored-by: Qiu Jian <qiujian@yunionyun.com>
2025-06-06 18:12:32 +08:00
Zexi Li
044d554d71 fix(host): marshal update status input inside error (#22693) 2025-06-06 17:28:00 +08:00
Jian Qiu
7e0e67daee fix: update vendor release/4.0.0 20250606 (#22686)
Co-authored-by: Qiu Jian <qiujian@yunionyun.com>
2025-06-06 14:23:40 +08:00
wanyaoqi
8779d89e06 fix(host): pass decoded userdata to host-deployer (#22682) 2025-06-05 23:51:03 +08:00
Zexi Li
5c182471c5 fix(host): change mount context timeout to 30s (#22675) 2025-06-05 18:40:22 +08:00
Jian Qiu
1902770c49 fix: cloudmon high cpu loads for bucket probing (#22659)
Co-authored-by: Qiu Jian <qiujian@yunionyun.com>
2025-06-05 17:51:40 +08:00
Zexi Li
11fccaeb51 fix(scheduler): wrong sort order of instance group selection (#22667) 2025-06-04 14:27:36 +08:00
Zexi Li
ea70981aa3 feat(host): containerd snapshot rootfs service (#22660) 2025-06-04 11:00:34 +08:00
Zexi Li
2ab08b0e2a fix(host): sync container crash status (#22656) 2025-06-03 20:16:26 +08:00
Zexi Li
76c9a6841c fix(host): retry stopping container forcibly (#22649) 2025-06-03 17:11:57 +08:00
Zexi Li
8ddf395e62 fix(host): losetup package initialization order (#22653) 2025-06-03 13:39:42 +08:00
Jian Qiu
591de392b7 fix: update vendor to fix keystone user join project not found (#22644)
Co-authored-by: Qiu Jian <qiujian@yunionyun.com>
2025-05-31 18:48:06 +08:00
Jian Qiu
fb0375dab4 fix: disk statu sync recover (#22632)
Co-authored-by: Qiu Jian <qiujian@yunionyun.com>
2025-05-31 09:04:40 +08:00
Jian Qiu
411dd53c12 fix: bucket perform mon random string generation consume high cpu load (#22640)
Co-authored-by: Qiu Jian <qiujian@yunionyun.com>
2025-05-31 09:03:04 +08:00
wanyaoqi
b3a687c380 fix(host): change log level to debug on get numa node faild (#22642) 2025-05-31 09:01:42 +08:00
Zexi Li
48d9270e71 refactor(region,host): container status management (#22636) 2025-05-30 17:48:51 +08:00
698 changed files with 63244 additions and 7829 deletions

View File

@@ -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:

View File

@@ -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))

25
go.mod
View File

@@ -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.20250528153742-2296b9b7287c
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.20250519013345-54017bf6c1f0
yunion.io/x/s3cli v0.0.0-20241221171442-1c11599d28e1
yunion.io/x/sqlchemy v1.1.3-0.20250513031856-ce9f71063b3a
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

58
go.sum
View File

@@ -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,8 +1410,8 @@ sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20250528153742-2296b9b7287c h1:DGnSo1KJS+0dZQTz76vArY+D1dEB8LoINmQP257Miso=
yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20250528153742-2296b9b7287c/go.mod h1:FXxAEbdNfWXX9gjME3K2nJhkydHY5EKEUZb+RLEzVwQ=
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=
@@ -1395,7 +1429,7 @@ yunion.io/x/pkg v1.10.4-0.20250519013345-54017bf6c1f0 h1:iKWkBMKazSijYNhOaSh4qBu
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.20250513031856-ce9f71063b3a h1:mDW1VyYJxZ4ORITZGDWacUiBNyqX6rMObnQk77NvUOg=
yunion.io/x/sqlchemy v1.1.3-0.20250513031856-ce9f71063b3a/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=

View File

@@ -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"`
}

View File

@@ -316,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"

View File

@@ -1424,3 +1424,8 @@ type ServerChangeBillingTypeInput struct {
// required: true
BillingType string `json:"billing_type"`
}
type ServerPerformStatusInput struct {
apis.PerformStatusInput
Containers map[string]*ContainerPerformStatusInput `json:"containers"`
}

View File

@@ -713,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 {

View File

@@ -90,6 +90,7 @@ var (
SERVICE_TYPE_CLOUDEVENT,
SERVICE_TYPE_ANSIBLE,
SERVICE_TYPE_INFLUXDB,
SERVICE_TYPE_VICTORIA_METRICS,
SERVICE_TYPE_APIMAP,
SERVICE_TYPE_LOG,
"autoupdate",
@@ -112,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",
}
)

View File

@@ -346,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"`
}

View File

@@ -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"`
}

View File

@@ -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,6 +63,19 @@ 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",

View File

@@ -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)

View File

@@ -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 {

View 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
}

View 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())
}
}

View File

@@ -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
}

View File

@@ -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 {

View File

@@ -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

View File

@@ -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,
}

View File

@@ -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
}
@@ -6773,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)
}

View File

@@ -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

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View 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"
)

View File

@@ -0,0 +1 @@
package snapshot_service // import "yunion.io/x/onecloud/pkg/hostman/container/snapshot_service"

View 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
}

View File

@@ -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,

View File

@@ -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() {
@@ -1783,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 {
@@ -1814,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,

View File

@@ -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"
@@ -351,7 +353,7 @@ func (s *sPodGuestInstance) getStatus(ctx context.Context, defaultStatus string)
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 {
@@ -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())
@@ -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)

View File

@@ -0,0 +1 @@
package statusman // import "yunion.io/x/onecloud/pkg/hostman/guestman/pod/statusman"

View 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
}

View File

@@ -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"
@@ -149,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
}
@@ -185,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)

View File

@@ -2840,6 +2840,9 @@ func (s *SKVMGuestInstance) allocGuestNumaCpuset() error {
}
func (s *SKVMGuestInstance) GetNeedMergeBackingFileDiskIndexs() []int {
if s.isDisableAutoMergeSnapshots() {
return nil
}
res := make([]int, 0)
for _, disk := range s.Desc.Disks {
if disk.MergeSnapshot {
@@ -3610,7 +3613,7 @@ func (s *SKVMGuestInstance) CPUSetRemove(ctx context.Context) error {
return nil
}
func (s *SKVMGuestInstance) GetUploadStatus(ctx context.Context, reason string) (*api.HostUploadGuestStatusResponse, error) {
func (s *SKVMGuestInstance) GetUploadStatus(ctx context.Context, reason string) (*api.HostUploadGuestStatusInput, error) {
var status = api.VM_READY
if s.IsSuspend() {
status = api.VM_SUSPEND
@@ -3628,15 +3631,15 @@ func (s *SKVMGuestInstance) GetUploadStatus(ctx context.Context, reason string)
statusInput.Status = api.VM_BLOCK_STREAM
}
}
return &api.HostUploadGuestStatusResponse{
return &api.HostUploadGuestStatusInput{
PerformStatusInput: *statusInput,
}, nil
}
func (s *SKVMGuestInstance) PostUploadStatus(resp *api.HostUploadGuestStatusResponse, reason string) {
func (s *SKVMGuestInstance) PostUploadStatus(resp *api.HostUploadGuestStatusInput, reason string) {
}
func (s *SKVMGuestInstance) HandleGuestStatus(ctx context.Context, resp *api.HostUploadGuestStatusResponse) (jsonutils.JSONObject, error) {
func (s *SKVMGuestInstance) HandleGuestStatus(ctx context.Context, resp *api.HostUploadGuestStatusInput) (jsonutils.JSONObject, error) {
if resp.Status == GUEST_RUNNING && s.pciUninitialized {
resp.Status = api.VM_UNSYNC
} else if resp.Status == GUEST_RUNNING {

View File

@@ -234,7 +234,11 @@ func (s *SKVMGuestInstance) isWindows10() bool {
}
func (s *SKVMGuestInstance) isMemcleanEnabled() bool {
return s.Desc.Metadata["enable_memclean"] == "true"
return s.Desc.Metadata[api.VM_METADATA_ENABLE_MEMCLEAN] == "true"
}
func (s *SKVMGuestInstance) isDisableAutoMergeSnapshots() bool {
return s.Desc.Metadata[api.VM_METADATA_DISABLE_AUTO_MERGE_SNAPSHOT] == "true"
}
func (s *SKVMGuestInstance) getMachine() string {

View File

@@ -61,9 +61,9 @@ type GuestRuntimeInstance interface {
ImportServer(pendingDelete bool)
ExitCleanup(bool)
HandleGuestStatus(ctx context.Context, resp *computeapi.HostUploadGuestStatusResponse) (jsonutils.JSONObject, error)
GetUploadStatus(ctx context.Context, reason string) (*computeapi.HostUploadGuestStatusResponse, error)
PostUploadStatus(resp *computeapi.HostUploadGuestStatusResponse, reason string)
HandleGuestStatus(ctx context.Context, resp *computeapi.HostUploadGuestStatusInput) (jsonutils.JSONObject, error)
GetUploadStatus(ctx context.Context, reason string) (*computeapi.HostUploadGuestStatusInput, error)
PostUploadStatus(resp *computeapi.HostUploadGuestStatusInput, reason string)
HandleGuestStart(ctx context.Context, userCred mcclient.TokenCredential, body jsonutils.JSONObject) (jsonutils.JSONObject, error)
HandleStop(ctx context.Context, timeout int64) error

View File

@@ -38,7 +38,9 @@ import (
"yunion.io/x/onecloud/pkg/hostman/storageman"
"yunion.io/x/onecloud/pkg/hostman/storageman/diskhandlers"
"yunion.io/x/onecloud/pkg/hostman/storageman/storagehandler"
losetupman "yunion.io/x/onecloud/pkg/util/losetup/manager"
"yunion.io/x/onecloud/pkg/util/procutils"
"yunion.io/x/onecloud/pkg/util/qemuimg"
"yunion.io/x/onecloud/pkg/util/sysutils"
)
@@ -67,6 +69,7 @@ func (host *SHostService) InitService() {
execlient.SetTimeoutSeconds(options.HostOptions.ExecutorConnectTimeoutSeconds)
procutils.SetRemoteExecutor()
}
losetupman.Init()
}
func (host *SHostService) OnExitService() {}
@@ -76,6 +79,10 @@ func (host *SHostService) RunService() {
cronManager := cronman.InitCronJobManager(false, options.HostOptions.CronJobWorkerCount, options.HostOptions.TimeZone)
hostutils.Init()
if err := qemuimg.SetPreallocation(options.HostOptions.Qcow2Preallocation); err != nil {
log.Fatalf("failed set qemuimg preallocation to %s: %s", options.HostOptions.Qcow2Preallocation, err)
}
hostInstance := hostinfo.Instance()
if err := hostInstance.Init(app.GetContext()); err != nil {
log.Fatalf("Host instance init error: %v", err)

View File

@@ -15,6 +15,7 @@
package apis
import (
"encoding/base64"
"encoding/json"
"yunion.io/x/cloudmux/pkg/apis/compute"
@@ -57,6 +58,10 @@ func NewDeployInfo(
TelegrafConf: telegrafConf,
}
}
userDataDecoded, _ := base64.StdEncoding.DecodeString(userData)
if len(userDataDecoded) > 0 {
userData = string(userDataDecoded)
}
depInfo.UserData = userData
return depInfo
}

View File

@@ -196,6 +196,10 @@ func UpdateServerStatus(ctx context.Context, sid string, statusInput *apis.Perfo
return UpdateResourceStatus(ctx, &modules.Servers, sid, statusInput)
}
func UpdateServerContainersStatus(ctx context.Context, sid string, input *computeapi.ServerPerformStatusInput) (jsonutils.JSONObject, error) {
return modules.Servers.PerformAction(GetComputeSession(ctx), sid, "status", jsonutils.Marshal(input))
}
func UpdateServerProgress(ctx context.Context, sid string, progress, progressMbps float64) (jsonutils.JSONObject, error) {
params := map[string]float64{
"progress": progress,
@@ -204,7 +208,7 @@ func UpdateServerProgress(ctx context.Context, sid string, progress, progressMbp
return modules.Servers.Update(GetComputeSession(ctx), sid, jsonutils.Marshal(params))
}
func UploadGuestsStatus(ctx context.Context, resp *computeapi.HostUploadGuestsStatusResponse) (jsonutils.JSONObject, error) {
func UploadGuestsStatus(ctx context.Context, resp *computeapi.HostUploadGuestsStatusInput) (jsonutils.JSONObject, error) {
return modules.Servers.PerformClassAction(GetComputeSession(ctx), "upload-status", jsonutils.Marshal(resp))
}

View File

@@ -91,7 +91,7 @@ func (c BaseDevice) GetNumaNode() (int, error) {
numaNodePath := fmt.Sprintf("/sys/bus/pci/devices/0000:%s/numa_node", c.SBaseDevice.GetOriginAddr())
numaNode, err := fileutils2.FileGetIntContent(numaNodePath)
if err != nil {
log.Errorf("failed get numa node %s: %s", c.SBaseDevice.GetOriginAddr(), err)
log.Debugf("failed get numa node %s: %s", c.SBaseDevice.GetOriginAddr(), err)
return -1, nil
}
return numaNode, nil

View File

@@ -835,7 +835,7 @@ func GetApiResourceData(dev IDevice) *jsonutils.JSONDict {
if numaNode, err := dev.GetNumaNode(); err == nil {
data["numa_node"] = numaNode
} else {
log.Warningf("failed get dev %s numa node %s", dev.GetAddr(), err)
log.Debugf("failed get dev %s numa node %s", dev.GetAddr(), err)
}
if dev.GetMdevId() != "" {

View File

@@ -222,6 +222,9 @@ func (s *Service) metaData(ctx context.Context, w http.ResponseWriter, r *http.R
ips := make([]string, 0)
guestNics := guestDesc.Nics
for _, nic := range guestNics {
if nic.Networkaddresses == nil {
continue
}
nas, _ := nic.Networkaddresses.GetArray()
for _, na := range nas {
if typ, _ := na.GetString("type"); typ == "sub_ip" {

View File

@@ -117,8 +117,43 @@ func (w *nullWriter) WriteAt(p []byte, off int64) (n int, err error) {
return len(p), nil
}
func getRandReader() io.Reader {
return rand.New(rand.NewSource(time.Now().UnixNano()))
var (
randBuffer [1024]byte
)
func init() {
for i := range randBuffer {
randBuffer[i] = byte(rand.Intn(256))
}
}
type randReader struct {
offset int64
sizeBytes int64
}
func newRandReader(sizeBytes int64) io.Reader {
return &randReader{offset: 0, sizeBytes: sizeBytes}
}
func (r *randReader) Read(p []byte) (n int, err error) {
if r.offset >= r.sizeBytes {
return 0, io.EOF
}
offset := 0
for offset < len(p) && r.offset+int64(offset) < r.sizeBytes {
readLen := len(randBuffer)
if readLen > len(p)-offset {
readLen = len(p) - offset
}
if readLen > int(r.sizeBytes-r.offset) {
readLen = int(r.sizeBytes-r.offset) - offset
}
copy(p[offset:], randBuffer[:readLen])
offset += readLen
}
r.offset += int64(offset)
return offset, nil
}
func ProbeBucketStats(ctx context.Context, bucket cloudprovider.ICloudBucket, testKey string, sizeBytes int64) (*api.BucketProbeResult, error) {
@@ -126,7 +161,7 @@ func ProbeBucketStats(ctx context.Context, bucket cloudprovider.ICloudBucket, te
start := time.Now()
// force upload object in one shot
err := cloudprovider.UploadObject(ctx, bucket, testKey, sizeBytes*2, getRandReader(), sizeBytes, cloudprovider.ACLPrivate, "", nil, false)
err := cloudprovider.UploadObject(ctx, bucket, testKey, sizeBytes*2, newRandReader(sizeBytes), sizeBytes, cloudprovider.ACLPrivate, "", nil, false)
if err != nil {
return nil, errors.Wrap(err, "cloudprovider.UploadObject")
}

View File

@@ -54,6 +54,7 @@ type ContainerCreateCommonOptions struct {
Args []string `help:"Args for the Command (i.e. command for docker)" json:"args"`
WorkingDir string `help:"Current working directory of the command" json:"working_dir"`
Env []string `help:"List of environment variable to set in the container and the format is: <key>=<value>"`
RootFs string `help:"Root filesystem of the container, e.g.: disk_index=<disk_number>,disk_id=<disk_id>"`
VolumeMount []string `help:"Volume mount of the container and the format is: name=<val>,mount=<container_path>,readonly=<true_or_false>,case_insensitive_paths=p1,p2,disk_index=<disk_number>,disk_id=<disk_id>"`
Device []string `help:"Host device: <host_path>:<container_path>:<permissions>, e.g.: /dev/snd:/dev/snd:rwm"`
Privileged bool `help:"Privileged mode"`
@@ -125,6 +126,13 @@ func (o ContainerCreateCommonOptions) getCreateSpec() (*computeapi.ContainerSpec
}
req.Envs = append(req.Envs, e)
}
if len(o.RootFs) != 0 {
rootFs, err := parseContainerRootFs(o.RootFs)
if err != nil {
return nil, errors.Wrapf(err, "parseContainerRootFs %s", o.RootFs)
}
req.RootFs = rootFs
}
for _, vmStr := range o.VolumeMount {
vm, err := parseContainerVolumeMount(vmStr)
if err != nil {
@@ -174,6 +182,32 @@ func parseContainerEnv(env string) (*apis.ContainerKeyValue, error) {
}, nil
}
func parseContainerRootFs(rootFs string) (*apis.ContainerRootfs, error) {
out := &apis.ContainerRootfs{
Type: apis.CONTAINER_VOLUME_MOUNT_TYPE_DISK,
Disk: &apis.ContainerVolumeMountDisk{},
}
for _, seg := range strings.Split(rootFs, ",") {
info := strings.Split(seg, "=")
if len(info) != 2 {
return nil, errors.Errorf("invalid option %s", seg)
}
key := info[0]
val := info[1]
switch key {
case "disk_index":
index, err := strconv.Atoi(val)
if err != nil {
return nil, errors.Wrapf(err, "wrong disk_index %s", val)
}
out.Disk.Index = &index
case "disk_id":
out.Disk.Id = val
}
}
return out, nil
}
func parseContainerVolumeMount(vmStr string) (*apis.ContainerVolumeMount, error) {
vm := &apis.ContainerVolumeMount{}
for _, seg := range strings.Split(vmStr, ",") {

View File

@@ -851,6 +851,16 @@ func (o *ServerModifySrcCheckOptions) Description() string {
return "Modify src ip, mac check settings"
}
type ServerDisableAutoMergeSnapshot struct {
ServerIdOptions
DisableAutoMergeSnapshot bool `help:"Disable auto merge snapshots"`
}
func (o *ServerDisableAutoMergeSnapshot) Params() (jsonutils.JSONObject, error) {
return options.StructToParams(o)
}
type ServerSendKeyOptions struct {
ID string `help:"ID or Name of server" metavar:"Guest" json:"-"`
KEYS string `help:"Special keys to send, eg. ctrl, alt, f12, shift, etc, separated by \"-\""`

View File

@@ -103,6 +103,14 @@ func (c *QueryCondition) GenerateFormatCond(meta *monitor.QueryResultMeta, metri
Evaluator: c.Evaluator,
}
}
func (c *QueryCondition) IsCloudResource() bool {
if c.ResType == "" {
return false
}
return monitor.MetricCloudResTypes.Has(c.ResType)
}
func (c FormatCond) String() string {
if c.QueryMeta != nil {
return fmt.Sprintf("%s(%q) %s", c.Reducer, c.QueryMeta.RawQuery, c.Evaluator.String())
@@ -172,7 +180,7 @@ func (c *QueryCondition) Eval(context *alerting.EvalContext) (*alerting.Conditio
}
for _, series := range seriesList {
if len(c.ResType) != 0 {
if c.IsCloudResource() {
isLatestOfSerie, resource := c.serieIsLatestResource(nil, series)
if !isLatestOfSerie {
continue
@@ -542,7 +550,11 @@ func (c *QueryCondition) checkGroupByField() {
}
for i, group := range c.Query.Model.GroupBy {
if group.Params[0] == "*" {
c.Query.Model.GroupBy[i].Params = []string{monitor.GetMeasurementTagIdKeyByResType(metricMeasurement.ResType)}
tagId := monitor.GetMeasurementTagIdKeyByResType(metricMeasurement.ResType)
if tagId == "" {
tagId = "*"
}
c.Query.Model.GroupBy[i].Params = []string{tagId}
}
}
}

View File

@@ -17,6 +17,7 @@ package alerting
import (
"context"
"fmt"
"sort"
"strings"
"time"
@@ -269,14 +270,30 @@ func (c *EvalContext) GetEvalMatches() []monitor.EvalMatch {
return ret
}
func (c *EvalContext) getTagsDesc(tags map[string]string) string {
strs := make([]string, 0)
for k, v := range tags {
if v == "" {
continue
}
strs = append(strs, k+"="+v)
}
sort.Strings(strs)
ret := strings.Join(strs, ",")
return "{" + ret + "}"
}
func (c *EvalContext) GetResourceNameOfMatches(matches []*monitor.EvalMatch) string {
names := strings.Builder{}
names.WriteString("\n")
for i, match := range matches {
if name, ok := match.Tags["name"]; ok {
names.WriteString(fmt.Sprintf("%s.%s(%s)", name, match.Metric, match.ValueStr))
if i < len(matches)-1 {
names.WriteString(", ")
}
if name, ok := match.Tags["name"]; ok && name != "" {
names.WriteString(fmt.Sprintf("- %s.%s: %s", name, match.Metric, match.ValueStr))
} else {
names.WriteString(fmt.Sprintf("- %s%s: %s", match.Metric, c.getTagsDesc(match.Tags), match.ValueStr))
}
if i < len(matches)-1 {
names.WriteString("\n")
}
}
return names.String()

View File

@@ -36,6 +36,12 @@ var worker = SMeasurement{
{
"queue_cnt", "Worker Queue Count", monitor.METRIC_UNIT_NULL,
},
{
"total_workload", "Total workload", monitor.METRIC_UNIT_NULL,
},
{
"active_workload", "Active workload", monitor.METRIC_UNIT_NULL,
},
},
}

View File

@@ -25,22 +25,154 @@ var serviceHttpCode = SMeasurement{
},
Metrics: []SMetric{
{
"duration.2xx", "http code 2xxx duration", monitor.METRIC_UNIT_NULL,
Name: "duration_ms_any",
DisplayName: "Accumulated request duration in milliseconds",
Unit: monitor.METRIC_UNIT_MS,
},
{
"duration.4xx", "http code 4xxx duration", monitor.METRIC_UNIT_NULL,
Name: "dura_ms_delta_any",
DisplayName: "Accumulated request duration in milliseconds in last interval",
Unit: monitor.METRIC_UNIT_MS,
},
{
"duration.5xx", "http code 5xxx duration", monitor.METRIC_UNIT_NULL,
Name: "hit_any",
DisplayName: "Accumulated request count",
Unit: monitor.METRIC_UNIT_NULL,
},
{
"hit.2xx", "http code 2xxx hit", monitor.METRIC_UNIT_NULL,
Name: "hit_delta_any",
DisplayName: "Accumulated request count in last interval",
Unit: monitor.METRIC_UNIT_NULL,
},
{
"hit.4xx", "http code 4xxx hit", monitor.METRIC_UNIT_NULL,
Name: "delay_ms_any",
DisplayName: "Average request delay in miilliseconds",
Unit: monitor.METRIC_UNIT_MS,
},
{
"hit.5xx", "http code 5xxx hit", monitor.METRIC_UNIT_NULL,
Name: "qps_any",
DisplayName: "Averatge request per second",
Unit: monitor.METRIC_UNIT_NULL,
},
{
Name: "duration_ms_2xx",
DisplayName: "Accumulated request duration in milliseconds for 2xx http code",
Unit: monitor.METRIC_UNIT_MS,
},
{
Name: "dura_ms_delta_2xx",
DisplayName: "Accumulated request duration in milliseconds in last interval for 2xx http code",
Unit: monitor.METRIC_UNIT_MS,
},
{
Name: "hit_2xx",
DisplayName: "Accumulated request count for 2xx http code",
Unit: monitor.METRIC_UNIT_NULL,
},
{
Name: "hit_delta_2xx",
DisplayName: "Accumulated request count in last interval for 2xx http code",
Unit: monitor.METRIC_UNIT_NULL,
},
{
Name: "delay_ms_2xx",
DisplayName: "Average request delay in miilliseconds for 2xx http code",
Unit: monitor.METRIC_UNIT_MS,
},
{
Name: "percent_hit_2xx",
DisplayName: "Request hit weight in percentage for 2xx http code",
Unit: monitor.METRIC_UNIT_PERCENT,
},
{
Name: "percent_duration_2xx",
DisplayName: "Request duration weight in percentage for 2xx http code",
Unit: monitor.METRIC_UNIT_PERCENT,
},
{
Name: "qps_2xx",
DisplayName: "Averatge request per second for 2xx http code",
Unit: monitor.METRIC_UNIT_NULL,
},
{
Name: "duration_ms_4xx",
DisplayName: "Accumulated request duration in milliseconds for 4xx http code",
Unit: monitor.METRIC_UNIT_MS,
},
{
Name: "dura_ms_delta_4xx",
DisplayName: "Accumulated request duration in milliseconds in last interval for 4xx http code",
Unit: monitor.METRIC_UNIT_MS,
},
{
Name: "hit_4xx",
DisplayName: "Accumulated request count for 4xx http code",
Unit: monitor.METRIC_UNIT_NULL,
},
{
Name: "hit_delta_4xx",
DisplayName: "Accumulated request count in last interval for 4xx http code",
Unit: monitor.METRIC_UNIT_NULL,
},
{
Name: "delay_ms_4xx",
DisplayName: "Average request delay in miilliseconds for 4xx http code",
Unit: monitor.METRIC_UNIT_MS,
},
{
Name: "percent_hit_4xx",
DisplayName: "Request hit weight in percentage for 4xx http code",
Unit: monitor.METRIC_UNIT_PERCENT,
},
{
Name: "percent_duration_4xx",
DisplayName: "Request duration weight in percentage for 4xx http code",
Unit: monitor.METRIC_UNIT_PERCENT,
},
{
Name: "qps_4xx",
DisplayName: "Averatge request per second for 4xx http code",
Unit: monitor.METRIC_UNIT_NULL,
},
{
Name: "duration_ms_5xx",
DisplayName: "Accumulated request duration in milliseconds for 5xx http code",
Unit: monitor.METRIC_UNIT_MS,
},
{
Name: "dura_ms_delta_5xx",
DisplayName: "Accumulated request duration in milliseconds in last interval for 5xx http code",
Unit: monitor.METRIC_UNIT_MS,
},
{
Name: "hit_5xx",
DisplayName: "Accumulated request count for 5xx http code",
Unit: monitor.METRIC_UNIT_NULL,
},
{
Name: "hit_delta_5xx",
DisplayName: "Accumulated request count in last interval for 5xx http code",
Unit: monitor.METRIC_UNIT_NULL,
},
{
Name: "delay_ms_5xx",
DisplayName: "Average request delay in miilliseconds for 5xx http code",
Unit: monitor.METRIC_UNIT_MS,
},
{
Name: "percent_hit_5xx",
DisplayName: "Request hit weight in percentage for 5xx http code",
Unit: monitor.METRIC_UNIT_PERCENT,
},
{
Name: "percent_duration_5xx",
DisplayName: "Request duration weight in percentage for 5xx http code",
Unit: monitor.METRIC_UNIT_PERCENT,
},
{
Name: "qps_5xx",
DisplayName: "Averatge request per second for 5xx http code",
Unit: monitor.METRIC_UNIT_NULL,
},
},
}

View File

@@ -472,6 +472,10 @@ func (m *SDataSourceManager) GetMetricMeasurement(userCred mcclient.TokenCredent
output.TagValue = make(map[string][]string, 0)
output.FieldKey = []string{field}
// 只查询过去 30m 的指标
if timeF.To == "now" {
timeF.From = "30m"
}
if err := getTagValues(userCred, output, timeF, tagFilter, true); err != nil {
return jsonutils.JSONNull, errors.Wrap(err, "getTagValues error")
}

View File

@@ -370,6 +370,11 @@ func (self *SUnifiedMonitorManager) ValidateInputQuery(query *monitor.AlertQuery
}
if input.Interval == "" {
input.Interval = "5m"
if input.To == "now" {
if input.From == "10m" {
input.Interval = "1m"
}
}
}
if query.From == "" {

View File

@@ -346,7 +346,19 @@ func (vm *vmAdapter) FillSelect(query *monitor.AlertQuery, isAlert bool) *monito
func (vm *vmAdapter) FillGroupBy(query *monitor.AlertQuery, inputQuery *monitor.MetricQueryInput, tagId string, isAlert bool) *monitor.AlertQuery {
if isAlert {
query = influxdb.FillGroupByWithWildChar(query, inputQuery, tagId)
query = FillGroupByWithWildChar(query, inputQuery, tagId)
}
return query
}
func FillGroupByWithWildChar(query *monitor.AlertQuery, inputQuery *monitor.MetricQueryInput, tagId string) *monitor.AlertQuery {
if len(tagId) == 0 {
tagId = "*"
}
query.Model.GroupBy = append(query.Model.GroupBy,
monitor.MetricQueryPart{
Type: "field",
Params: []string{tagId},
})
return query
}

View File

@@ -107,7 +107,8 @@ func sortHosts(hosts []*sSchedResultItem, guestInfo *sGuestInfo, isBackup *bool)
}
sortIndexi[1], sortIndexj[1] = hosts[i].Count, hosts[j].Count
sortIndexi[2], sortIndexj[2] = -(hosts[i].minInstanceGroupCapacity(guestInfo.instanceGroupsDetail)), -(hosts[j].minInstanceGroupCapacity(guestInfo.instanceGroupsDetail))
sortIndexi[3], sortIndexj[3] = scoreNormalization(hosts[i].Score, hosts[j].Score)
iScore, jScore := scoreNormalization(hosts[i].Score, hosts[j].Score)
sortIndexi[3], sortIndexj[3] = -iScore, -jScore
sortIndexi[4], sortIndexj[4] = -(hosts[i].Capacity), -(hosts[j].Capacity)
for i := 0; i < 5; i++ {
if sortIndexi[i] == sortIndexj[i] {

View File

@@ -17,7 +17,7 @@ package ioctl
/*
#include <linux/loop.h>
*/
import "C"
//import "C"
import (
"fmt"
"os"
@@ -38,9 +38,9 @@ import (
const (
LOOP_CTL_PATH = "/dev/loop-control"
LOOP_CTL_REMOVE = C.LOOP_CTL_REMOVE
LOOP_CTL_REMOVE = 0x4c81 // 19585 C.LOOP_CTL_REMOVE
// LOOP_CTL_GET_FREE = C.LOOP_CTL_GET_FREE
LOOP_CTL_ADD = C.LOOP_CTL_ADD
LOOP_CTL_ADD = 0x4c80 // 19584 C.LOOP_CTL_ADD
)
func AddDevice(devNumber int) (string, error) {

View File

@@ -15,6 +15,8 @@
package manager
import (
"sync"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
@@ -22,10 +24,18 @@ import (
"yunion.io/x/onecloud/pkg/util/losetup"
)
var managerObj iManager
var (
managerObj iManager
managerInitLock sync.Mutex
)
func init() {
managerObj = newManager()
func Init() {
managerInitLock.Lock()
defer managerInitLock.Unlock()
if managerObj == nil {
managerObj = newManager()
}
}
func ListDevices() (*losetup.Devices, error) {

View File

@@ -30,6 +30,10 @@ import (
"yunion.io/x/onecloud/pkg/util/procutils"
)
var (
mountTimeout = 30 * time.Second
)
func mountWrap(mountPoint string, action func() error) error {
if !fileutils2.Exists(mountPoint) {
output, err := procutils.NewCommand("mkdir", "-p", mountPoint).Output()
@@ -46,7 +50,7 @@ func mountWrap(mountPoint string, action func() error) error {
func Mount(devPath string, mountPoint string, fsType string) error {
return mountWrap(mountPoint, func() error {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
ctx, cancel := context.WithTimeout(context.Background(), mountTimeout)
defer cancel()
if out, err := procutils.NewRemoteCommandContextAsFarAsPossible(ctx, "mount", "-t", fsType, devPath, mountPoint).Output(); err != nil {
return errors.Wrapf(err, "mount %s to %s with fs %s: %s", devPath, mountPoint, fsType, string(out))
@@ -57,7 +61,7 @@ func Mount(devPath string, mountPoint string, fsType string) error {
func MountWithParams(devPath string, mountPoint string, fsType string, opts []string) error {
return mountWrap(mountPoint, func() error {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
ctx, cancel := context.WithTimeout(context.Background(), mountTimeout)
defer cancel()
args := []string{"-t", fsType, devPath, mountPoint}
args = append(args, opts...)
@@ -82,7 +86,7 @@ func MountOverlayWithFeatures(lowerDir []string, upperDir string, workDir string
func mountOverlay(lowerDir []string, upperDir string, workDir string, mergedDir string, features *MountOverlayFeatures) error {
return mountWrap(mergedDir, func() error {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
ctx, cancel := context.WithTimeout(context.Background(), mountTimeout)
defer cancel()
optStr := fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", strings.Join(lowerDir, ":"), upperDir, workDir)
if features != nil {
@@ -100,7 +104,7 @@ func mountOverlay(lowerDir []string, upperDir string, workDir string, mergedDir
func MountBind(src, target string) error {
return mountWrap(target, func() error {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
ctx, cancel := context.WithTimeout(context.Background(), mountTimeout)
defer cancel()
bindArgs := []string{"--bind", src, target}
if out, err := procutils.NewRemoteCommandContextAsFarAsPossible(ctx, "mount", bindArgs...).Output(); err != nil {

View File

@@ -404,6 +404,15 @@ func (c crictl) StopContainer(ctx context.Context, ctrId string, timeout int64,
isStopped = true
}
}
// 尝试 force kill 容器
if !force && !isStopped {
if err := c.forceKillContainer(ctx, ctrId); err != nil {
log.Infof("try force kill container %s error: %v", ctrId, err)
errs = append(errs, errors.Wrap(err, "retry forceKillContainer"))
} else {
isStopped = true
}
}
if tryRemove {
// try force remove container
ctx, cancel := context.WithTimeout(ctx, 10*time.Second)

View File

@@ -67,6 +67,19 @@ const (
const DefaultConvertCorutines = 8
var preallocation = "metadata"
func SetPreallocation(prealloc string) error {
if !utils.IsInStringArray(prealloc, []string{"", "disable", "metadata", "falloc", "full"}) {
return errors.Errorf("unsupported preallocation %s", prealloc)
}
if prealloc == "disable" {
prealloc = ""
}
preallocation = prealloc
return nil
}
type SQemuImage struct {
Path string
Password string
@@ -739,8 +752,10 @@ func (img *SQemuImage) CreateQcow2(sizeMB int, compact bool, backPath string, pa
}
} else if !compact {
sparseOpts := qcow2SparseOptions()
if sizeMB <= 1024*1024*4 {
options = append(options, "preallocation=metadata")
if preallocation != "" {
if sizeMB <= 1024*1024*4 {
options = append(options, fmt.Sprintf("preallocation=%s", preallocation))
}
}
options = append(options, sparseOpts...)
}

1
vendor/github.com/Microsoft/go-winio/.gitattributes generated vendored Normal file
View File

@@ -0,0 +1 @@
* text=auto eol=lf

View File

@@ -1 +1,10 @@
.vscode/
*.exe
# testing
testdata
# go workspaces
go.work
go.work.sum

147
vendor/github.com/Microsoft/go-winio/.golangci.yml generated vendored Normal file
View File

@@ -0,0 +1,147 @@
linters:
enable:
# style
- containedctx # struct contains a context
- dupl # duplicate code
- errname # erorrs are named correctly
- nolintlint # "//nolint" directives are properly explained
- revive # golint replacement
- unconvert # unnecessary conversions
- wastedassign
# bugs, performance, unused, etc ...
- contextcheck # function uses a non-inherited context
- errorlint # errors not wrapped for 1.13
- exhaustive # check exhaustiveness of enum switch statements
- gofmt # files are gofmt'ed
- gosec # security
- nilerr # returns nil even with non-nil error
- thelper # test helpers without t.Helper()
- unparam # unused function params
issues:
exclude-dirs:
- pkg/etw/sample
exclude-rules:
# err is very often shadowed in nested scopes
- linters:
- govet
text: '^shadow: declaration of "err" shadows declaration'
# ignore long lines for skip autogen directives
- linters:
- revive
text: "^line-length-limit: "
source: "^//(go:generate|sys) "
#TODO: remove after upgrading to go1.18
# ignore comment spacing for nolint and sys directives
- linters:
- revive
text: "^comment-spacings: no space between comment delimiter and comment text"
source: "//(cspell:|nolint:|sys |todo)"
# not on go 1.18 yet, so no any
- linters:
- revive
text: "^use-any: since GO 1.18 'interface{}' can be replaced by 'any'"
# allow unjustified ignores of error checks in defer statements
- linters:
- nolintlint
text: "^directive `//nolint:errcheck` should provide explanation"
source: '^\s*defer '
# allow unjustified ignores of error lints for io.EOF
- linters:
- nolintlint
text: "^directive `//nolint:errorlint` should provide explanation"
source: '[=|!]= io.EOF'
linters-settings:
exhaustive:
default-signifies-exhaustive: true
govet:
enable-all: true
disable:
# struct order is often for Win32 compat
# also, ignore pointer bytes/GC issues for now until performance becomes an issue
- fieldalignment
nolintlint:
require-explanation: true
require-specific: true
revive:
# revive is more configurable than static check, so likely the preferred alternative to static-check
# (once the perf issue is solved: https://github.com/golangci/golangci-lint/issues/2997)
enable-all-rules:
true
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md
rules:
# rules with required arguments
- name: argument-limit
disabled: true
- name: banned-characters
disabled: true
- name: cognitive-complexity
disabled: true
- name: cyclomatic
disabled: true
- name: file-header
disabled: true
- name: function-length
disabled: true
- name: function-result-limit
disabled: true
- name: max-public-structs
disabled: true
# geneally annoying rules
- name: add-constant # complains about any and all strings and integers
disabled: true
- name: confusing-naming # we frequently use "Foo()" and "foo()" together
disabled: true
- name: flag-parameter # excessive, and a common idiom we use
disabled: true
- name: unhandled-error # warns over common fmt.Print* and io.Close; rely on errcheck instead
disabled: true
# general config
- name: line-length-limit
arguments:
- 140
- name: var-naming
arguments:
- []
- - CID
- CRI
- CTRD
- DACL
- DLL
- DOS
- ETW
- FSCTL
- GCS
- GMSA
- HCS
- HV
- IO
- LCOW
- LDAP
- LPAC
- LTSC
- MMIO
- NT
- OCI
- PMEM
- PWSH
- RX
- SACl
- SID
- SMB
- TX
- VHD
- VHDX
- VMID
- VPCI
- WCOW
- WIM

1
vendor/github.com/Microsoft/go-winio/CODEOWNERS generated vendored Normal file
View File

@@ -0,0 +1 @@
* @microsoft/containerplat

View File

@@ -1,4 +1,4 @@
# go-winio
# go-winio [![Build Status](https://github.com/microsoft/go-winio/actions/workflows/ci.yml/badge.svg)](https://github.com/microsoft/go-winio/actions/workflows/ci.yml)
This repository contains utilities for efficiently performing Win32 IO operations in
Go. Currently, this is focused on accessing named pipes and other file handles, and
@@ -11,12 +11,79 @@ package.
Please see the LICENSE file for licensing information.
This project has adopted the [Microsoft Open Source Code of
Conduct](https://opensource.microsoft.com/codeofconduct/). For more information
see the [Code of Conduct
FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact
[opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional
questions or comments.
## Contributing
Thanks to natefinch for the inspiration for this library. See https://github.com/natefinch/npipe
for another named pipe implementation.
This project welcomes contributions and suggestions.
Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that
you have the right to, and actually do, grant us the rights to use your contribution.
For details, visit [Microsoft CLA](https://cla.microsoft.com).
When you submit a pull request, a CLA-bot will automatically determine whether you need to
provide a CLA and decorate the PR appropriately (e.g., label, comment).
Simply follow the instructions provided by the bot.
You will only need to do this once across all repos using our CLA.
Additionally, the pull request pipeline requires the following steps to be performed before
mergining.
### Code Sign-Off
We require that contributors sign their commits using [`git commit --signoff`][git-commit-s]
to certify they either authored the work themselves or otherwise have permission to use it in this project.
A range of commits can be signed off using [`git rebase --signoff`][git-rebase-s].
Please see [the developer certificate](https://developercertificate.org) for more info,
as well as to make sure that you can attest to the rules listed.
Our CI uses the DCO Github app to ensure that all commits in a given PR are signed-off.
### Linting
Code must pass a linting stage, which uses [`golangci-lint`][lint].
The linting settings are stored in [`.golangci.yaml`](./.golangci.yaml), and can be run
automatically with VSCode by adding the following to your workspace or folder settings:
```json
"go.lintTool": "golangci-lint",
"go.lintOnSave": "package",
```
Additional editor [integrations options are also available][lint-ide].
Alternatively, `golangci-lint` can be [installed locally][lint-install] and run from the repo root:
```shell
# use . or specify a path to only lint a package
# to show all lint errors, use flags "--max-issues-per-linter=0 --max-same-issues=0"
> golangci-lint run ./...
```
### Go Generate
The pipeline checks that auto-generated code, via `go generate`, are up to date.
This can be done for the entire repo:
```shell
> go generate ./...
```
## Code of Conduct
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
## Special Thanks
Thanks to [natefinch][natefinch] for the inspiration for this library.
See [npipe](https://github.com/natefinch/npipe) for another named pipe implementation.
[lint]: https://golangci-lint.run/
[lint-ide]: https://golangci-lint.run/usage/integrations/#editor-integration
[lint-install]: https://golangci-lint.run/usage/install/#local-installation
[git-commit-s]: https://git-scm.com/docs/git-commit#Documentation/git-commit.txt--s
[git-rebase-s]: https://git-scm.com/docs/git-rebase#Documentation/git-rebase.txt---signoff
[natefinch]: https://github.com/natefinch

41
vendor/github.com/Microsoft/go-winio/SECURITY.md generated vendored Normal file
View File

@@ -0,0 +1,41 @@
<!-- BEGIN MICROSOFT SECURITY.MD V0.0.7 BLOCK -->
## Security
Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/).
If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below.
## Reporting Security Issues
**Please do not report security vulnerabilities through public GitHub issues.**
Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report).
If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey).
You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc).
Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
* Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
* Full paths of source file(s) related to the manifestation of the issue
* The location of the affected source code (tag/branch/commit or direct URL)
* Any special configuration required to reproduce the issue
* Step-by-step instructions to reproduce the issue
* Proof-of-concept or exploit code (if possible)
* Impact of the issue, including how an attacker might exploit the issue
This information will help us triage your report more quickly.
If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs.
## Preferred Languages
We prefer all communications to be in English.
## Policy
Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd).
<!-- END MICROSOFT SECURITY.MD BLOCK -->

View File

@@ -1,3 +1,4 @@
//go:build windows
// +build windows
package winio
@@ -7,15 +8,16 @@ import (
"errors"
"fmt"
"io"
"io/ioutil"
"os"
"runtime"
"syscall"
"unicode/utf16"
"github.com/Microsoft/go-winio/internal/fs"
"golang.org/x/sys/windows"
)
//sys backupRead(h syscall.Handle, b []byte, bytesRead *uint32, abort bool, processSecurity bool, context *uintptr) (err error) = BackupRead
//sys backupWrite(h syscall.Handle, b []byte, bytesWritten *uint32, abort bool, processSecurity bool, context *uintptr) (err error) = BackupWrite
//sys backupRead(h windows.Handle, b []byte, bytesRead *uint32, abort bool, processSecurity bool, context *uintptr) (err error) = BackupRead
//sys backupWrite(h windows.Handle, b []byte, bytesWritten *uint32, abort bool, processSecurity bool, context *uintptr) (err error) = BackupWrite
const (
BackupData = uint32(iota + 1)
@@ -24,7 +26,7 @@ const (
BackupAlternateData
BackupLink
BackupPropertyData
BackupObjectId
BackupObjectId //revive:disable-line:var-naming ID, not Id
BackupReparseData
BackupSparseBlock
BackupTxfsData
@@ -34,14 +36,16 @@ const (
StreamSparseAttributes = uint32(8)
)
//nolint:revive // var-naming: ALL_CAPS
const (
WRITE_DAC = 0x40000
WRITE_OWNER = 0x80000
ACCESS_SYSTEM_SECURITY = 0x1000000
WRITE_DAC = windows.WRITE_DAC
WRITE_OWNER = windows.WRITE_OWNER
ACCESS_SYSTEM_SECURITY = windows.ACCESS_SYSTEM_SECURITY
)
// BackupHeader represents a backup stream of a file.
type BackupHeader struct {
//revive:disable-next-line:var-naming ID, not Id
Id uint32 // The backup stream ID
Attributes uint32 // Stream attributes
Size int64 // The size of the stream in bytes
@@ -49,8 +53,8 @@ type BackupHeader struct {
Offset int64 // The offset of the stream in the file (for BackupSparseBlock only).
}
type win32StreamId struct {
StreamId uint32
type win32StreamID struct {
StreamID uint32
Attributes uint32
Size uint64
NameSize uint32
@@ -71,7 +75,7 @@ func NewBackupStreamReader(r io.Reader) *BackupStreamReader {
// Next returns the next backup stream and prepares for calls to Read(). It skips the remainder of the current stream if
// it was not completely read.
func (r *BackupStreamReader) Next() (*BackupHeader, error) {
if r.bytesLeft > 0 {
if r.bytesLeft > 0 { //nolint:nestif // todo: flatten this
if s, ok := r.r.(io.Seeker); ok {
// Make sure Seek on io.SeekCurrent sometimes succeeds
// before trying the actual seek.
@@ -82,16 +86,16 @@ func (r *BackupStreamReader) Next() (*BackupHeader, error) {
r.bytesLeft = 0
}
}
if _, err := io.Copy(ioutil.Discard, r); err != nil {
if _, err := io.Copy(io.Discard, r); err != nil {
return nil, err
}
}
var wsi win32StreamId
var wsi win32StreamID
if err := binary.Read(r.r, binary.LittleEndian, &wsi); err != nil {
return nil, err
}
hdr := &BackupHeader{
Id: wsi.StreamId,
Id: wsi.StreamID,
Attributes: wsi.Attributes,
Size: int64(wsi.Size),
}
@@ -100,9 +104,9 @@ func (r *BackupStreamReader) Next() (*BackupHeader, error) {
if err := binary.Read(r.r, binary.LittleEndian, name); err != nil {
return nil, err
}
hdr.Name = syscall.UTF16ToString(name)
hdr.Name = windows.UTF16ToString(name)
}
if wsi.StreamId == BackupSparseBlock {
if wsi.StreamID == BackupSparseBlock {
if err := binary.Read(r.r, binary.LittleEndian, &hdr.Offset); err != nil {
return nil, err
}
@@ -147,8 +151,8 @@ func (w *BackupStreamWriter) WriteHeader(hdr *BackupHeader) error {
return fmt.Errorf("missing %d bytes", w.bytesLeft)
}
name := utf16.Encode([]rune(hdr.Name))
wsi := win32StreamId{
StreamId: hdr.Id,
wsi := win32StreamID{
StreamID: hdr.Id,
Attributes: hdr.Attributes,
Size: uint64(hdr.Size),
NameSize: uint32(len(name) * 2),
@@ -201,9 +205,9 @@ func NewBackupFileReader(f *os.File, includeSecurity bool) *BackupFileReader {
// Read reads a backup stream from the file by calling the Win32 API BackupRead().
func (r *BackupFileReader) Read(b []byte) (int, error) {
var bytesRead uint32
err := backupRead(syscall.Handle(r.f.Fd()), b, &bytesRead, false, r.includeSecurity, &r.ctx)
err := backupRead(windows.Handle(r.f.Fd()), b, &bytesRead, false, r.includeSecurity, &r.ctx)
if err != nil {
return 0, &os.PathError{"BackupRead", r.f.Name(), err}
return 0, &os.PathError{Op: "BackupRead", Path: r.f.Name(), Err: err}
}
runtime.KeepAlive(r.f)
if bytesRead == 0 {
@@ -216,7 +220,7 @@ func (r *BackupFileReader) Read(b []byte) (int, error) {
// the underlying file.
func (r *BackupFileReader) Close() error {
if r.ctx != 0 {
backupRead(syscall.Handle(r.f.Fd()), nil, nil, true, false, &r.ctx)
_ = backupRead(windows.Handle(r.f.Fd()), nil, nil, true, false, &r.ctx)
runtime.KeepAlive(r.f)
r.ctx = 0
}
@@ -240,9 +244,9 @@ func NewBackupFileWriter(f *os.File, includeSecurity bool) *BackupFileWriter {
// Write restores a portion of the file using the provided backup stream.
func (w *BackupFileWriter) Write(b []byte) (int, error) {
var bytesWritten uint32
err := backupWrite(syscall.Handle(w.f.Fd()), b, &bytesWritten, false, w.includeSecurity, &w.ctx)
err := backupWrite(windows.Handle(w.f.Fd()), b, &bytesWritten, false, w.includeSecurity, &w.ctx)
if err != nil {
return 0, &os.PathError{"BackupWrite", w.f.Name(), err}
return 0, &os.PathError{Op: "BackupWrite", Path: w.f.Name(), Err: err}
}
runtime.KeepAlive(w.f)
if int(bytesWritten) != len(b) {
@@ -255,7 +259,7 @@ func (w *BackupFileWriter) Write(b []byte) (int, error) {
// close the underlying file.
func (w *BackupFileWriter) Close() error {
if w.ctx != 0 {
backupWrite(syscall.Handle(w.f.Fd()), nil, nil, true, false, &w.ctx)
_ = backupWrite(windows.Handle(w.f.Fd()), nil, nil, true, false, &w.ctx)
runtime.KeepAlive(w.f)
w.ctx = 0
}
@@ -267,11 +271,14 @@ func (w *BackupFileWriter) Close() error {
//
// If the file opened was a directory, it cannot be used with Readdir().
func OpenForBackup(path string, access uint32, share uint32, createmode uint32) (*os.File, error) {
winPath, err := syscall.UTF16FromString(path)
if err != nil {
return nil, err
}
h, err := syscall.CreateFile(&winPath[0], access, share, nil, createmode, syscall.FILE_FLAG_BACKUP_SEMANTICS|syscall.FILE_FLAG_OPEN_REPARSE_POINT, 0)
h, err := fs.CreateFile(path,
fs.AccessMask(access),
fs.FileShareMode(share),
nil,
fs.FileCreationDisposition(createmode),
fs.FILE_FLAG_BACKUP_SEMANTICS|fs.FILE_FLAG_OPEN_REPARSE_POINT,
0,
)
if err != nil {
err = &os.PathError{Op: "open", Path: path, Err: err}
return nil, err

22
vendor/github.com/Microsoft/go-winio/doc.go generated vendored Normal file
View File

@@ -0,0 +1,22 @@
// This package provides utilities for efficiently performing Win32 IO operations in Go.
// Currently, this package is provides support for genreal IO and management of
// - named pipes
// - files
// - [Hyper-V sockets]
//
// This code is similar to Go's [net] package, and uses IO completion ports to avoid
// blocking IO on system threads, allowing Go to reuse the thread to schedule other goroutines.
//
// This limits support to Windows Vista and newer operating systems.
//
// Additionally, this package provides support for:
// - creating and managing GUIDs
// - writing to [ETW]
// - opening and manageing VHDs
// - parsing [Windows Image files]
// - auto-generating Win32 API code
//
// [Hyper-V sockets]: https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/user-guide/make-integration-service
// [ETW]: https://docs.microsoft.com/en-us/windows-hardware/drivers/devtest/event-tracing-for-windows--etw-
// [Windows Image files]: https://docs.microsoft.com/en-us/windows-hardware/manufacture/desktop/work-with-windows-images
package winio

View File

@@ -33,7 +33,7 @@ func parseEa(b []byte) (ea ExtendedAttribute, nb []byte, err error) {
err = binary.Read(bytes.NewReader(b), binary.LittleEndian, &info)
if err != nil {
err = errInvalidEaBuffer
return
return ea, nb, err
}
nameOffset := fileFullEaInformationSize
@@ -43,7 +43,7 @@ func parseEa(b []byte) (ea ExtendedAttribute, nb []byte, err error) {
nextOffset := int(info.NextEntryOffset)
if valueLen+valueOffset > len(b) || nextOffset < 0 || nextOffset > len(b) {
err = errInvalidEaBuffer
return
return ea, nb, err
}
ea.Name = string(b[nameOffset : nameOffset+nameLen])
@@ -52,7 +52,7 @@ func parseEa(b []byte) (ea ExtendedAttribute, nb []byte, err error) {
if info.NextEntryOffset != 0 {
nb = b[info.NextEntryOffset:]
}
return
return ea, nb, err
}
// DecodeExtendedAttributes decodes a list of EAs from a FILE_FULL_EA_INFORMATION
@@ -67,7 +67,7 @@ func DecodeExtendedAttributes(b []byte) (eas []ExtendedAttribute, err error) {
eas = append(eas, ea)
b = nb
}
return
return eas, err
}
func writeEa(buf *bytes.Buffer, ea *ExtendedAttribute, last bool) error {

View File

@@ -1,3 +1,4 @@
//go:build windows
// +build windows
package winio
@@ -10,31 +11,15 @@ import (
"sync/atomic"
"syscall"
"time"
"golang.org/x/sys/windows"
)
//sys cancelIoEx(file syscall.Handle, o *syscall.Overlapped) (err error) = CancelIoEx
//sys createIoCompletionPort(file syscall.Handle, port syscall.Handle, key uintptr, threadCount uint32) (newport syscall.Handle, err error) = CreateIoCompletionPort
//sys getQueuedCompletionStatus(port syscall.Handle, bytes *uint32, key *uintptr, o **ioOperation, timeout uint32) (err error) = GetQueuedCompletionStatus
//sys setFileCompletionNotificationModes(h syscall.Handle, flags uint8) (err error) = SetFileCompletionNotificationModes
//sys wsaGetOverlappedResult(h syscall.Handle, o *syscall.Overlapped, bytes *uint32, wait bool, flags *uint32) (err error) = ws2_32.WSAGetOverlappedResult
type atomicBool int32
func (b *atomicBool) isSet() bool { return atomic.LoadInt32((*int32)(b)) != 0 }
func (b *atomicBool) setFalse() { atomic.StoreInt32((*int32)(b), 0) }
func (b *atomicBool) setTrue() { atomic.StoreInt32((*int32)(b), 1) }
func (b *atomicBool) swap(new bool) bool {
var newInt int32
if new {
newInt = 1
}
return atomic.SwapInt32((*int32)(b), newInt) == 1
}
const (
cFILE_SKIP_COMPLETION_PORT_ON_SUCCESS = 1
cFILE_SKIP_SET_EVENT_ON_HANDLE = 2
)
//sys cancelIoEx(file windows.Handle, o *windows.Overlapped) (err error) = CancelIoEx
//sys createIoCompletionPort(file windows.Handle, port windows.Handle, key uintptr, threadCount uint32) (newport windows.Handle, err error) = CreateIoCompletionPort
//sys getQueuedCompletionStatus(port windows.Handle, bytes *uint32, key *uintptr, o **ioOperation, timeout uint32) (err error) = GetQueuedCompletionStatus
//sys setFileCompletionNotificationModes(h windows.Handle, flags uint8) (err error) = SetFileCompletionNotificationModes
//sys wsaGetOverlappedResult(h windows.Handle, o *windows.Overlapped, bytes *uint32, wait bool, flags *uint32) (err error) = ws2_32.WSAGetOverlappedResult
var (
ErrFileClosed = errors.New("file has already been closed")
@@ -43,29 +28,29 @@ var (
type timeoutError struct{}
func (e *timeoutError) Error() string { return "i/o timeout" }
func (e *timeoutError) Timeout() bool { return true }
func (e *timeoutError) Temporary() bool { return true }
func (*timeoutError) Error() string { return "i/o timeout" }
func (*timeoutError) Timeout() bool { return true }
func (*timeoutError) Temporary() bool { return true }
type timeoutChan chan struct{}
var ioInitOnce sync.Once
var ioCompletionPort syscall.Handle
var ioCompletionPort windows.Handle
// ioResult contains the result of an asynchronous IO operation
// ioResult contains the result of an asynchronous IO operation.
type ioResult struct {
bytes uint32
err error
}
// ioOperation represents an outstanding asynchronous Win32 IO
// ioOperation represents an outstanding asynchronous Win32 IO.
type ioOperation struct {
o syscall.Overlapped
o windows.Overlapped
ch chan ioResult
}
func initIo() {
h, err := createIoCompletionPort(syscall.InvalidHandle, 0, 0, 0xffffffff)
func initIO() {
h, err := createIoCompletionPort(windows.InvalidHandle, 0, 0, 0xffffffff)
if err != nil {
panic(err)
}
@@ -76,10 +61,10 @@ func initIo() {
// win32File implements Reader, Writer, and Closer on a Win32 handle without blocking in a syscall.
// It takes ownership of this handle and will close it if it is garbage collected.
type win32File struct {
handle syscall.Handle
handle windows.Handle
wg sync.WaitGroup
wgLock sync.RWMutex
closing atomicBool
closing atomic.Bool
socket bool
readDeadline deadlineHandler
writeDeadline deadlineHandler
@@ -90,18 +75,18 @@ type deadlineHandler struct {
channel timeoutChan
channelLock sync.RWMutex
timer *time.Timer
timedout atomicBool
timedout atomic.Bool
}
// makeWin32File makes a new win32File from an existing file handle
func makeWin32File(h syscall.Handle) (*win32File, error) {
// makeWin32File makes a new win32File from an existing file handle.
func makeWin32File(h windows.Handle) (*win32File, error) {
f := &win32File{handle: h}
ioInitOnce.Do(initIo)
ioInitOnce.Do(initIO)
_, err := createIoCompletionPort(h, ioCompletionPort, 0, 0xffffffff)
if err != nil {
return nil, err
}
err = setFileCompletionNotificationModes(h, cFILE_SKIP_COMPLETION_PORT_ON_SUCCESS|cFILE_SKIP_SET_EVENT_ON_HANDLE)
err = setFileCompletionNotificationModes(h, windows.FILE_SKIP_COMPLETION_PORT_ON_SUCCESS|windows.FILE_SKIP_SET_EVENT_ON_HANDLE)
if err != nil {
return nil, err
}
@@ -110,7 +95,12 @@ func makeWin32File(h syscall.Handle) (*win32File, error) {
return f, nil
}
// Deprecated: use NewOpenFile instead.
func MakeOpenFile(h syscall.Handle) (io.ReadWriteCloser, error) {
return NewOpenFile(windows.Handle(h))
}
func NewOpenFile(h windows.Handle) (io.ReadWriteCloser, error) {
// If we return the result of makeWin32File directly, it can result in an
// interface-wrapped nil, rather than a nil interface value.
f, err := makeWin32File(h)
@@ -120,17 +110,17 @@ func MakeOpenFile(h syscall.Handle) (io.ReadWriteCloser, error) {
return f, nil
}
// closeHandle closes the resources associated with a Win32 handle
// closeHandle closes the resources associated with a Win32 handle.
func (f *win32File) closeHandle() {
f.wgLock.Lock()
// Atomically set that we are closing, releasing the resources only once.
if !f.closing.swap(true) {
if !f.closing.Swap(true) {
f.wgLock.Unlock()
// cancel all IO and wait for it to complete
cancelIoEx(f.handle, nil)
_ = cancelIoEx(f.handle, nil)
f.wg.Wait()
// at this point, no new IO can start
syscall.Close(f.handle)
windows.Close(f.handle)
f.handle = 0
} else {
f.wgLock.Unlock()
@@ -143,11 +133,16 @@ func (f *win32File) Close() error {
return nil
}
// prepareIo prepares for a new IO operation.
// IsClosed checks if the file has been closed.
func (f *win32File) IsClosed() bool {
return f.closing.Load()
}
// prepareIO prepares for a new IO operation.
// The caller must call f.wg.Done() when the IO is finished, prior to Close() returning.
func (f *win32File) prepareIo() (*ioOperation, error) {
func (f *win32File) prepareIO() (*ioOperation, error) {
f.wgLock.RLock()
if f.closing.isSet() {
if f.closing.Load() {
f.wgLock.RUnlock()
return nil, ErrFileClosed
}
@@ -158,13 +153,13 @@ func (f *win32File) prepareIo() (*ioOperation, error) {
return c, nil
}
// ioCompletionProcessor processes completed async IOs forever
func ioCompletionProcessor(h syscall.Handle) {
// ioCompletionProcessor processes completed async IOs forever.
func ioCompletionProcessor(h windows.Handle) {
for {
var bytes uint32
var key uintptr
var op *ioOperation
err := getQueuedCompletionStatus(h, &bytes, &key, &op, syscall.INFINITE)
err := getQueuedCompletionStatus(h, &bytes, &key, &op, windows.INFINITE)
if op == nil {
panic(err)
}
@@ -172,15 +167,17 @@ func ioCompletionProcessor(h syscall.Handle) {
}
}
// asyncIo processes the return value from ReadFile or WriteFile, blocking until
// todo: helsaawy - create an asyncIO version that takes a context
// asyncIO processes the return value from ReadFile or WriteFile, blocking until
// the operation has actually completed.
func (f *win32File) asyncIo(c *ioOperation, d *deadlineHandler, bytes uint32, err error) (int, error) {
if err != syscall.ERROR_IO_PENDING {
func (f *win32File) asyncIO(c *ioOperation, d *deadlineHandler, bytes uint32, err error) (int, error) {
if err != windows.ERROR_IO_PENDING { //nolint:errorlint // err is Errno
return int(bytes), err
}
if f.closing.isSet() {
cancelIoEx(f.handle, &c.o)
if f.closing.Load() {
_ = cancelIoEx(f.handle, &c.o)
}
var timeout timeoutChan
@@ -194,8 +191,8 @@ func (f *win32File) asyncIo(c *ioOperation, d *deadlineHandler, bytes uint32, er
select {
case r = <-c.ch:
err = r.err
if err == syscall.ERROR_OPERATION_ABORTED {
if f.closing.isSet() {
if err == windows.ERROR_OPERATION_ABORTED { //nolint:errorlint // err is Errno
if f.closing.Load() {
err = ErrFileClosed
}
} else if err != nil && f.socket {
@@ -204,10 +201,10 @@ func (f *win32File) asyncIo(c *ioOperation, d *deadlineHandler, bytes uint32, er
err = wsaGetOverlappedResult(f.handle, &c.o, &bytes, false, &flags)
}
case <-timeout:
cancelIoEx(f.handle, &c.o)
_ = cancelIoEx(f.handle, &c.o)
r = <-c.ch
err = r.err
if err == syscall.ERROR_OPERATION_ABORTED {
if err == windows.ERROR_OPERATION_ABORTED { //nolint:errorlint // err is Errno
err = ErrTimeout
}
}
@@ -215,52 +212,52 @@ func (f *win32File) asyncIo(c *ioOperation, d *deadlineHandler, bytes uint32, er
// runtime.KeepAlive is needed, as c is passed via native
// code to ioCompletionProcessor, c must remain alive
// until the channel read is complete.
// todo: (de)allocate *ioOperation via win32 heap functions, instead of needing to KeepAlive?
runtime.KeepAlive(c)
return int(r.bytes), err
}
// Read reads from a file handle.
func (f *win32File) Read(b []byte) (int, error) {
c, err := f.prepareIo()
c, err := f.prepareIO()
if err != nil {
return 0, err
}
defer f.wg.Done()
if f.readDeadline.timedout.isSet() {
if f.readDeadline.timedout.Load() {
return 0, ErrTimeout
}
var bytes uint32
err = syscall.ReadFile(f.handle, b, &bytes, &c.o)
n, err := f.asyncIo(c, &f.readDeadline, bytes, err)
err = windows.ReadFile(f.handle, b, &bytes, &c.o)
n, err := f.asyncIO(c, &f.readDeadline, bytes, err)
runtime.KeepAlive(b)
// Handle EOF conditions.
if err == nil && n == 0 && len(b) != 0 {
return 0, io.EOF
} else if err == syscall.ERROR_BROKEN_PIPE {
} else if err == windows.ERROR_BROKEN_PIPE { //nolint:errorlint // err is Errno
return 0, io.EOF
} else {
return n, err
}
return n, err
}
// Write writes to a file handle.
func (f *win32File) Write(b []byte) (int, error) {
c, err := f.prepareIo()
c, err := f.prepareIO()
if err != nil {
return 0, err
}
defer f.wg.Done()
if f.writeDeadline.timedout.isSet() {
if f.writeDeadline.timedout.Load() {
return 0, ErrTimeout
}
var bytes uint32
err = syscall.WriteFile(f.handle, b, &bytes, &c.o)
n, err := f.asyncIo(c, &f.writeDeadline, bytes, err)
err = windows.WriteFile(f.handle, b, &bytes, &c.o)
n, err := f.asyncIO(c, &f.writeDeadline, bytes, err)
runtime.KeepAlive(b)
return n, err
}
@@ -274,7 +271,7 @@ func (f *win32File) SetWriteDeadline(deadline time.Time) error {
}
func (f *win32File) Flush() error {
return syscall.FlushFileBuffers(f.handle)
return windows.FlushFileBuffers(f.handle)
}
func (f *win32File) Fd() uintptr {
@@ -291,7 +288,7 @@ func (d *deadlineHandler) set(deadline time.Time) error {
}
d.timer = nil
}
d.timedout.setFalse()
d.timedout.Store(false)
select {
case <-d.channel:
@@ -306,7 +303,7 @@ func (d *deadlineHandler) set(deadline time.Time) error {
}
timeoutIO := func() {
d.timedout.setTrue()
d.timedout.Store(true)
close(d.channel)
}

View File

@@ -1,3 +1,4 @@
//go:build windows
// +build windows
package winio
@@ -5,44 +6,83 @@ package winio
import (
"os"
"runtime"
"syscall"
"unsafe"
)
//sys getFileInformationByHandleEx(h syscall.Handle, class uint32, buffer *byte, size uint32) (err error) = GetFileInformationByHandleEx
//sys setFileInformationByHandle(h syscall.Handle, class uint32, buffer *byte, size uint32) (err error) = SetFileInformationByHandle
const (
fileBasicInfo = 0
fileIDInfo = 0x12
"golang.org/x/sys/windows"
)
// FileBasicInfo contains file access time and file attributes information.
type FileBasicInfo struct {
CreationTime, LastAccessTime, LastWriteTime, ChangeTime syscall.Filetime
CreationTime, LastAccessTime, LastWriteTime, ChangeTime windows.Filetime
FileAttributes uint32
pad uint32 // padding
_ uint32 // padding
}
// alignedFileBasicInfo is a FileBasicInfo, but aligned to uint64 by containing
// uint64 rather than windows.Filetime. Filetime contains two uint32s. uint64
// alignment is necessary to pass this as FILE_BASIC_INFO.
type alignedFileBasicInfo struct {
CreationTime, LastAccessTime, LastWriteTime, ChangeTime uint64
FileAttributes uint32
_ uint32 // padding
}
// GetFileBasicInfo retrieves times and attributes for a file.
func GetFileBasicInfo(f *os.File) (*FileBasicInfo, error) {
bi := &FileBasicInfo{}
if err := getFileInformationByHandleEx(syscall.Handle(f.Fd()), fileBasicInfo, (*byte)(unsafe.Pointer(bi)), uint32(unsafe.Sizeof(*bi))); err != nil {
bi := &alignedFileBasicInfo{}
if err := windows.GetFileInformationByHandleEx(
windows.Handle(f.Fd()),
windows.FileBasicInfo,
(*byte)(unsafe.Pointer(bi)),
uint32(unsafe.Sizeof(*bi)),
); err != nil {
return nil, &os.PathError{Op: "GetFileInformationByHandleEx", Path: f.Name(), Err: err}
}
runtime.KeepAlive(f)
return bi, nil
// Reinterpret the alignedFileBasicInfo as a FileBasicInfo so it matches the
// public API of this module. The data may be unnecessarily aligned.
return (*FileBasicInfo)(unsafe.Pointer(bi)), nil
}
// SetFileBasicInfo sets times and attributes for a file.
func SetFileBasicInfo(f *os.File, bi *FileBasicInfo) error {
if err := setFileInformationByHandle(syscall.Handle(f.Fd()), fileBasicInfo, (*byte)(unsafe.Pointer(bi)), uint32(unsafe.Sizeof(*bi))); err != nil {
// Create an alignedFileBasicInfo based on a FileBasicInfo. The copy is
// suitable to pass to GetFileInformationByHandleEx.
biAligned := *(*alignedFileBasicInfo)(unsafe.Pointer(bi))
if err := windows.SetFileInformationByHandle(
windows.Handle(f.Fd()),
windows.FileBasicInfo,
(*byte)(unsafe.Pointer(&biAligned)),
uint32(unsafe.Sizeof(biAligned)),
); err != nil {
return &os.PathError{Op: "SetFileInformationByHandle", Path: f.Name(), Err: err}
}
runtime.KeepAlive(f)
return nil
}
// FileStandardInfo contains extended information for the file.
// FILE_STANDARD_INFO in WinBase.h
// https://docs.microsoft.com/en-us/windows/win32/api/winbase/ns-winbase-file_standard_info
type FileStandardInfo struct {
AllocationSize, EndOfFile int64
NumberOfLinks uint32
DeletePending, Directory bool
}
// GetFileStandardInfo retrieves ended information for the file.
func GetFileStandardInfo(f *os.File) (*FileStandardInfo, error) {
si := &FileStandardInfo{}
if err := windows.GetFileInformationByHandleEx(windows.Handle(f.Fd()),
windows.FileStandardInfo,
(*byte)(unsafe.Pointer(si)),
uint32(unsafe.Sizeof(*si))); err != nil {
return nil, &os.PathError{Op: "GetFileInformationByHandleEx", Path: f.Name(), Err: err}
}
runtime.KeepAlive(f)
return si, nil
}
// FileIDInfo contains the volume serial number and file ID for a file. This pair should be
// unique on a system.
type FileIDInfo struct {
@@ -53,7 +93,12 @@ type FileIDInfo struct {
// GetFileID retrieves the unique (volume, file ID) pair for a file.
func GetFileID(f *os.File) (*FileIDInfo, error) {
fileID := &FileIDInfo{}
if err := getFileInformationByHandleEx(syscall.Handle(f.Fd()), fileIDInfo, (*byte)(unsafe.Pointer(fileID)), uint32(unsafe.Sizeof(*fileID))); err != nil {
if err := windows.GetFileInformationByHandleEx(
windows.Handle(f.Fd()),
windows.FileIdInfo,
(*byte)(unsafe.Pointer(fileID)),
uint32(unsafe.Sizeof(*fileID)),
); err != nil {
return nil, &os.PathError{Op: "GetFileInformationByHandleEx", Path: f.Name(), Err: err}
}
runtime.KeepAlive(f)

View File

@@ -1,24 +1,99 @@
//go:build windows
// +build windows
package winio
import (
"context"
"errors"
"fmt"
"io"
"net"
"os"
"syscall"
"time"
"unsafe"
"golang.org/x/sys/windows"
"github.com/Microsoft/go-winio/internal/socket"
"github.com/Microsoft/go-winio/pkg/guid"
)
//sys bind(s syscall.Handle, name unsafe.Pointer, namelen int32) (err error) [failretval==socketError] = ws2_32.bind
const afHVSock = 34 // AF_HYPERV
const (
afHvSock = 34 // AF_HYPERV
// Well known Service and VM IDs
// https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/user-guide/make-integration-service#vmid-wildcards
socketError = ^uintptr(0)
)
// HvsockGUIDWildcard is the wildcard VmId for accepting connections from all partitions.
func HvsockGUIDWildcard() guid.GUID { // 00000000-0000-0000-0000-000000000000
return guid.GUID{}
}
// HvsockGUIDBroadcast is the wildcard VmId for broadcasting sends to all partitions.
func HvsockGUIDBroadcast() guid.GUID { // ffffffff-ffff-ffff-ffff-ffffffffffff
return guid.GUID{
Data1: 0xffffffff,
Data2: 0xffff,
Data3: 0xffff,
Data4: [8]uint8{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
}
}
// HvsockGUIDLoopback is the Loopback VmId for accepting connections to the same partition as the connector.
func HvsockGUIDLoopback() guid.GUID { // e0e16197-dd56-4a10-9195-5ee7a155a838
return guid.GUID{
Data1: 0xe0e16197,
Data2: 0xdd56,
Data3: 0x4a10,
Data4: [8]uint8{0x91, 0x95, 0x5e, 0xe7, 0xa1, 0x55, 0xa8, 0x38},
}
}
// HvsockGUIDSiloHost is the address of a silo's host partition:
// - The silo host of a hosted silo is the utility VM.
// - The silo host of a silo on a physical host is the physical host.
func HvsockGUIDSiloHost() guid.GUID { // 36bd0c5c-7276-4223-88ba-7d03b654c568
return guid.GUID{
Data1: 0x36bd0c5c,
Data2: 0x7276,
Data3: 0x4223,
Data4: [8]byte{0x88, 0xba, 0x7d, 0x03, 0xb6, 0x54, 0xc5, 0x68},
}
}
// HvsockGUIDChildren is the wildcard VmId for accepting connections from the connector's child partitions.
func HvsockGUIDChildren() guid.GUID { // 90db8b89-0d35-4f79-8ce9-49ea0ac8b7cd
return guid.GUID{
Data1: 0x90db8b89,
Data2: 0xd35,
Data3: 0x4f79,
Data4: [8]uint8{0x8c, 0xe9, 0x49, 0xea, 0xa, 0xc8, 0xb7, 0xcd},
}
}
// HvsockGUIDParent is the wildcard VmId for accepting connections from the connector's parent partition.
// Listening on this VmId accepts connection from:
// - Inside silos: silo host partition.
// - Inside hosted silo: host of the VM.
// - Inside VM: VM host.
// - Physical host: Not supported.
func HvsockGUIDParent() guid.GUID { // a42e7cda-d03f-480c-9cc2-a4de20abb878
return guid.GUID{
Data1: 0xa42e7cda,
Data2: 0xd03f,
Data3: 0x480c,
Data4: [8]uint8{0x9c, 0xc2, 0xa4, 0xde, 0x20, 0xab, 0xb8, 0x78},
}
}
// hvsockVsockServiceTemplate is the Service GUID used for the VSOCK protocol.
func hvsockVsockServiceTemplate() guid.GUID { // 00000000-facb-11e6-bd58-64006a7986d3
return guid.GUID{
Data2: 0xfacb,
Data3: 0x11e6,
Data4: [8]uint8{0xbd, 0x58, 0x64, 0x00, 0x6a, 0x79, 0x86, 0xd3},
}
}
// An HvsockAddr is an address for a AF_HYPERV socket.
type HvsockAddr struct {
@@ -33,8 +108,10 @@ type rawHvsockAddr struct {
ServiceID guid.GUID
}
var _ socket.RawSockaddr = &rawHvsockAddr{}
// Network returns the address's network name, "hvsock".
func (addr *HvsockAddr) Network() string {
func (*HvsockAddr) Network() string {
return "hvsock"
}
@@ -44,14 +121,14 @@ func (addr *HvsockAddr) String() string {
// VsockServiceID returns an hvsock service ID corresponding to the specified AF_VSOCK port.
func VsockServiceID(port uint32) guid.GUID {
g, _ := guid.FromString("00000000-facb-11e6-bd58-64006a7986d3")
g := hvsockVsockServiceTemplate() // make a copy
g.Data1 = port
return g
}
func (addr *HvsockAddr) raw() rawHvsockAddr {
return rawHvsockAddr{
Family: afHvSock,
Family: afHVSock,
VMID: addr.VMID,
ServiceID: addr.ServiceID,
}
@@ -62,26 +139,54 @@ func (addr *HvsockAddr) fromRaw(raw *rawHvsockAddr) {
addr.ServiceID = raw.ServiceID
}
// Sockaddr returns a pointer to and the size of this struct.
//
// Implements the [socket.RawSockaddr] interface, and allows use in
// [socket.Bind] and [socket.ConnectEx].
func (r *rawHvsockAddr) Sockaddr() (unsafe.Pointer, int32, error) {
return unsafe.Pointer(r), int32(unsafe.Sizeof(rawHvsockAddr{})), nil
}
// Sockaddr interface allows use with `sockets.Bind()` and `.ConnectEx()`.
func (r *rawHvsockAddr) FromBytes(b []byte) error {
n := int(unsafe.Sizeof(rawHvsockAddr{}))
if len(b) < n {
return fmt.Errorf("got %d, want %d: %w", len(b), n, socket.ErrBufferSize)
}
copy(unsafe.Slice((*byte)(unsafe.Pointer(r)), n), b[:n])
if r.Family != afHVSock {
return fmt.Errorf("got %d, want %d: %w", r.Family, afHVSock, socket.ErrAddrFamily)
}
return nil
}
// HvsockListener is a socket listener for the AF_HYPERV address family.
type HvsockListener struct {
sock *win32File
addr HvsockAddr
}
var _ net.Listener = &HvsockListener{}
// HvsockConn is a connected socket of the AF_HYPERV address family.
type HvsockConn struct {
sock *win32File
local, remote HvsockAddr
}
func newHvSocket() (*win32File, error) {
fd, err := syscall.Socket(afHvSock, syscall.SOCK_STREAM, 1)
var _ net.Conn = &HvsockConn{}
func newHVSocket() (*win32File, error) {
fd, err := windows.Socket(afHVSock, windows.SOCK_STREAM, 1)
if err != nil {
return nil, os.NewSyscallError("socket", err)
}
f, err := makeWin32File(fd)
if err != nil {
syscall.Close(fd)
windows.Close(fd)
return nil, err
}
f.socket = true
@@ -91,16 +196,24 @@ func newHvSocket() (*win32File, error) {
// ListenHvsock listens for connections on the specified hvsock address.
func ListenHvsock(addr *HvsockAddr) (_ *HvsockListener, err error) {
l := &HvsockListener{addr: *addr}
sock, err := newHvSocket()
var sock *win32File
sock, err = newHVSocket()
if err != nil {
return nil, l.opErr("listen", err)
}
defer func() {
if err != nil {
_ = sock.Close()
}
}()
sa := addr.raw()
err = bind(sock.handle, unsafe.Pointer(&sa), int32(unsafe.Sizeof(sa)))
err = socket.Bind(sock.handle, &sa)
if err != nil {
return nil, l.opErr("listen", os.NewSyscallError("socket", err))
}
err = syscall.Listen(sock.handle, 16)
err = windows.Listen(sock.handle, 16)
if err != nil {
return nil, l.opErr("listen", os.NewSyscallError("listen", err))
}
@@ -118,7 +231,7 @@ func (l *HvsockListener) Addr() net.Addr {
// Accept waits for the next connection and returns it.
func (l *HvsockListener) Accept() (_ net.Conn, err error) {
sock, err := newHvSocket()
sock, err := newHVSocket()
if err != nil {
return nil, l.opErr("accept", err)
}
@@ -127,27 +240,42 @@ func (l *HvsockListener) Accept() (_ net.Conn, err error) {
sock.Close()
}
}()
c, err := l.sock.prepareIo()
c, err := l.sock.prepareIO()
if err != nil {
return nil, l.opErr("accept", err)
}
defer l.sock.wg.Done()
// AcceptEx, per documentation, requires an extra 16 bytes per address.
//
// https://docs.microsoft.com/en-us/windows/win32/api/mswsock/nf-mswsock-acceptex
const addrlen = uint32(16 + unsafe.Sizeof(rawHvsockAddr{}))
var addrbuf [addrlen * 2]byte
var bytes uint32
err = syscall.AcceptEx(l.sock.handle, sock.handle, &addrbuf[0], 0, addrlen, addrlen, &bytes, &c.o)
_, err = l.sock.asyncIo(c, nil, bytes, err)
if err != nil {
err = windows.AcceptEx(l.sock.handle, sock.handle, &addrbuf[0], 0 /* rxdatalen */, addrlen, addrlen, &bytes, &c.o)
if _, err = l.sock.asyncIO(c, nil, bytes, err); err != nil {
return nil, l.opErr("accept", os.NewSyscallError("acceptex", err))
}
conn := &HvsockConn{
sock: sock,
}
// The local address returned in the AcceptEx buffer is the same as the Listener socket's
// address. However, the service GUID reported by GetSockName is different from the Listeners
// socket, and is sometimes the same as the local address of the socket that dialed the
// address, with the service GUID.Data1 incremented, but othertimes is different.
// todo: does the local address matter? is the listener's address or the actual address appropriate?
conn.local.fromRaw((*rawHvsockAddr)(unsafe.Pointer(&addrbuf[0])))
conn.remote.fromRaw((*rawHvsockAddr)(unsafe.Pointer(&addrbuf[addrlen])))
// initialize the accepted socket and update its properties with those of the listening socket
if err = windows.Setsockopt(sock.handle,
windows.SOL_SOCKET, windows.SO_UPDATE_ACCEPT_CONTEXT,
(*byte)(unsafe.Pointer(&l.sock.handle)), int32(unsafe.Sizeof(l.sock.handle))); err != nil {
return nil, conn.opErr("accept", os.NewSyscallError("setsockopt", err))
}
sock = nil
return conn, nil
}
@@ -157,54 +285,183 @@ func (l *HvsockListener) Close() error {
return l.sock.Close()
}
/* Need to finish ConnectEx handling
func DialHvsock(ctx context.Context, addr *HvsockAddr) (*HvsockConn, error) {
sock, err := newHvSocket()
// HvsockDialer configures and dials a Hyper-V Socket (ie, [HvsockConn]).
type HvsockDialer struct {
// Deadline is the time the Dial operation must connect before erroring.
Deadline time.Time
// Retries is the number of additional connects to try if the connection times out, is refused,
// or the host is unreachable
Retries uint
// RetryWait is the time to wait after a connection error to retry
RetryWait time.Duration
rt *time.Timer // redial wait timer
}
// Dial the Hyper-V socket at addr.
//
// See [HvsockDialer.Dial] for more information.
func Dial(ctx context.Context, addr *HvsockAddr) (conn *HvsockConn, err error) {
return (&HvsockDialer{}).Dial(ctx, addr)
}
// Dial attempts to connect to the Hyper-V socket at addr, and returns a connection if successful.
// Will attempt (HvsockDialer).Retries if dialing fails, waiting (HvsockDialer).RetryWait between
// retries.
//
// Dialing can be cancelled either by providing (HvsockDialer).Deadline, or cancelling ctx.
func (d *HvsockDialer) Dial(ctx context.Context, addr *HvsockAddr) (conn *HvsockConn, err error) {
op := "dial"
// create the conn early to use opErr()
conn = &HvsockConn{
remote: *addr,
}
if !d.Deadline.IsZero() {
var cancel context.CancelFunc
ctx, cancel = context.WithDeadline(ctx, d.Deadline)
defer cancel()
}
// preemptive timeout/cancellation check
if err = ctx.Err(); err != nil {
return nil, conn.opErr(op, err)
}
sock, err := newHVSocket()
if err != nil {
return nil, err
return nil, conn.opErr(op, err)
}
defer func() {
if sock != nil {
sock.Close()
}
}()
c, err := sock.prepareIo()
sa := addr.raw()
err = socket.Bind(sock.handle, &sa)
if err != nil {
return nil, err
return nil, conn.opErr(op, os.NewSyscallError("bind", err))
}
c, err := sock.prepareIO()
if err != nil {
return nil, conn.opErr(op, err)
}
defer sock.wg.Done()
var bytes uint32
err = windows.ConnectEx(windows.Handle(sock.handle), sa, nil, 0, &bytes, &c.o)
_, err = sock.asyncIo(ctx, c, nil, bytes, err)
for i := uint(0); i <= d.Retries; i++ {
err = socket.ConnectEx(
sock.handle,
&sa,
nil, // sendBuf
0, // sendDataLen
&bytes,
(*windows.Overlapped)(unsafe.Pointer(&c.o)))
_, err = sock.asyncIO(c, nil, bytes, err)
if i < d.Retries && canRedial(err) {
if err = d.redialWait(ctx); err == nil {
continue
}
}
break
}
if err != nil {
return nil, err
return nil, conn.opErr(op, os.NewSyscallError("connectex", err))
}
conn := &HvsockConn{
sock: sock,
remote: *addr,
// update the connection properties, so shutdown can be used
if err = windows.Setsockopt(
sock.handle,
windows.SOL_SOCKET,
windows.SO_UPDATE_CONNECT_CONTEXT,
nil, // optvalue
0, // optlen
); err != nil {
return nil, conn.opErr(op, os.NewSyscallError("setsockopt", err))
}
// get the local name
var sal rawHvsockAddr
err = socket.GetSockName(sock.handle, &sal)
if err != nil {
return nil, conn.opErr(op, os.NewSyscallError("getsockname", err))
}
conn.local.fromRaw(&sal)
// one last check for timeout, since asyncIO doesn't check the context
if err = ctx.Err(); err != nil {
return nil, conn.opErr(op, err)
}
conn.sock = sock
sock = nil
return conn, nil
}
*/
// redialWait waits before attempting to redial, resetting the timer as appropriate.
func (d *HvsockDialer) redialWait(ctx context.Context) (err error) {
if d.RetryWait == 0 {
return nil
}
if d.rt == nil {
d.rt = time.NewTimer(d.RetryWait)
} else {
// should already be stopped and drained
d.rt.Reset(d.RetryWait)
}
select {
case <-ctx.Done():
case <-d.rt.C:
return nil
}
// stop and drain the timer
if !d.rt.Stop() {
<-d.rt.C
}
return ctx.Err()
}
// assumes error is a plain, unwrapped windows.Errno provided by direct syscall.
func canRedial(err error) bool {
//nolint:errorlint // guaranteed to be an Errno
switch err {
case windows.WSAECONNREFUSED, windows.WSAENETUNREACH, windows.WSAETIMEDOUT,
windows.ERROR_CONNECTION_REFUSED, windows.ERROR_CONNECTION_UNAVAIL:
return true
default:
return false
}
}
func (conn *HvsockConn) opErr(op string, err error) error {
// translate from "file closed" to "socket closed"
if errors.Is(err, ErrFileClosed) {
err = socket.ErrSocketClosed
}
return &net.OpError{Op: op, Net: "hvsock", Source: &conn.local, Addr: &conn.remote, Err: err}
}
func (conn *HvsockConn) Read(b []byte) (int, error) {
c, err := conn.sock.prepareIo()
c, err := conn.sock.prepareIO()
if err != nil {
return 0, conn.opErr("read", err)
}
defer conn.sock.wg.Done()
buf := syscall.WSABuf{Buf: &b[0], Len: uint32(len(b))}
buf := windows.WSABuf{Buf: &b[0], Len: uint32(len(b))}
var flags, bytes uint32
err = syscall.WSARecv(conn.sock.handle, &buf, 1, &bytes, &flags, &c.o, nil)
n, err := conn.sock.asyncIo(c, &conn.sock.readDeadline, bytes, err)
err = windows.WSARecv(conn.sock.handle, &buf, 1, &bytes, &flags, &c.o, nil)
n, err := conn.sock.asyncIO(c, &conn.sock.readDeadline, bytes, err)
if err != nil {
if _, ok := err.(syscall.Errno); ok {
err = os.NewSyscallError("wsarecv", err)
var eno windows.Errno
if errors.As(err, &eno) {
err = os.NewSyscallError("wsarecv", eno)
}
return 0, conn.opErr("read", err)
} else if n == 0 {
@@ -227,18 +484,19 @@ func (conn *HvsockConn) Write(b []byte) (int, error) {
}
func (conn *HvsockConn) write(b []byte) (int, error) {
c, err := conn.sock.prepareIo()
c, err := conn.sock.prepareIO()
if err != nil {
return 0, conn.opErr("write", err)
}
defer conn.sock.wg.Done()
buf := syscall.WSABuf{Buf: &b[0], Len: uint32(len(b))}
buf := windows.WSABuf{Buf: &b[0], Len: uint32(len(b))}
var bytes uint32
err = syscall.WSASend(conn.sock.handle, &buf, 1, &bytes, 0, &c.o, nil)
n, err := conn.sock.asyncIo(c, &conn.sock.writeDeadline, bytes, err)
err = windows.WSASend(conn.sock.handle, &buf, 1, &bytes, 0, &c.o, nil)
n, err := conn.sock.asyncIO(c, &conn.sock.writeDeadline, bytes, err)
if err != nil {
if _, ok := err.(syscall.Errno); ok {
err = os.NewSyscallError("wsasend", err)
var eno windows.Errno
if errors.As(err, &eno) {
err = os.NewSyscallError("wsasend", eno)
}
return 0, conn.opErr("write", err)
}
@@ -250,29 +508,43 @@ func (conn *HvsockConn) Close() error {
return conn.sock.Close()
}
func (conn *HvsockConn) IsClosed() bool {
return conn.sock.IsClosed()
}
// shutdown disables sending or receiving on a socket.
func (conn *HvsockConn) shutdown(how int) error {
err := syscall.Shutdown(conn.sock.handle, syscall.SHUT_RD)
if conn.IsClosed() {
return socket.ErrSocketClosed
}
err := windows.Shutdown(conn.sock.handle, how)
if err != nil {
// If the connection was closed, shutdowns fail with "not connected"
if errors.Is(err, windows.WSAENOTCONN) ||
errors.Is(err, windows.WSAESHUTDOWN) {
err = socket.ErrSocketClosed
}
return os.NewSyscallError("shutdown", err)
}
return nil
}
// CloseRead shuts down the read end of the socket.
// CloseRead shuts down the read end of the socket, preventing future read operations.
func (conn *HvsockConn) CloseRead() error {
err := conn.shutdown(syscall.SHUT_RD)
err := conn.shutdown(windows.SHUT_RD)
if err != nil {
return conn.opErr("close", err)
return conn.opErr("closeread", err)
}
return nil
}
// CloseWrite shuts down the write end of the socket, notifying the other endpoint that
// no more data will be written.
// CloseWrite shuts down the write end of the socket, preventing future write operations and
// notifying the other endpoint that no more data will be written.
func (conn *HvsockConn) CloseWrite() error {
err := conn.shutdown(syscall.SHUT_WR)
err := conn.shutdown(windows.SHUT_WR)
if err != nil {
return conn.opErr("close", err)
return conn.opErr("closewrite", err)
}
return nil
}
@@ -289,8 +561,13 @@ func (conn *HvsockConn) RemoteAddr() net.Addr {
// SetDeadline implements the net.Conn SetDeadline method.
func (conn *HvsockConn) SetDeadline(t time.Time) error {
conn.SetReadDeadline(t)
conn.SetWriteDeadline(t)
// todo: implement `SetDeadline` for `win32File`
if err := conn.SetReadDeadline(t); err != nil {
return fmt.Errorf("set read deadline: %w", err)
}
if err := conn.SetWriteDeadline(t); err != nil {
return fmt.Errorf("set write deadline: %w", err)
}
return nil
}

View File

@@ -0,0 +1,2 @@
// This package contains Win32 filesystem functionality.
package fs

262
vendor/github.com/Microsoft/go-winio/internal/fs/fs.go generated vendored Normal file
View File

@@ -0,0 +1,262 @@
//go:build windows
package fs
import (
"golang.org/x/sys/windows"
"github.com/Microsoft/go-winio/internal/stringbuffer"
)
//go:generate go run github.com/Microsoft/go-winio/tools/mkwinsyscall -output zsyscall_windows.go fs.go
// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew
//sys CreateFile(name string, access AccessMask, mode FileShareMode, sa *windows.SecurityAttributes, createmode FileCreationDisposition, attrs FileFlagOrAttribute, templatefile windows.Handle) (handle windows.Handle, err error) [failretval==windows.InvalidHandle] = CreateFileW
const NullHandle windows.Handle = 0
// AccessMask defines standard, specific, and generic rights.
//
// Used with CreateFile and NtCreateFile (and co.).
//
// Bitmask:
// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
// +---------------+---------------+-------------------------------+
// |G|G|G|G|Resvd|A| StandardRights| SpecificRights |
// |R|W|E|A| |S| | |
// +-+-------------+---------------+-------------------------------+
//
// GR Generic Read
// GW Generic Write
// GE Generic Exectue
// GA Generic All
// Resvd Reserved
// AS Access Security System
//
// https://learn.microsoft.com/en-us/windows/win32/secauthz/access-mask
//
// https://learn.microsoft.com/en-us/windows/win32/secauthz/generic-access-rights
//
// https://learn.microsoft.com/en-us/windows/win32/fileio/file-access-rights-constants
type AccessMask = windows.ACCESS_MASK
//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API.
const (
// Not actually any.
//
// For CreateFile: "query certain metadata such as file, directory, or device attributes without accessing that file or device"
// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew#parameters
FILE_ANY_ACCESS AccessMask = 0
GENERIC_READ AccessMask = 0x8000_0000
GENERIC_WRITE AccessMask = 0x4000_0000
GENERIC_EXECUTE AccessMask = 0x2000_0000
GENERIC_ALL AccessMask = 0x1000_0000
ACCESS_SYSTEM_SECURITY AccessMask = 0x0100_0000
// Specific Object Access
// from ntioapi.h
FILE_READ_DATA AccessMask = (0x0001) // file & pipe
FILE_LIST_DIRECTORY AccessMask = (0x0001) // directory
FILE_WRITE_DATA AccessMask = (0x0002) // file & pipe
FILE_ADD_FILE AccessMask = (0x0002) // directory
FILE_APPEND_DATA AccessMask = (0x0004) // file
FILE_ADD_SUBDIRECTORY AccessMask = (0x0004) // directory
FILE_CREATE_PIPE_INSTANCE AccessMask = (0x0004) // named pipe
FILE_READ_EA AccessMask = (0x0008) // file & directory
FILE_READ_PROPERTIES AccessMask = FILE_READ_EA
FILE_WRITE_EA AccessMask = (0x0010) // file & directory
FILE_WRITE_PROPERTIES AccessMask = FILE_WRITE_EA
FILE_EXECUTE AccessMask = (0x0020) // file
FILE_TRAVERSE AccessMask = (0x0020) // directory
FILE_DELETE_CHILD AccessMask = (0x0040) // directory
FILE_READ_ATTRIBUTES AccessMask = (0x0080) // all
FILE_WRITE_ATTRIBUTES AccessMask = (0x0100) // all
FILE_ALL_ACCESS AccessMask = (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1FF)
FILE_GENERIC_READ AccessMask = (STANDARD_RIGHTS_READ | FILE_READ_DATA | FILE_READ_ATTRIBUTES | FILE_READ_EA | SYNCHRONIZE)
FILE_GENERIC_WRITE AccessMask = (STANDARD_RIGHTS_WRITE | FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | FILE_APPEND_DATA | SYNCHRONIZE)
FILE_GENERIC_EXECUTE AccessMask = (STANDARD_RIGHTS_EXECUTE | FILE_READ_ATTRIBUTES | FILE_EXECUTE | SYNCHRONIZE)
SPECIFIC_RIGHTS_ALL AccessMask = 0x0000FFFF
// Standard Access
// from ntseapi.h
DELETE AccessMask = 0x0001_0000
READ_CONTROL AccessMask = 0x0002_0000
WRITE_DAC AccessMask = 0x0004_0000
WRITE_OWNER AccessMask = 0x0008_0000
SYNCHRONIZE AccessMask = 0x0010_0000
STANDARD_RIGHTS_REQUIRED AccessMask = 0x000F_0000
STANDARD_RIGHTS_READ AccessMask = READ_CONTROL
STANDARD_RIGHTS_WRITE AccessMask = READ_CONTROL
STANDARD_RIGHTS_EXECUTE AccessMask = READ_CONTROL
STANDARD_RIGHTS_ALL AccessMask = 0x001F_0000
)
type FileShareMode uint32
//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API.
const (
FILE_SHARE_NONE FileShareMode = 0x00
FILE_SHARE_READ FileShareMode = 0x01
FILE_SHARE_WRITE FileShareMode = 0x02
FILE_SHARE_DELETE FileShareMode = 0x04
FILE_SHARE_VALID_FLAGS FileShareMode = 0x07
)
type FileCreationDisposition uint32
//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API.
const (
// from winbase.h
CREATE_NEW FileCreationDisposition = 0x01
CREATE_ALWAYS FileCreationDisposition = 0x02
OPEN_EXISTING FileCreationDisposition = 0x03
OPEN_ALWAYS FileCreationDisposition = 0x04
TRUNCATE_EXISTING FileCreationDisposition = 0x05
)
// Create disposition values for NtCreate*
type NTFileCreationDisposition uint32
//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API.
const (
// From ntioapi.h
FILE_SUPERSEDE NTFileCreationDisposition = 0x00
FILE_OPEN NTFileCreationDisposition = 0x01
FILE_CREATE NTFileCreationDisposition = 0x02
FILE_OPEN_IF NTFileCreationDisposition = 0x03
FILE_OVERWRITE NTFileCreationDisposition = 0x04
FILE_OVERWRITE_IF NTFileCreationDisposition = 0x05
FILE_MAXIMUM_DISPOSITION NTFileCreationDisposition = 0x05
)
// CreateFile and co. take flags or attributes together as one parameter.
// Define alias until we can use generics to allow both
//
// https://learn.microsoft.com/en-us/windows/win32/fileio/file-attribute-constants
type FileFlagOrAttribute uint32
//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API.
const (
// from winnt.h
FILE_FLAG_WRITE_THROUGH FileFlagOrAttribute = 0x8000_0000
FILE_FLAG_OVERLAPPED FileFlagOrAttribute = 0x4000_0000
FILE_FLAG_NO_BUFFERING FileFlagOrAttribute = 0x2000_0000
FILE_FLAG_RANDOM_ACCESS FileFlagOrAttribute = 0x1000_0000
FILE_FLAG_SEQUENTIAL_SCAN FileFlagOrAttribute = 0x0800_0000
FILE_FLAG_DELETE_ON_CLOSE FileFlagOrAttribute = 0x0400_0000
FILE_FLAG_BACKUP_SEMANTICS FileFlagOrAttribute = 0x0200_0000
FILE_FLAG_POSIX_SEMANTICS FileFlagOrAttribute = 0x0100_0000
FILE_FLAG_OPEN_REPARSE_POINT FileFlagOrAttribute = 0x0020_0000
FILE_FLAG_OPEN_NO_RECALL FileFlagOrAttribute = 0x0010_0000
FILE_FLAG_FIRST_PIPE_INSTANCE FileFlagOrAttribute = 0x0008_0000
)
// NtCreate* functions take a dedicated CreateOptions parameter.
//
// https://learn.microsoft.com/en-us/windows/win32/api/Winternl/nf-winternl-ntcreatefile
//
// https://learn.microsoft.com/en-us/windows/win32/devnotes/nt-create-named-pipe-file
type NTCreateOptions uint32
//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API.
const (
// From ntioapi.h
FILE_DIRECTORY_FILE NTCreateOptions = 0x0000_0001
FILE_WRITE_THROUGH NTCreateOptions = 0x0000_0002
FILE_SEQUENTIAL_ONLY NTCreateOptions = 0x0000_0004
FILE_NO_INTERMEDIATE_BUFFERING NTCreateOptions = 0x0000_0008
FILE_SYNCHRONOUS_IO_ALERT NTCreateOptions = 0x0000_0010
FILE_SYNCHRONOUS_IO_NONALERT NTCreateOptions = 0x0000_0020
FILE_NON_DIRECTORY_FILE NTCreateOptions = 0x0000_0040
FILE_CREATE_TREE_CONNECTION NTCreateOptions = 0x0000_0080
FILE_COMPLETE_IF_OPLOCKED NTCreateOptions = 0x0000_0100
FILE_NO_EA_KNOWLEDGE NTCreateOptions = 0x0000_0200
FILE_DISABLE_TUNNELING NTCreateOptions = 0x0000_0400
FILE_RANDOM_ACCESS NTCreateOptions = 0x0000_0800
FILE_DELETE_ON_CLOSE NTCreateOptions = 0x0000_1000
FILE_OPEN_BY_FILE_ID NTCreateOptions = 0x0000_2000
FILE_OPEN_FOR_BACKUP_INTENT NTCreateOptions = 0x0000_4000
FILE_NO_COMPRESSION NTCreateOptions = 0x0000_8000
)
type FileSQSFlag = FileFlagOrAttribute
//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API.
const (
// from winbase.h
SECURITY_ANONYMOUS FileSQSFlag = FileSQSFlag(SecurityAnonymous << 16)
SECURITY_IDENTIFICATION FileSQSFlag = FileSQSFlag(SecurityIdentification << 16)
SECURITY_IMPERSONATION FileSQSFlag = FileSQSFlag(SecurityImpersonation << 16)
SECURITY_DELEGATION FileSQSFlag = FileSQSFlag(SecurityDelegation << 16)
SECURITY_SQOS_PRESENT FileSQSFlag = 0x0010_0000
SECURITY_VALID_SQOS_FLAGS FileSQSFlag = 0x001F_0000
)
// GetFinalPathNameByHandle flags
//
// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfinalpathnamebyhandlew#parameters
type GetFinalPathFlag uint32
//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API.
const (
GetFinalPathDefaultFlag GetFinalPathFlag = 0x0
FILE_NAME_NORMALIZED GetFinalPathFlag = 0x0
FILE_NAME_OPENED GetFinalPathFlag = 0x8
VOLUME_NAME_DOS GetFinalPathFlag = 0x0
VOLUME_NAME_GUID GetFinalPathFlag = 0x1
VOLUME_NAME_NT GetFinalPathFlag = 0x2
VOLUME_NAME_NONE GetFinalPathFlag = 0x4
)
// getFinalPathNameByHandle facilitates calling the Windows API GetFinalPathNameByHandle
// with the given handle and flags. It transparently takes care of creating a buffer of the
// correct size for the call.
//
// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfinalpathnamebyhandlew
func GetFinalPathNameByHandle(h windows.Handle, flags GetFinalPathFlag) (string, error) {
b := stringbuffer.NewWString()
//TODO: can loop infinitely if Win32 keeps returning the same (or a larger) n?
for {
n, err := windows.GetFinalPathNameByHandle(h, b.Pointer(), b.Cap(), uint32(flags))
if err != nil {
return "", err
}
// If the buffer wasn't large enough, n will be the total size needed (including null terminator).
// Resize and try again.
if n > b.Cap() {
b.ResizeTo(n)
continue
}
// If the buffer is large enough, n will be the size not including the null terminator.
// Convert to a Go string and return.
return b.String(), nil
}
}

View File

@@ -0,0 +1,12 @@
package fs
// https://learn.microsoft.com/en-us/windows/win32/api/winnt/ne-winnt-security_impersonation_level
type SecurityImpersonationLevel int32 // C default enums underlying type is `int`, which is Go `int32`
// Impersonation levels
const (
SecurityAnonymous SecurityImpersonationLevel = 0
SecurityIdentification SecurityImpersonationLevel = 1
SecurityImpersonation SecurityImpersonationLevel = 2
SecurityDelegation SecurityImpersonationLevel = 3
)

View File

@@ -0,0 +1,61 @@
//go:build windows
// Code generated by 'go generate' using "github.com/Microsoft/go-winio/tools/mkwinsyscall"; DO NOT EDIT.
package fs
import (
"syscall"
"unsafe"
"golang.org/x/sys/windows"
)
var _ unsafe.Pointer
// Do the interface allocations only once for common
// Errno values.
const (
errnoERROR_IO_PENDING = 997
)
var (
errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
errERROR_EINVAL error = syscall.EINVAL
)
// errnoErr returns common boxed Errno values, to prevent
// allocations at runtime.
func errnoErr(e syscall.Errno) error {
switch e {
case 0:
return errERROR_EINVAL
case errnoERROR_IO_PENDING:
return errERROR_IO_PENDING
}
return e
}
var (
modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
procCreateFileW = modkernel32.NewProc("CreateFileW")
)
func CreateFile(name string, access AccessMask, mode FileShareMode, sa *windows.SecurityAttributes, createmode FileCreationDisposition, attrs FileFlagOrAttribute, templatefile windows.Handle) (handle windows.Handle, err error) {
var _p0 *uint16
_p0, err = syscall.UTF16PtrFromString(name)
if err != nil {
return
}
return _CreateFile(_p0, access, mode, sa, createmode, attrs, templatefile)
}
func _CreateFile(name *uint16, access AccessMask, mode FileShareMode, sa *windows.SecurityAttributes, createmode FileCreationDisposition, attrs FileFlagOrAttribute, templatefile windows.Handle) (handle windows.Handle, err error) {
r0, _, e1 := syscall.SyscallN(procCreateFileW.Addr(), uintptr(unsafe.Pointer(name)), uintptr(access), uintptr(mode), uintptr(unsafe.Pointer(sa)), uintptr(createmode), uintptr(attrs), uintptr(templatefile))
handle = windows.Handle(r0)
if handle == windows.InvalidHandle {
err = errnoErr(e1)
}
return
}

View File

@@ -0,0 +1,20 @@
package socket
import (
"unsafe"
)
// RawSockaddr allows structs to be used with [Bind] and [ConnectEx]. The
// struct must meet the Win32 sockaddr requirements specified here:
// https://docs.microsoft.com/en-us/windows/win32/winsock/sockaddr-2
//
// Specifically, the struct size must be least larger than an int16 (unsigned short)
// for the address family.
type RawSockaddr interface {
// Sockaddr returns a pointer to the RawSockaddr and its struct size, allowing
// for the RawSockaddr's data to be overwritten by syscalls (if necessary).
//
// It is the callers responsibility to validate that the values are valid; invalid
// pointers or size can cause a panic.
Sockaddr() (unsafe.Pointer, int32, error)
}

View File

@@ -0,0 +1,177 @@
//go:build windows
package socket
import (
"errors"
"fmt"
"net"
"sync"
"syscall"
"unsafe"
"github.com/Microsoft/go-winio/pkg/guid"
"golang.org/x/sys/windows"
)
//go:generate go run github.com/Microsoft/go-winio/tools/mkwinsyscall -output zsyscall_windows.go socket.go
//sys getsockname(s windows.Handle, name unsafe.Pointer, namelen *int32) (err error) [failretval==socketError] = ws2_32.getsockname
//sys getpeername(s windows.Handle, name unsafe.Pointer, namelen *int32) (err error) [failretval==socketError] = ws2_32.getpeername
//sys bind(s windows.Handle, name unsafe.Pointer, namelen int32) (err error) [failretval==socketError] = ws2_32.bind
const socketError = uintptr(^uint32(0))
var (
// todo(helsaawy): create custom error types to store the desired vs actual size and addr family?
ErrBufferSize = errors.New("buffer size")
ErrAddrFamily = errors.New("address family")
ErrInvalidPointer = errors.New("invalid pointer")
ErrSocketClosed = fmt.Errorf("socket closed: %w", net.ErrClosed)
)
// todo(helsaawy): replace these with generics, ie: GetSockName[S RawSockaddr](s windows.Handle) (S, error)
// GetSockName writes the local address of socket s to the [RawSockaddr] rsa.
// If rsa is not large enough, the [windows.WSAEFAULT] is returned.
func GetSockName(s windows.Handle, rsa RawSockaddr) error {
ptr, l, err := rsa.Sockaddr()
if err != nil {
return fmt.Errorf("could not retrieve socket pointer and size: %w", err)
}
// although getsockname returns WSAEFAULT if the buffer is too small, it does not set
// &l to the correct size, so--apart from doubling the buffer repeatedly--there is no remedy
return getsockname(s, ptr, &l)
}
// GetPeerName returns the remote address the socket is connected to.
//
// See [GetSockName] for more information.
func GetPeerName(s windows.Handle, rsa RawSockaddr) error {
ptr, l, err := rsa.Sockaddr()
if err != nil {
return fmt.Errorf("could not retrieve socket pointer and size: %w", err)
}
return getpeername(s, ptr, &l)
}
func Bind(s windows.Handle, rsa RawSockaddr) (err error) {
ptr, l, err := rsa.Sockaddr()
if err != nil {
return fmt.Errorf("could not retrieve socket pointer and size: %w", err)
}
return bind(s, ptr, l)
}
// "golang.org/x/sys/windows".ConnectEx and .Bind only accept internal implementations of the
// their sockaddr interface, so they cannot be used with HvsockAddr
// Replicate functionality here from
// https://cs.opensource.google/go/x/sys/+/master:windows/syscall_windows.go
// The function pointers to `AcceptEx`, `ConnectEx` and `GetAcceptExSockaddrs` must be loaded at
// runtime via a WSAIoctl call:
// https://docs.microsoft.com/en-us/windows/win32/api/Mswsock/nc-mswsock-lpfn_connectex#remarks
type runtimeFunc struct {
id guid.GUID
once sync.Once
addr uintptr
err error
}
func (f *runtimeFunc) Load() error {
f.once.Do(func() {
var s windows.Handle
s, f.err = windows.Socket(windows.AF_INET, windows.SOCK_STREAM, windows.IPPROTO_TCP)
if f.err != nil {
return
}
defer windows.CloseHandle(s) //nolint:errcheck
var n uint32
f.err = windows.WSAIoctl(s,
windows.SIO_GET_EXTENSION_FUNCTION_POINTER,
(*byte)(unsafe.Pointer(&f.id)),
uint32(unsafe.Sizeof(f.id)),
(*byte)(unsafe.Pointer(&f.addr)),
uint32(unsafe.Sizeof(f.addr)),
&n,
nil, // overlapped
0, // completionRoutine
)
})
return f.err
}
var (
// todo: add `AcceptEx` and `GetAcceptExSockaddrs`
WSAID_CONNECTEX = guid.GUID{ //revive:disable-line:var-naming ALL_CAPS
Data1: 0x25a207b9,
Data2: 0xddf3,
Data3: 0x4660,
Data4: [8]byte{0x8e, 0xe9, 0x76, 0xe5, 0x8c, 0x74, 0x06, 0x3e},
}
connectExFunc = runtimeFunc{id: WSAID_CONNECTEX}
)
func ConnectEx(
fd windows.Handle,
rsa RawSockaddr,
sendBuf *byte,
sendDataLen uint32,
bytesSent *uint32,
overlapped *windows.Overlapped,
) error {
if err := connectExFunc.Load(); err != nil {
return fmt.Errorf("failed to load ConnectEx function pointer: %w", err)
}
ptr, n, err := rsa.Sockaddr()
if err != nil {
return err
}
return connectEx(fd, ptr, n, sendBuf, sendDataLen, bytesSent, overlapped)
}
// BOOL LpfnConnectex(
// [in] SOCKET s,
// [in] const sockaddr *name,
// [in] int namelen,
// [in, optional] PVOID lpSendBuffer,
// [in] DWORD dwSendDataLength,
// [out] LPDWORD lpdwBytesSent,
// [in] LPOVERLAPPED lpOverlapped
// )
func connectEx(
s windows.Handle,
name unsafe.Pointer,
namelen int32,
sendBuf *byte,
sendDataLen uint32,
bytesSent *uint32,
overlapped *windows.Overlapped,
) (err error) {
r1, _, e1 := syscall.SyscallN(connectExFunc.addr,
uintptr(s),
uintptr(name),
uintptr(namelen),
uintptr(unsafe.Pointer(sendBuf)),
uintptr(sendDataLen),
uintptr(unsafe.Pointer(bytesSent)),
uintptr(unsafe.Pointer(overlapped)),
)
if r1 == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return err
}

View File

@@ -0,0 +1,69 @@
//go:build windows
// Code generated by 'go generate' using "github.com/Microsoft/go-winio/tools/mkwinsyscall"; DO NOT EDIT.
package socket
import (
"syscall"
"unsafe"
"golang.org/x/sys/windows"
)
var _ unsafe.Pointer
// Do the interface allocations only once for common
// Errno values.
const (
errnoERROR_IO_PENDING = 997
)
var (
errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
errERROR_EINVAL error = syscall.EINVAL
)
// errnoErr returns common boxed Errno values, to prevent
// allocations at runtime.
func errnoErr(e syscall.Errno) error {
switch e {
case 0:
return errERROR_EINVAL
case errnoERROR_IO_PENDING:
return errERROR_IO_PENDING
}
return e
}
var (
modws2_32 = windows.NewLazySystemDLL("ws2_32.dll")
procbind = modws2_32.NewProc("bind")
procgetpeername = modws2_32.NewProc("getpeername")
procgetsockname = modws2_32.NewProc("getsockname")
)
func bind(s windows.Handle, name unsafe.Pointer, namelen int32) (err error) {
r1, _, e1 := syscall.SyscallN(procbind.Addr(), uintptr(s), uintptr(name), uintptr(namelen))
if r1 == socketError {
err = errnoErr(e1)
}
return
}
func getpeername(s windows.Handle, name unsafe.Pointer, namelen *int32) (err error) {
r1, _, e1 := syscall.SyscallN(procgetpeername.Addr(), uintptr(s), uintptr(name), uintptr(unsafe.Pointer(namelen)))
if r1 == socketError {
err = errnoErr(e1)
}
return
}
func getsockname(s windows.Handle, name unsafe.Pointer, namelen *int32) (err error) {
r1, _, e1 := syscall.SyscallN(procgetsockname.Addr(), uintptr(s), uintptr(name), uintptr(unsafe.Pointer(namelen)))
if r1 == socketError {
err = errnoErr(e1)
}
return
}

View File

@@ -0,0 +1,132 @@
package stringbuffer
import (
"sync"
"unicode/utf16"
)
// TODO: worth exporting and using in mkwinsyscall?
// Uint16BufferSize is the buffer size in the pool, chosen somewhat arbitrarily to accommodate
// large path strings:
// MAX_PATH (260) + size of volume GUID prefix (49) + null terminator = 310.
const MinWStringCap = 310
// use *[]uint16 since []uint16 creates an extra allocation where the slice header
// is copied to heap and then referenced via pointer in the interface header that sync.Pool
// stores.
var pathPool = sync.Pool{ // if go1.18+ adds Pool[T], use that to store []uint16 directly
New: func() interface{} {
b := make([]uint16, MinWStringCap)
return &b
},
}
func newBuffer() []uint16 { return *(pathPool.Get().(*[]uint16)) }
// freeBuffer copies the slice header data, and puts a pointer to that in the pool.
// This avoids taking a pointer to the slice header in WString, which can be set to nil.
func freeBuffer(b []uint16) { pathPool.Put(&b) }
// WString is a wide string buffer ([]uint16) meant for storing UTF-16 encoded strings
// for interacting with Win32 APIs.
// Sizes are specified as uint32 and not int.
//
// It is not thread safe.
type WString struct {
// type-def allows casting to []uint16 directly, use struct to prevent that and allow adding fields in the future.
// raw buffer
b []uint16
}
// NewWString returns a [WString] allocated from a shared pool with an
// initial capacity of at least [MinWStringCap].
// Since the buffer may have been previously used, its contents are not guaranteed to be empty.
//
// The buffer should be freed via [WString.Free]
func NewWString() *WString {
return &WString{
b: newBuffer(),
}
}
func (b *WString) Free() {
if b.empty() {
return
}
freeBuffer(b.b)
b.b = nil
}
// ResizeTo grows the buffer to at least c and returns the new capacity, freeing the
// previous buffer back into pool.
func (b *WString) ResizeTo(c uint32) uint32 {
// already sufficient (or n is 0)
if c <= b.Cap() {
return b.Cap()
}
if c <= MinWStringCap {
c = MinWStringCap
}
// allocate at-least double buffer size, as is done in [bytes.Buffer] and other places
if c <= 2*b.Cap() {
c = 2 * b.Cap()
}
b2 := make([]uint16, c)
if !b.empty() {
copy(b2, b.b)
freeBuffer(b.b)
}
b.b = b2
return c
}
// Buffer returns the underlying []uint16 buffer.
func (b *WString) Buffer() []uint16 {
if b.empty() {
return nil
}
return b.b
}
// Pointer returns a pointer to the first uint16 in the buffer.
// If the [WString.Free] has already been called, the pointer will be nil.
func (b *WString) Pointer() *uint16 {
if b.empty() {
return nil
}
return &b.b[0]
}
// String returns the returns the UTF-8 encoding of the UTF-16 string in the buffer.
//
// It assumes that the data is null-terminated.
func (b *WString) String() string {
// Using [windows.UTF16ToString] would require importing "golang.org/x/sys/windows"
// and would make this code Windows-only, which makes no sense.
// So copy UTF16ToString code into here.
// If other windows-specific code is added, switch to [windows.UTF16ToString]
s := b.b
for i, v := range s {
if v == 0 {
s = s[:i]
break
}
}
return string(utf16.Decode(s))
}
// Cap returns the underlying buffer capacity.
func (b *WString) Cap() uint32 {
if b.empty() {
return 0
}
return b.cap()
}
func (b *WString) cap() uint32 { return uint32(cap(b.b)) }
func (b *WString) empty() bool { return b == nil || b.cap() == 0 }

View File

@@ -1,3 +1,4 @@
//go:build windows
// +build windows
package winio
@@ -10,26 +11,52 @@ import (
"net"
"os"
"runtime"
"syscall"
"time"
"unsafe"
"golang.org/x/sys/windows"
"github.com/Microsoft/go-winio/internal/fs"
)
//sys connectNamedPipe(pipe syscall.Handle, o *syscall.Overlapped) (err error) = ConnectNamedPipe
//sys createNamedPipe(name string, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *syscall.SecurityAttributes) (handle syscall.Handle, err error) [failretval==syscall.InvalidHandle] = CreateNamedPipeW
//sys createFile(name string, access uint32, mode uint32, sa *syscall.SecurityAttributes, createmode uint32, attrs uint32, templatefile syscall.Handle) (handle syscall.Handle, err error) [failretval==syscall.InvalidHandle] = CreateFileW
//sys getNamedPipeInfo(pipe syscall.Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error) = GetNamedPipeInfo
//sys getNamedPipeHandleState(pipe syscall.Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) = GetNamedPipeHandleStateW
//sys localAlloc(uFlags uint32, length uint32) (ptr uintptr) = LocalAlloc
//sys ntCreateNamedPipeFile(pipe *syscall.Handle, access uint32, oa *objectAttributes, iosb *ioStatusBlock, share uint32, disposition uint32, options uint32, typ uint32, readMode uint32, completionMode uint32, maxInstances uint32, inboundQuota uint32, outputQuota uint32, timeout *int64) (status ntstatus) = ntdll.NtCreateNamedPipeFile
//sys rtlNtStatusToDosError(status ntstatus) (winerr error) = ntdll.RtlNtStatusToDosErrorNoTeb
//sys rtlDosPathNameToNtPathName(name *uint16, ntName *unicodeString, filePart uintptr, reserved uintptr) (status ntstatus) = ntdll.RtlDosPathNameToNtPathName_U
//sys rtlDefaultNpAcl(dacl *uintptr) (status ntstatus) = ntdll.RtlDefaultNpAcl
//sys connectNamedPipe(pipe windows.Handle, o *windows.Overlapped) (err error) = ConnectNamedPipe
//sys createNamedPipe(name string, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *windows.SecurityAttributes) (handle windows.Handle, err error) [failretval==windows.InvalidHandle] = CreateNamedPipeW
//sys disconnectNamedPipe(pipe windows.Handle) (err error) = DisconnectNamedPipe
//sys getNamedPipeInfo(pipe windows.Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error) = GetNamedPipeInfo
//sys getNamedPipeHandleState(pipe windows.Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) = GetNamedPipeHandleStateW
//sys ntCreateNamedPipeFile(pipe *windows.Handle, access ntAccessMask, oa *objectAttributes, iosb *ioStatusBlock, share ntFileShareMode, disposition ntFileCreationDisposition, options ntFileOptions, typ uint32, readMode uint32, completionMode uint32, maxInstances uint32, inboundQuota uint32, outputQuota uint32, timeout *int64) (status ntStatus) = ntdll.NtCreateNamedPipeFile
//sys rtlNtStatusToDosError(status ntStatus) (winerr error) = ntdll.RtlNtStatusToDosErrorNoTeb
//sys rtlDosPathNameToNtPathName(name *uint16, ntName *unicodeString, filePart uintptr, reserved uintptr) (status ntStatus) = ntdll.RtlDosPathNameToNtPathName_U
//sys rtlDefaultNpAcl(dacl *uintptr) (status ntStatus) = ntdll.RtlDefaultNpAcl
type PipeConn interface {
net.Conn
Disconnect() error
Flush() error
}
// type aliases for mkwinsyscall code
type (
ntAccessMask = fs.AccessMask
ntFileShareMode = fs.FileShareMode
ntFileCreationDisposition = fs.NTFileCreationDisposition
ntFileOptions = fs.NTCreateOptions
)
type ioStatusBlock struct {
Status, Information uintptr
}
// typedef struct _OBJECT_ATTRIBUTES {
// ULONG Length;
// HANDLE RootDirectory;
// PUNICODE_STRING ObjectName;
// ULONG Attributes;
// PVOID SecurityDescriptor;
// PVOID SecurityQualityOfService;
// } OBJECT_ATTRIBUTES;
//
// https://learn.microsoft.com/en-us/windows/win32/api/ntdef/ns-ntdef-_object_attributes
type objectAttributes struct {
Length uintptr
RootDirectory uintptr
@@ -45,51 +72,39 @@ type unicodeString struct {
Buffer uintptr
}
// typedef struct _SECURITY_DESCRIPTOR {
// BYTE Revision;
// BYTE Sbz1;
// SECURITY_DESCRIPTOR_CONTROL Control;
// PSID Owner;
// PSID Group;
// PACL Sacl;
// PACL Dacl;
// } SECURITY_DESCRIPTOR, *PISECURITY_DESCRIPTOR;
//
// https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-security_descriptor
type securityDescriptor struct {
Revision byte
Sbz1 byte
Control uint16
Owner uintptr
Group uintptr
Sacl uintptr
Dacl uintptr
Sacl uintptr //revive:disable-line:var-naming SACL, not Sacl
Dacl uintptr //revive:disable-line:var-naming DACL, not Dacl
}
type ntstatus int32
type ntStatus int32
func (status ntstatus) Err() error {
func (status ntStatus) Err() error {
if status >= 0 {
return nil
}
return rtlNtStatusToDosError(status)
}
const (
cERROR_PIPE_BUSY = syscall.Errno(231)
cERROR_NO_DATA = syscall.Errno(232)
cERROR_PIPE_CONNECTED = syscall.Errno(535)
cERROR_SEM_TIMEOUT = syscall.Errno(121)
cSECURITY_SQOS_PRESENT = 0x100000
cSECURITY_ANONYMOUS = 0
cPIPE_TYPE_MESSAGE = 4
cPIPE_READMODE_MESSAGE = 2
cFILE_OPEN = 1
cFILE_CREATE = 2
cFILE_PIPE_MESSAGE_TYPE = 1
cFILE_PIPE_REJECT_REMOTE_CLIENTS = 2
cSE_DACL_PRESENT = 4
)
var (
// ErrPipeListenerClosed is returned for pipe operations on listeners that have been closed.
// This error should match net.errClosing since docker takes a dependency on its text.
ErrPipeListenerClosed = errors.New("use of closed network connection")
ErrPipeListenerClosed = net.ErrClosed
errPipeWriteClosed = errors.New("pipe has been closed for write")
)
@@ -99,6 +114,8 @@ type win32Pipe struct {
path string
}
var _ PipeConn = (*win32Pipe)(nil)
type win32MessageBytePipe struct {
win32Pipe
writeClosed bool
@@ -116,9 +133,14 @@ func (f *win32Pipe) RemoteAddr() net.Addr {
}
func (f *win32Pipe) SetDeadline(t time.Time) error {
f.SetReadDeadline(t)
f.SetWriteDeadline(t)
return nil
if err := f.SetReadDeadline(t); err != nil {
return err
}
return f.SetWriteDeadline(t)
}
func (f *win32Pipe) Disconnect() error {
return disconnectNamedPipe(f.win32File.handle)
}
// CloseWrite closes the write side of a message pipe in byte mode.
@@ -157,14 +179,14 @@ func (f *win32MessageBytePipe) Read(b []byte) (int, error) {
return 0, io.EOF
}
n, err := f.win32File.Read(b)
if err == io.EOF {
if err == io.EOF { //nolint:errorlint
// If this was the result of a zero-byte read, then
// it is possible that the read was due to a zero-size
// message. Since we are simulating CloseWrite with a
// zero-byte message, ensure that all future Read() calls
// also return EOF.
f.readEOF = true
} else if err == syscall.ERROR_MORE_DATA {
} else if err == windows.ERROR_MORE_DATA { //nolint:errorlint // err is Errno
// ERROR_MORE_DATA indicates that the pipe's read mode is message mode
// and the message still has more bytes. Treat this as a success, since
// this package presents all named pipes as byte streams.
@@ -173,7 +195,7 @@ func (f *win32MessageBytePipe) Read(b []byte) (int, error) {
return n, err
}
func (s pipeAddress) Network() string {
func (pipeAddress) Network() string {
return "pipe"
}
@@ -182,18 +204,24 @@ func (s pipeAddress) String() string {
}
// tryDialPipe attempts to dial the pipe at `path` until `ctx` cancellation or timeout.
func tryDialPipe(ctx context.Context, path *string, access uint32) (syscall.Handle, error) {
func tryDialPipe(ctx context.Context, path *string, access fs.AccessMask, impLevel PipeImpLevel) (windows.Handle, error) {
for {
select {
case <-ctx.Done():
return syscall.Handle(0), ctx.Err()
return windows.Handle(0), ctx.Err()
default:
h, err := createFile(*path, access, 0, nil, syscall.OPEN_EXISTING, syscall.FILE_FLAG_OVERLAPPED|cSECURITY_SQOS_PRESENT|cSECURITY_ANONYMOUS, 0)
h, err := fs.CreateFile(*path,
access,
0, // mode
nil, // security attributes
fs.OPEN_EXISTING,
fs.FILE_FLAG_OVERLAPPED|fs.SECURITY_SQOS_PRESENT|fs.FileSQSFlag(impLevel),
0, // template file handle
)
if err == nil {
return h, nil
}
if err != cERROR_PIPE_BUSY {
if err != windows.ERROR_PIPE_BUSY { //nolint:errorlint // err is Errno
return h, &os.PathError{Err: err, Op: "open", Path: *path}
}
// Wait 10 msec and try again. This is a rather simplistic
@@ -213,9 +241,10 @@ func DialPipe(path string, timeout *time.Duration) (net.Conn, error) {
} else {
absTimeout = time.Now().Add(2 * time.Second)
}
ctx, _ := context.WithDeadline(context.Background(), absTimeout)
ctx, cancel := context.WithDeadline(context.Background(), absTimeout)
defer cancel()
conn, err := DialPipeContext(ctx, path)
if err == context.DeadlineExceeded {
if errors.Is(err, context.DeadlineExceeded) {
return nil, ErrTimeout
}
return conn, err
@@ -224,15 +253,33 @@ func DialPipe(path string, timeout *time.Duration) (net.Conn, error) {
// DialPipeContext attempts to connect to a named pipe by `path` until `ctx`
// cancellation or timeout.
func DialPipeContext(ctx context.Context, path string) (net.Conn, error) {
return DialPipeAccess(ctx, path, syscall.GENERIC_READ|syscall.GENERIC_WRITE)
return DialPipeAccess(ctx, path, uint32(fs.GENERIC_READ|fs.GENERIC_WRITE))
}
// PipeImpLevel is an enumeration of impersonation levels that may be set
// when calling DialPipeAccessImpersonation.
type PipeImpLevel uint32
const (
PipeImpLevelAnonymous = PipeImpLevel(fs.SECURITY_ANONYMOUS)
PipeImpLevelIdentification = PipeImpLevel(fs.SECURITY_IDENTIFICATION)
PipeImpLevelImpersonation = PipeImpLevel(fs.SECURITY_IMPERSONATION)
PipeImpLevelDelegation = PipeImpLevel(fs.SECURITY_DELEGATION)
)
// DialPipeAccess attempts to connect to a named pipe by `path` with `access` until `ctx`
// cancellation or timeout.
func DialPipeAccess(ctx context.Context, path string, access uint32) (net.Conn, error) {
return DialPipeAccessImpLevel(ctx, path, access, PipeImpLevelAnonymous)
}
// DialPipeAccessImpLevel attempts to connect to a named pipe by `path` with
// `access` at `impLevel` until `ctx` cancellation or timeout. The other
// DialPipe* implementations use PipeImpLevelAnonymous.
func DialPipeAccessImpLevel(ctx context.Context, path string, access uint32, impLevel PipeImpLevel) (net.Conn, error) {
var err error
var h syscall.Handle
h, err = tryDialPipe(ctx, &path, access)
var h windows.Handle
h, err = tryDialPipe(ctx, &path, fs.AccessMask(access), impLevel)
if err != nil {
return nil, err
}
@@ -245,13 +292,13 @@ func DialPipeAccess(ctx context.Context, path string, access uint32) (net.Conn,
f, err := makeWin32File(h)
if err != nil {
syscall.Close(h)
windows.Close(h)
return nil, err
}
// If the pipe is in message mode, return a message byte pipe, which
// supports CloseWrite().
if flags&cPIPE_TYPE_MESSAGE != 0 {
if flags&windows.PIPE_TYPE_MESSAGE != 0 {
return &win32MessageBytePipe{
win32Pipe: win32Pipe{win32File: f, path: path},
}, nil
@@ -265,7 +312,7 @@ type acceptResponse struct {
}
type win32PipeListener struct {
firstHandle syscall.Handle
firstHandle windows.Handle
path string
config PipeConfig
acceptCh chan (chan acceptResponse)
@@ -273,8 +320,8 @@ type win32PipeListener struct {
doneCh chan int
}
func makeServerPipeHandle(path string, sd []byte, c *PipeConfig, first bool) (syscall.Handle, error) {
path16, err := syscall.UTF16FromString(path)
func makeServerPipeHandle(path string, sd []byte, c *PipeConfig, first bool) (windows.Handle, error) {
path16, err := windows.UTF16FromString(path)
if err != nil {
return 0, &os.PathError{Op: "open", Path: path, Err: err}
}
@@ -283,59 +330,81 @@ func makeServerPipeHandle(path string, sd []byte, c *PipeConfig, first bool) (sy
oa.Length = unsafe.Sizeof(oa)
var ntPath unicodeString
if err := rtlDosPathNameToNtPathName(&path16[0], &ntPath, 0, 0).Err(); err != nil {
if err := rtlDosPathNameToNtPathName(&path16[0],
&ntPath,
0,
0,
).Err(); err != nil {
return 0, &os.PathError{Op: "open", Path: path, Err: err}
}
defer localFree(ntPath.Buffer)
defer windows.LocalFree(windows.Handle(ntPath.Buffer)) //nolint:errcheck
oa.ObjectName = &ntPath
oa.Attributes = windows.OBJ_CASE_INSENSITIVE
// The security descriptor is only needed for the first pipe.
if first {
if sd != nil {
len := uint32(len(sd))
sdb := localAlloc(0, len)
defer localFree(sdb)
//todo: does `sdb` need to be allocated on the heap, or can go allocate it?
l := uint32(len(sd))
sdb, err := windows.LocalAlloc(0, l)
if err != nil {
return 0, fmt.Errorf("LocalAlloc for security descriptor with of length %d: %w", l, err)
}
defer windows.LocalFree(windows.Handle(sdb)) //nolint:errcheck
copy((*[0xffff]byte)(unsafe.Pointer(sdb))[:], sd)
oa.SecurityDescriptor = (*securityDescriptor)(unsafe.Pointer(sdb))
} else {
// Construct the default named pipe security descriptor.
var dacl uintptr
if err := rtlDefaultNpAcl(&dacl).Err(); err != nil {
return 0, fmt.Errorf("getting default named pipe ACL: %s", err)
return 0, fmt.Errorf("getting default named pipe ACL: %w", err)
}
defer localFree(dacl)
defer windows.LocalFree(windows.Handle(dacl)) //nolint:errcheck
sdb := &securityDescriptor{
Revision: 1,
Control: cSE_DACL_PRESENT,
Control: windows.SE_DACL_PRESENT,
Dacl: dacl,
}
oa.SecurityDescriptor = sdb
}
}
typ := uint32(cFILE_PIPE_REJECT_REMOTE_CLIENTS)
typ := uint32(windows.FILE_PIPE_REJECT_REMOTE_CLIENTS)
if c.MessageMode {
typ |= cFILE_PIPE_MESSAGE_TYPE
typ |= windows.FILE_PIPE_MESSAGE_TYPE
}
disposition := uint32(cFILE_OPEN)
access := uint32(syscall.GENERIC_READ | syscall.GENERIC_WRITE | syscall.SYNCHRONIZE)
disposition := fs.FILE_OPEN
access := fs.GENERIC_READ | fs.GENERIC_WRITE | fs.SYNCHRONIZE
if first {
disposition = cFILE_CREATE
disposition = fs.FILE_CREATE
// By not asking for read or write access, the named pipe file system
// will put this pipe into an initially disconnected state, blocking
// client connections until the next call with first == false.
access = syscall.SYNCHRONIZE
access = fs.SYNCHRONIZE
}
timeout := int64(-50 * 10000) // 50ms
var (
h syscall.Handle
h windows.Handle
iosb ioStatusBlock
)
err = ntCreateNamedPipeFile(&h, access, &oa, &iosb, syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE, disposition, 0, typ, 0, 0, 0xffffffff, uint32(c.InputBufferSize), uint32(c.OutputBufferSize), &timeout).Err()
err = ntCreateNamedPipeFile(&h,
access,
&oa,
&iosb,
fs.FILE_SHARE_READ|fs.FILE_SHARE_WRITE,
disposition,
0,
typ,
0,
0,
0xffffffff,
uint32(c.InputBufferSize),
uint32(c.OutputBufferSize),
&timeout).Err()
if err != nil {
return 0, &os.PathError{Op: "open", Path: path, Err: err}
}
@@ -351,7 +420,7 @@ func (l *win32PipeListener) makeServerPipe() (*win32File, error) {
}
f, err := makeWin32File(h)
if err != nil {
syscall.Close(h)
windows.Close(h)
return nil, err
}
return f, nil
@@ -380,7 +449,7 @@ func (l *win32PipeListener) makeConnectedServerPipe() (*win32File, error) {
p.Close()
p = nil
err = <-ch
if err == nil || err == ErrFileClosed {
if err == nil || err == ErrFileClosed { //nolint:errorlint // err is Errno
err = ErrPipeListenerClosed
}
}
@@ -402,15 +471,15 @@ func (l *win32PipeListener) listenerRoutine() {
p, err = l.makeConnectedServerPipe()
// If the connection was immediately closed by the client, try
// again.
if err != cERROR_NO_DATA {
if err != windows.ERROR_NO_DATA { //nolint:errorlint // err is Errno
break
}
}
responseCh <- acceptResponse{p, err}
closed = err == ErrPipeListenerClosed
closed = err == ErrPipeListenerClosed //nolint:errorlint // err is Errno
}
}
syscall.Close(l.firstHandle)
windows.Close(l.firstHandle)
l.firstHandle = 0
// Notify Close() and Accept() callers that the handle has been closed.
close(l.doneCh)
@@ -429,10 +498,10 @@ type PipeConfig struct {
// when the pipe is in message mode.
MessageMode bool
// InputBufferSize specifies the size the input buffer, in bytes.
// InputBufferSize specifies the size of the input buffer, in bytes.
InputBufferSize int32
// OutputBufferSize specifies the size the input buffer, in bytes.
// OutputBufferSize specifies the size of the output buffer, in bytes.
OutputBufferSize int32
}
@@ -469,15 +538,15 @@ func ListenPipe(path string, c *PipeConfig) (net.Listener, error) {
}
func connectPipe(p *win32File) error {
c, err := p.prepareIo()
c, err := p.prepareIO()
if err != nil {
return err
}
defer p.wg.Done()
err = connectNamedPipe(p.handle, &c.o)
_, err = p.asyncIo(c, nil, 0, err)
if err != nil && err != cERROR_PIPE_CONNECTED {
_, err = p.asyncIO(c, nil, 0, err)
if err != nil && err != windows.ERROR_PIPE_CONNECTED { //nolint:errorlint // err is Errno
return err
}
return nil

View File

@@ -7,26 +7,26 @@ package guid
import (
"crypto/rand"
"crypto/sha1"
"crypto/sha1" //nolint:gosec // not used for secure application
"encoding"
"encoding/binary"
"fmt"
"strconv"
"golang.org/x/sys/windows"
)
//go:generate go run golang.org/x/tools/cmd/stringer -type=Variant -trimprefix=Variant -linecomment
// Variant specifies which GUID variant (or "type") of the GUID. It determines
// how the entirety of the rest of the GUID is interpreted.
type Variant uint8
// The variants specified by RFC 4122.
// The variants specified by RFC 4122 section 4.1.1.
const (
// VariantUnknown specifies a GUID variant which does not conform to one of
// the variant encodings specified in RFC 4122.
VariantUnknown Variant = iota
VariantNCS
VariantRFC4122
VariantRFC4122 // RFC 4122
VariantMicrosoft
VariantFuture
)
@@ -36,16 +36,13 @@ const (
// hash of an input string.
type Version uint8
func (v Version) String() string {
return strconv.FormatUint(uint64(v), 10)
}
var _ = (encoding.TextMarshaler)(GUID{})
var _ = (encoding.TextUnmarshaler)(&GUID{})
// GUID represents a GUID/UUID. It has the same structure as
// golang.org/x/sys/windows.GUID so that it can be used with functions expecting
// that type. It is defined as its own type so that stringification and
// marshaling can be supported. The representation matches that used by native
// Windows code.
type GUID windows.GUID
// NewV4 returns a new version 4 (pseudorandom) GUID, as defined by RFC 4122.
func NewV4() (GUID, error) {
var b [16]byte
@@ -68,7 +65,7 @@ func NewV4() (GUID, error) {
// big-endian UTF16 stream of bytes. If that is desired, the string can be
// encoded as such before being passed to this function.
func NewV5(namespace GUID, name []byte) (GUID, error) {
b := sha1.New()
b := sha1.New() //nolint:gosec // not used for secure application
namespaceBytes := namespace.ToArray()
b.Write(namespaceBytes[:])
b.Write(name)

View File

@@ -0,0 +1,16 @@
//go:build !windows
// +build !windows
package guid
// GUID represents a GUID/UUID. It has the same structure as
// golang.org/x/sys/windows.GUID so that it can be used with functions expecting
// that type. It is defined as its own type as that is only available to builds
// targeted at `windows`. The representation matches that used by native Windows
// code.
type GUID struct {
Data1 uint32
Data2 uint16
Data3 uint16
Data4 [8]byte
}

View File

@@ -0,0 +1,13 @@
//go:build windows
// +build windows
package guid
import "golang.org/x/sys/windows"
// GUID represents a GUID/UUID. It has the same structure as
// golang.org/x/sys/windows.GUID so that it can be used with functions expecting
// that type. It is defined as its own type so that stringification and
// marshaling can be supported. The representation matches that used by native
// Windows code.
type GUID windows.GUID

View File

@@ -0,0 +1,27 @@
// Code generated by "stringer -type=Variant -trimprefix=Variant -linecomment"; DO NOT EDIT.
package guid
import "strconv"
func _() {
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
var x [1]struct{}
_ = x[VariantUnknown-0]
_ = x[VariantNCS-1]
_ = x[VariantRFC4122-2]
_ = x[VariantMicrosoft-3]
_ = x[VariantFuture-4]
}
const _Variant_name = "UnknownNCSRFC 4122MicrosoftFuture"
var _Variant_index = [...]uint8{0, 7, 10, 18, 27, 33}
func (i Variant) String() string {
if i >= Variant(len(_Variant_index)-1) {
return "Variant(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _Variant_name[_Variant_index[i]:_Variant_index[i+1]]
}

View File

@@ -0,0 +1,168 @@
//go:build windows
// +build windows
package security
import (
"fmt"
"os"
"unsafe"
"golang.org/x/sys/windows"
)
type (
accessMask uint32
accessMode uint32
desiredAccess uint32
inheritMode uint32
objectType uint32
shareMode uint32
securityInformation uint32
trusteeForm uint32
trusteeType uint32
explicitAccess struct {
accessPermissions accessMask
accessMode accessMode
inheritance inheritMode
trustee trustee
}
trustee struct {
multipleTrustee *trustee
multipleTrusteeOperation int32
trusteeForm trusteeForm
trusteeType trusteeType
name uintptr
}
)
const (
accessMaskDesiredPermission accessMask = 1 << 31 // GENERIC_READ
accessModeGrant accessMode = 1
desiredAccessReadControl desiredAccess = 0x20000
desiredAccessWriteDac desiredAccess = 0x40000
//cspell:disable-next-line
gvmga = "GrantVmGroupAccess:"
inheritModeNoInheritance inheritMode = 0x0
inheritModeSubContainersAndObjectsInherit inheritMode = 0x3
objectTypeFileObject objectType = 0x1
securityInformationDACL securityInformation = 0x4
shareModeRead shareMode = 0x1
shareModeWrite shareMode = 0x2
sidVMGroup = "S-1-5-83-0"
trusteeFormIsSID trusteeForm = 0
trusteeTypeWellKnownGroup trusteeType = 5
)
// GrantVMGroupAccess sets the DACL for a specified file or directory to
// include Grant ACE entries for the VM Group SID. This is a golang re-
// implementation of the same function in vmcompute, just not exported in
// RS5. Which kind of sucks. Sucks a lot :/
//
//revive:disable-next-line:var-naming VM, not Vm
func GrantVmGroupAccess(name string) error {
// Stat (to determine if `name` is a directory).
s, err := os.Stat(name)
if err != nil {
return fmt.Errorf("%s os.Stat %s: %w", gvmga, name, err)
}
// Get a handle to the file/directory. Must defer Close on success.
fd, err := createFile(name, s.IsDir())
if err != nil {
return err // Already wrapped
}
defer windows.CloseHandle(fd) //nolint:errcheck
// Get the current DACL and Security Descriptor. Must defer LocalFree on success.
ot := objectTypeFileObject
si := securityInformationDACL
sd := uintptr(0)
origDACL := uintptr(0)
if err := getSecurityInfo(fd, uint32(ot), uint32(si), nil, nil, &origDACL, nil, &sd); err != nil {
return fmt.Errorf("%s GetSecurityInfo %s: %w", gvmga, name, err)
}
defer windows.LocalFree(windows.Handle(sd)) //nolint:errcheck
// Generate a new DACL which is the current DACL with the required ACEs added.
// Must defer LocalFree on success.
newDACL, err := generateDACLWithAcesAdded(name, s.IsDir(), origDACL)
if err != nil {
return err // Already wrapped
}
defer windows.LocalFree(windows.Handle(newDACL)) //nolint:errcheck
// And finally use SetSecurityInfo to apply the updated DACL.
if err := setSecurityInfo(fd, uint32(ot), uint32(si), uintptr(0), uintptr(0), newDACL, uintptr(0)); err != nil {
return fmt.Errorf("%s SetSecurityInfo %s: %w", gvmga, name, err)
}
return nil
}
// createFile is a helper function to call [Nt]CreateFile to get a handle to
// the file or directory.
func createFile(name string, isDir bool) (windows.Handle, error) {
namep, err := windows.UTF16FromString(name)
if err != nil {
return windows.InvalidHandle, fmt.Errorf("could not convernt name to UTF-16: %w", err)
}
da := uint32(desiredAccessReadControl | desiredAccessWriteDac)
sm := uint32(shareModeRead | shareModeWrite)
fa := uint32(windows.FILE_ATTRIBUTE_NORMAL)
if isDir {
fa |= windows.FILE_FLAG_BACKUP_SEMANTICS
}
fd, err := windows.CreateFile(&namep[0], da, sm, nil, windows.OPEN_EXISTING, fa, 0)
if err != nil {
return windows.InvalidHandle, fmt.Errorf("%s windows.CreateFile %s: %w", gvmga, name, err)
}
return fd, nil
}
// generateDACLWithAcesAdded generates a new DACL with the two needed ACEs added.
// The caller is responsible for LocalFree of the returned DACL on success.
func generateDACLWithAcesAdded(name string, isDir bool, origDACL uintptr) (uintptr, error) {
// Generate pointers to the SIDs based on the string SIDs
sid, err := windows.StringToSid(sidVMGroup)
if err != nil {
return 0, fmt.Errorf("%s windows.StringToSid %s %s: %w", gvmga, name, sidVMGroup, err)
}
inheritance := inheritModeNoInheritance
if isDir {
inheritance = inheritModeSubContainersAndObjectsInherit
}
eaArray := []explicitAccess{
{
accessPermissions: accessMaskDesiredPermission,
accessMode: accessModeGrant,
inheritance: inheritance,
trustee: trustee{
trusteeForm: trusteeFormIsSID,
trusteeType: trusteeTypeWellKnownGroup,
name: uintptr(unsafe.Pointer(sid)),
},
},
}
modifiedDACL := uintptr(0)
if err := setEntriesInAcl(uintptr(uint32(1)), uintptr(unsafe.Pointer(&eaArray[0])), origDACL, &modifiedDACL); err != nil {
return 0, fmt.Errorf("%s SetEntriesInAcl %s: %w", gvmga, name, err)
}
return modifiedDACL, nil
}

View File

@@ -0,0 +1,7 @@
package security
//go:generate go run github.com/Microsoft/go-winio/tools/mkwinsyscall -output zsyscall_windows.go syscall_windows.go
//sys getSecurityInfo(handle windows.Handle, objectType uint32, si uint32, ppsidOwner **uintptr, ppsidGroup **uintptr, ppDacl *uintptr, ppSacl *uintptr, ppSecurityDescriptor *uintptr) (win32err error) = advapi32.GetSecurityInfo
//sys setSecurityInfo(handle windows.Handle, objectType uint32, si uint32, psidOwner uintptr, psidGroup uintptr, pDacl uintptr, pSacl uintptr) (win32err error) = advapi32.SetSecurityInfo
//sys setEntriesInAcl(count uintptr, pListOfEEs uintptr, oldAcl uintptr, newAcl *uintptr) (win32err error) = advapi32.SetEntriesInAclW

View File

@@ -0,0 +1,69 @@
//go:build windows
// Code generated by 'go generate' using "github.com/Microsoft/go-winio/tools/mkwinsyscall"; DO NOT EDIT.
package security
import (
"syscall"
"unsafe"
"golang.org/x/sys/windows"
)
var _ unsafe.Pointer
// Do the interface allocations only once for common
// Errno values.
const (
errnoERROR_IO_PENDING = 997
)
var (
errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
errERROR_EINVAL error = syscall.EINVAL
)
// errnoErr returns common boxed Errno values, to prevent
// allocations at runtime.
func errnoErr(e syscall.Errno) error {
switch e {
case 0:
return errERROR_EINVAL
case errnoERROR_IO_PENDING:
return errERROR_IO_PENDING
}
return e
}
var (
modadvapi32 = windows.NewLazySystemDLL("advapi32.dll")
procGetSecurityInfo = modadvapi32.NewProc("GetSecurityInfo")
procSetEntriesInAclW = modadvapi32.NewProc("SetEntriesInAclW")
procSetSecurityInfo = modadvapi32.NewProc("SetSecurityInfo")
)
func getSecurityInfo(handle windows.Handle, objectType uint32, si uint32, ppsidOwner **uintptr, ppsidGroup **uintptr, ppDacl *uintptr, ppSacl *uintptr, ppSecurityDescriptor *uintptr) (win32err error) {
r0, _, _ := syscall.SyscallN(procGetSecurityInfo.Addr(), uintptr(handle), uintptr(objectType), uintptr(si), uintptr(unsafe.Pointer(ppsidOwner)), uintptr(unsafe.Pointer(ppsidGroup)), uintptr(unsafe.Pointer(ppDacl)), uintptr(unsafe.Pointer(ppSacl)), uintptr(unsafe.Pointer(ppSecurityDescriptor)))
if r0 != 0 {
win32err = syscall.Errno(r0)
}
return
}
func setEntriesInAcl(count uintptr, pListOfEEs uintptr, oldAcl uintptr, newAcl *uintptr) (win32err error) {
r0, _, _ := syscall.SyscallN(procSetEntriesInAclW.Addr(), uintptr(count), uintptr(pListOfEEs), uintptr(oldAcl), uintptr(unsafe.Pointer(newAcl)))
if r0 != 0 {
win32err = syscall.Errno(r0)
}
return
}
func setSecurityInfo(handle windows.Handle, objectType uint32, si uint32, psidOwner uintptr, psidGroup uintptr, pDacl uintptr, pSacl uintptr) (win32err error) {
r0, _, _ := syscall.SyscallN(procSetSecurityInfo.Addr(), uintptr(handle), uintptr(objectType), uintptr(si), uintptr(psidOwner), uintptr(psidGroup), uintptr(pDacl), uintptr(pSacl))
if r0 != 0 {
win32err = syscall.Errno(r0)
}
return
}

View File

@@ -1,3 +1,4 @@
//go:build windows
// +build windows
package winio
@@ -8,7 +9,6 @@ import (
"fmt"
"runtime"
"sync"
"syscall"
"unicode/utf16"
"golang.org/x/sys/windows"
@@ -17,26 +17,22 @@ import (
//sys adjustTokenPrivileges(token windows.Token, releaseAll bool, input *byte, outputSize uint32, output *byte, requiredSize *uint32) (success bool, err error) [true] = advapi32.AdjustTokenPrivileges
//sys impersonateSelf(level uint32) (err error) = advapi32.ImpersonateSelf
//sys revertToSelf() (err error) = advapi32.RevertToSelf
//sys openThreadToken(thread syscall.Handle, accessMask uint32, openAsSelf bool, token *windows.Token) (err error) = advapi32.OpenThreadToken
//sys getCurrentThread() (h syscall.Handle) = GetCurrentThread
//sys openThreadToken(thread windows.Handle, accessMask uint32, openAsSelf bool, token *windows.Token) (err error) = advapi32.OpenThreadToken
//sys getCurrentThread() (h windows.Handle) = GetCurrentThread
//sys lookupPrivilegeValue(systemName string, name string, luid *uint64) (err error) = advapi32.LookupPrivilegeValueW
//sys lookupPrivilegeName(systemName string, luid *uint64, buffer *uint16, size *uint32) (err error) = advapi32.LookupPrivilegeNameW
//sys lookupPrivilegeDisplayName(systemName string, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) = advapi32.LookupPrivilegeDisplayNameW
const (
SE_PRIVILEGE_ENABLED = 2
//revive:disable-next-line:var-naming ALL_CAPS
SE_PRIVILEGE_ENABLED = windows.SE_PRIVILEGE_ENABLED
ERROR_NOT_ALL_ASSIGNED syscall.Errno = 1300
//revive:disable-next-line:var-naming ALL_CAPS
ERROR_NOT_ALL_ASSIGNED windows.Errno = windows.ERROR_NOT_ALL_ASSIGNED
SeBackupPrivilege = "SeBackupPrivilege"
SeRestorePrivilege = "SeRestorePrivilege"
)
const (
securityAnonymous = iota
securityIdentification
securityImpersonation
securityDelegation
SeBackupPrivilege = "SeBackupPrivilege"
SeRestorePrivilege = "SeRestorePrivilege"
SeSecurityPrivilege = "SeSecurityPrivilege"
)
var (
@@ -50,11 +46,9 @@ type PrivilegeError struct {
}
func (e *PrivilegeError) Error() string {
s := ""
s := "Could not enable privilege "
if len(e.privileges) > 1 {
s = "Could not enable privileges "
} else {
s = "Could not enable privilege "
}
for i, p := range e.privileges {
if i != 0 {
@@ -93,7 +87,7 @@ func RunWithPrivileges(names []string, fn func() error) error {
}
func mapPrivileges(names []string) ([]uint64, error) {
var privileges []uint64
privileges := make([]uint64, 0, len(names))
privNameMutex.Lock()
defer privNameMutex.Unlock()
for _, name := range names {
@@ -126,7 +120,7 @@ func enableDisableProcessPrivilege(names []string, action uint32) error {
return err
}
p, _ := windows.GetCurrentProcess()
p := windows.CurrentProcess()
var token windows.Token
err = windows.OpenProcessToken(p, windows.TOKEN_ADJUST_PRIVILEGES|windows.TOKEN_QUERY, &token)
if err != nil {
@@ -139,10 +133,10 @@ func enableDisableProcessPrivilege(names []string, action uint32) error {
func adjustPrivileges(token windows.Token, privileges []uint64, action uint32) error {
var b bytes.Buffer
binary.Write(&b, binary.LittleEndian, uint32(len(privileges)))
_ = binary.Write(&b, binary.LittleEndian, uint32(len(privileges)))
for _, p := range privileges {
binary.Write(&b, binary.LittleEndian, p)
binary.Write(&b, binary.LittleEndian, action)
_ = binary.Write(&b, binary.LittleEndian, p)
_ = binary.Write(&b, binary.LittleEndian, action)
}
prevState := make([]byte, b.Len())
reqSize := uint32(0)
@@ -150,7 +144,7 @@ func adjustPrivileges(token windows.Token, privileges []uint64, action uint32) e
if !success {
return err
}
if err == ERROR_NOT_ALL_ASSIGNED {
if err == ERROR_NOT_ALL_ASSIGNED { //nolint:errorlint // err is Errno
return &PrivilegeError{privileges}
}
return nil
@@ -176,13 +170,13 @@ func getPrivilegeName(luid uint64) string {
}
func newThreadToken() (windows.Token, error) {
err := impersonateSelf(securityImpersonation)
err := impersonateSelf(windows.SecurityImpersonation)
if err != nil {
return 0, err
}
var token windows.Token
err = openThreadToken(getCurrentThread(), syscall.TOKEN_ADJUST_PRIVILEGES|syscall.TOKEN_QUERY, false, &token)
err = openThreadToken(getCurrentThread(), windows.TOKEN_ADJUST_PRIVILEGES|windows.TOKEN_QUERY, false, &token)
if err != nil {
rerr := revertToSelf()
if rerr != nil {

View File

@@ -1,3 +1,6 @@
//go:build windows
// +build windows
package winio
import (
@@ -113,16 +116,16 @@ func EncodeReparsePoint(rp *ReparsePoint) []byte {
}
var b bytes.Buffer
binary.Write(&b, binary.LittleEndian, &data)
_ = binary.Write(&b, binary.LittleEndian, &data)
if !rp.IsMountPoint {
flags := uint32(0)
if relative {
flags |= 1
}
binary.Write(&b, binary.LittleEndian, flags)
_ = binary.Write(&b, binary.LittleEndian, flags)
}
binary.Write(&b, binary.LittleEndian, ntTarget16)
binary.Write(&b, binary.LittleEndian, target16)
_ = binary.Write(&b, binary.LittleEndian, ntTarget16)
_ = binary.Write(&b, binary.LittleEndian, target16)
return b.Bytes()
}

View File

@@ -1,22 +1,20 @@
//go:build windows
// +build windows
package winio
import (
"syscall"
"errors"
"fmt"
"unsafe"
"golang.org/x/sys/windows"
)
//sys lookupAccountName(systemName *uint16, accountName string, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) = advapi32.LookupAccountNameW
//sys lookupAccountSid(systemName *uint16, sid *byte, name *uint16, nameSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) = advapi32.LookupAccountSidW
//sys convertSidToStringSid(sid *byte, str **uint16) (err error) = advapi32.ConvertSidToStringSidW
//sys convertStringSecurityDescriptorToSecurityDescriptor(str string, revision uint32, sd *uintptr, size *uint32) (err error) = advapi32.ConvertStringSecurityDescriptorToSecurityDescriptorW
//sys convertSecurityDescriptorToStringSecurityDescriptor(sd *byte, revision uint32, secInfo uint32, sddl **uint16, sddlSize *uint32) (err error) = advapi32.ConvertSecurityDescriptorToStringSecurityDescriptorW
//sys localFree(mem uintptr) = LocalFree
//sys getSecurityDescriptorLength(sd uintptr) (len uint32) = advapi32.GetSecurityDescriptorLength
const (
cERROR_NONE_MAPPED = syscall.Errno(1332)
)
//sys convertStringSidToSid(str *uint16, sid **byte) (err error) = advapi32.ConvertStringSidToSidW
type AccountLookupError struct {
Name string
@@ -28,8 +26,10 @@ func (e *AccountLookupError) Error() string {
return "lookup account: empty account name specified"
}
var s string
switch e.Err {
case cERROR_NONE_MAPPED:
switch {
case errors.Is(e.Err, windows.ERROR_INVALID_SID):
s = "the security ID structure is invalid"
case errors.Is(e.Err, windows.ERROR_NONE_MAPPED):
s = "not found"
default:
s = e.Err.Error()
@@ -37,6 +37,8 @@ func (e *AccountLookupError) Error() string {
return "lookup account " + e.Name + ": " + s
}
func (e *AccountLookupError) Unwrap() error { return e.Err }
type SddlConversionError struct {
Sddl string
Err error
@@ -46,15 +48,19 @@ func (e *SddlConversionError) Error() string {
return "convert " + e.Sddl + ": " + e.Err.Error()
}
func (e *SddlConversionError) Unwrap() error { return e.Err }
// LookupSidByName looks up the SID of an account by name
//
//revive:disable-next-line:var-naming SID, not Sid
func LookupSidByName(name string) (sid string, err error) {
if name == "" {
return "", &AccountLookupError{name, cERROR_NONE_MAPPED}
return "", &AccountLookupError{name, windows.ERROR_NONE_MAPPED}
}
var sidSize, sidNameUse, refDomainSize uint32
err = lookupAccountName(nil, name, nil, &sidSize, nil, &refDomainSize, &sidNameUse)
if err != nil && err != syscall.ERROR_INSUFFICIENT_BUFFER {
if err != nil && err != windows.ERROR_INSUFFICIENT_BUFFER { //nolint:errorlint // err is Errno
return "", &AccountLookupError{name, err}
}
sidBuffer := make([]byte, sidSize)
@@ -68,31 +74,60 @@ func LookupSidByName(name string) (sid string, err error) {
if err != nil {
return "", &AccountLookupError{name, err}
}
sid = syscall.UTF16ToString((*[0xffff]uint16)(unsafe.Pointer(strBuffer))[:])
localFree(uintptr(unsafe.Pointer(strBuffer)))
sid = windows.UTF16ToString((*[0xffff]uint16)(unsafe.Pointer(strBuffer))[:])
_, _ = windows.LocalFree(windows.Handle(unsafe.Pointer(strBuffer)))
return sid, nil
}
func SddlToSecurityDescriptor(sddl string) ([]byte, error) {
var sdBuffer uintptr
err := convertStringSecurityDescriptorToSecurityDescriptor(sddl, 1, &sdBuffer, nil)
if err != nil {
return nil, &SddlConversionError{sddl, err}
// LookupNameBySid looks up the name of an account by SID
//
//revive:disable-next-line:var-naming SID, not Sid
func LookupNameBySid(sid string) (name string, err error) {
if sid == "" {
return "", &AccountLookupError{sid, windows.ERROR_NONE_MAPPED}
}
defer localFree(sdBuffer)
sd := make([]byte, getSecurityDescriptorLength(sdBuffer))
copy(sd, (*[0xffff]byte)(unsafe.Pointer(sdBuffer))[:len(sd)])
return sd, nil
sidBuffer, err := windows.UTF16PtrFromString(sid)
if err != nil {
return "", &AccountLookupError{sid, err}
}
var sidPtr *byte
if err = convertStringSidToSid(sidBuffer, &sidPtr); err != nil {
return "", &AccountLookupError{sid, err}
}
defer windows.LocalFree(windows.Handle(unsafe.Pointer(sidPtr))) //nolint:errcheck
var nameSize, refDomainSize, sidNameUse uint32
err = lookupAccountSid(nil, sidPtr, nil, &nameSize, nil, &refDomainSize, &sidNameUse)
if err != nil && err != windows.ERROR_INSUFFICIENT_BUFFER { //nolint:errorlint // err is Errno
return "", &AccountLookupError{sid, err}
}
nameBuffer := make([]uint16, nameSize)
refDomainBuffer := make([]uint16, refDomainSize)
err = lookupAccountSid(nil, sidPtr, &nameBuffer[0], &nameSize, &refDomainBuffer[0], &refDomainSize, &sidNameUse)
if err != nil {
return "", &AccountLookupError{sid, err}
}
name = windows.UTF16ToString(nameBuffer)
return name, nil
}
func SddlToSecurityDescriptor(sddl string) ([]byte, error) {
sd, err := windows.SecurityDescriptorFromString(sddl)
if err != nil {
return nil, &SddlConversionError{Sddl: sddl, Err: err}
}
b := unsafe.Slice((*byte)(unsafe.Pointer(sd)), sd.Length())
return b, nil
}
func SecurityDescriptorToSddl(sd []byte) (string, error) {
var sddl *uint16
// The returned string length seems to including an aribtrary number of terminating NULs.
// Don't use it.
err := convertSecurityDescriptorToStringSecurityDescriptor(&sd[0], 1, 0xff, &sddl, nil)
if err != nil {
return "", err
if l := int(unsafe.Sizeof(windows.SECURITY_DESCRIPTOR{})); len(sd) < l {
return "", fmt.Errorf("SecurityDescriptor (%d) smaller than expected (%d): %w", len(sd), l, windows.ERROR_INCORRECT_SIZE)
}
defer localFree(uintptr(unsafe.Pointer(sddl)))
return syscall.UTF16ToString((*[0xffff]uint16)(unsafe.Pointer(sddl))[:]), nil
s := (*windows.SECURITY_DESCRIPTOR)(unsafe.Pointer(&sd[0]))
return s.String(), nil
}

View File

@@ -1,3 +1,5 @@
//go:build windows
package winio
//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go file.go pipe.go sd.go fileinfo.go privilege.go backup.go hvsock.go
//go:generate go run github.com/Microsoft/go-winio/tools/mkwinsyscall -output zsyscall_windows.go ./*.go

377
vendor/github.com/Microsoft/go-winio/vhd/vhd.go generated vendored Normal file
View File

@@ -0,0 +1,377 @@
//go:build windows
// +build windows
package vhd
import (
"fmt"
"syscall"
"github.com/Microsoft/go-winio/pkg/guid"
"golang.org/x/sys/windows"
)
//go:generate go run github.com/Microsoft/go-winio/tools/mkwinsyscall -output zvhd_windows.go vhd.go
//sys createVirtualDisk(virtualStorageType *VirtualStorageType, path string, virtualDiskAccessMask uint32, securityDescriptor *uintptr, createVirtualDiskFlags uint32, providerSpecificFlags uint32, parameters *CreateVirtualDiskParameters, overlapped *syscall.Overlapped, handle *syscall.Handle) (win32err error) = virtdisk.CreateVirtualDisk
//sys openVirtualDisk(virtualStorageType *VirtualStorageType, path string, virtualDiskAccessMask uint32, openVirtualDiskFlags uint32, parameters *openVirtualDiskParameters, handle *syscall.Handle) (win32err error) = virtdisk.OpenVirtualDisk
//sys attachVirtualDisk(handle syscall.Handle, securityDescriptor *uintptr, attachVirtualDiskFlag uint32, providerSpecificFlags uint32, parameters *AttachVirtualDiskParameters, overlapped *syscall.Overlapped) (win32err error) = virtdisk.AttachVirtualDisk
//sys detachVirtualDisk(handle syscall.Handle, detachVirtualDiskFlags uint32, providerSpecificFlags uint32) (win32err error) = virtdisk.DetachVirtualDisk
//sys getVirtualDiskPhysicalPath(handle syscall.Handle, diskPathSizeInBytes *uint32, buffer *uint16) (win32err error) = virtdisk.GetVirtualDiskPhysicalPath
type (
CreateVirtualDiskFlag uint32
VirtualDiskFlag uint32
AttachVirtualDiskFlag uint32
DetachVirtualDiskFlag uint32
VirtualDiskAccessMask uint32
)
type VirtualStorageType struct {
DeviceID uint32
VendorID guid.GUID
}
type CreateVersion2 struct {
UniqueID guid.GUID
MaximumSize uint64
BlockSizeInBytes uint32
SectorSizeInBytes uint32
PhysicalSectorSizeInByte uint32
ParentPath *uint16 // string
SourcePath *uint16 // string
OpenFlags uint32
ParentVirtualStorageType VirtualStorageType
SourceVirtualStorageType VirtualStorageType
ResiliencyGUID guid.GUID
}
type CreateVirtualDiskParameters struct {
Version uint32 // Must always be set to 2
Version2 CreateVersion2
}
type OpenVersion2 struct {
GetInfoOnly bool
ReadOnly bool
ResiliencyGUID guid.GUID
}
type OpenVirtualDiskParameters struct {
Version uint32 // Must always be set to 2
Version2 OpenVersion2
}
// The higher level `OpenVersion2` struct uses `bool`s to refer to `GetInfoOnly` and `ReadOnly` for ease of use. However,
// the internal windows structure uses `BOOL`s aka int32s for these types. `openVersion2` is used for translating
// `OpenVersion2` fields to the correct windows internal field types on the `Open____` methods.
type openVersion2 struct {
getInfoOnly int32
readOnly int32
resiliencyGUID guid.GUID
}
type openVirtualDiskParameters struct {
version uint32
version2 openVersion2
}
type AttachVersion2 struct {
RestrictedOffset uint64
RestrictedLength uint64
}
type AttachVirtualDiskParameters struct {
Version uint32
Version2 AttachVersion2
}
const (
//revive:disable-next-line:var-naming ALL_CAPS
VIRTUAL_STORAGE_TYPE_DEVICE_VHDX = 0x3
// Access Mask for opening a VHD.
VirtualDiskAccessNone VirtualDiskAccessMask = 0x00000000
VirtualDiskAccessAttachRO VirtualDiskAccessMask = 0x00010000
VirtualDiskAccessAttachRW VirtualDiskAccessMask = 0x00020000
VirtualDiskAccessDetach VirtualDiskAccessMask = 0x00040000
VirtualDiskAccessGetInfo VirtualDiskAccessMask = 0x00080000
VirtualDiskAccessCreate VirtualDiskAccessMask = 0x00100000
VirtualDiskAccessMetaOps VirtualDiskAccessMask = 0x00200000
VirtualDiskAccessRead VirtualDiskAccessMask = 0x000d0000
VirtualDiskAccessAll VirtualDiskAccessMask = 0x003f0000
VirtualDiskAccessWritable VirtualDiskAccessMask = 0x00320000
// Flags for creating a VHD.
CreateVirtualDiskFlagNone CreateVirtualDiskFlag = 0x0
CreateVirtualDiskFlagFullPhysicalAllocation CreateVirtualDiskFlag = 0x1
CreateVirtualDiskFlagPreventWritesToSourceDisk CreateVirtualDiskFlag = 0x2
CreateVirtualDiskFlagDoNotCopyMetadataFromParent CreateVirtualDiskFlag = 0x4
CreateVirtualDiskFlagCreateBackingStorage CreateVirtualDiskFlag = 0x8
CreateVirtualDiskFlagUseChangeTrackingSourceLimit CreateVirtualDiskFlag = 0x10
CreateVirtualDiskFlagPreserveParentChangeTrackingState CreateVirtualDiskFlag = 0x20
CreateVirtualDiskFlagVhdSetUseOriginalBackingStorage CreateVirtualDiskFlag = 0x40 //revive:disable-line:var-naming VHD, not Vhd
CreateVirtualDiskFlagSparseFile CreateVirtualDiskFlag = 0x80
CreateVirtualDiskFlagPmemCompatible CreateVirtualDiskFlag = 0x100 //revive:disable-line:var-naming PMEM, not Pmem
CreateVirtualDiskFlagSupportCompressedVolumes CreateVirtualDiskFlag = 0x200
// Flags for opening a VHD.
OpenVirtualDiskFlagNone VirtualDiskFlag = 0x00000000
OpenVirtualDiskFlagNoParents VirtualDiskFlag = 0x00000001
OpenVirtualDiskFlagBlankFile VirtualDiskFlag = 0x00000002
OpenVirtualDiskFlagBootDrive VirtualDiskFlag = 0x00000004
OpenVirtualDiskFlagCachedIO VirtualDiskFlag = 0x00000008
OpenVirtualDiskFlagCustomDiffChain VirtualDiskFlag = 0x00000010
OpenVirtualDiskFlagParentCachedIO VirtualDiskFlag = 0x00000020
OpenVirtualDiskFlagVhdsetFileOnly VirtualDiskFlag = 0x00000040
OpenVirtualDiskFlagIgnoreRelativeParentLocator VirtualDiskFlag = 0x00000080
OpenVirtualDiskFlagNoWriteHardening VirtualDiskFlag = 0x00000100
OpenVirtualDiskFlagSupportCompressedVolumes VirtualDiskFlag = 0x00000200
// Flags for attaching a VHD.
AttachVirtualDiskFlagNone AttachVirtualDiskFlag = 0x00000000
AttachVirtualDiskFlagReadOnly AttachVirtualDiskFlag = 0x00000001
AttachVirtualDiskFlagNoDriveLetter AttachVirtualDiskFlag = 0x00000002
AttachVirtualDiskFlagPermanentLifetime AttachVirtualDiskFlag = 0x00000004
AttachVirtualDiskFlagNoLocalHost AttachVirtualDiskFlag = 0x00000008
AttachVirtualDiskFlagNoSecurityDescriptor AttachVirtualDiskFlag = 0x00000010
AttachVirtualDiskFlagBypassDefaultEncryptionPolicy AttachVirtualDiskFlag = 0x00000020
AttachVirtualDiskFlagNonPnp AttachVirtualDiskFlag = 0x00000040
AttachVirtualDiskFlagRestrictedRange AttachVirtualDiskFlag = 0x00000080
AttachVirtualDiskFlagSinglePartition AttachVirtualDiskFlag = 0x00000100
AttachVirtualDiskFlagRegisterVolume AttachVirtualDiskFlag = 0x00000200
// Flags for detaching a VHD.
DetachVirtualDiskFlagNone DetachVirtualDiskFlag = 0x0
)
// CreateVhdx is a helper function to create a simple vhdx file at the given path using
// default values.
//
//revive:disable-next-line:var-naming VHDX, not Vhdx
func CreateVhdx(path string, maxSizeInGb, blockSizeInMb uint32) error {
params := CreateVirtualDiskParameters{
Version: 2,
Version2: CreateVersion2{
MaximumSize: uint64(maxSizeInGb) * 1024 * 1024 * 1024,
BlockSizeInBytes: blockSizeInMb * 1024 * 1024,
},
}
handle, err := CreateVirtualDisk(path, VirtualDiskAccessNone, CreateVirtualDiskFlagNone, &params)
if err != nil {
return err
}
return syscall.CloseHandle(handle)
}
// DetachVirtualDisk detaches a virtual hard disk by handle.
func DetachVirtualDisk(handle syscall.Handle) (err error) {
if err := detachVirtualDisk(handle, 0, 0); err != nil {
return fmt.Errorf("failed to detach virtual disk: %w", err)
}
return nil
}
// DetachVhd detaches a vhd found at `path`.
//
//revive:disable-next-line:var-naming VHD, not Vhd
func DetachVhd(path string) error {
handle, err := OpenVirtualDisk(
path,
VirtualDiskAccessNone,
OpenVirtualDiskFlagCachedIO|OpenVirtualDiskFlagIgnoreRelativeParentLocator,
)
if err != nil {
return err
}
defer syscall.CloseHandle(handle) //nolint:errcheck
return DetachVirtualDisk(handle)
}
// AttachVirtualDisk attaches a virtual hard disk for use.
func AttachVirtualDisk(
handle syscall.Handle,
attachVirtualDiskFlag AttachVirtualDiskFlag,
parameters *AttachVirtualDiskParameters,
) (err error) {
// Supports both version 1 and 2 of the attach parameters as version 2 wasn't present in RS5.
if err := attachVirtualDisk(
handle,
nil,
uint32(attachVirtualDiskFlag),
0,
parameters,
nil,
); err != nil {
return fmt.Errorf("failed to attach virtual disk: %w", err)
}
return nil
}
// AttachVhd attaches a virtual hard disk at `path` for use. Attaches using version 2
// of the ATTACH_VIRTUAL_DISK_PARAMETERS.
//
//revive:disable-next-line:var-naming VHD, not Vhd
func AttachVhd(path string) (err error) {
handle, err := OpenVirtualDisk(
path,
VirtualDiskAccessNone,
OpenVirtualDiskFlagCachedIO|OpenVirtualDiskFlagIgnoreRelativeParentLocator,
)
if err != nil {
return err
}
defer syscall.CloseHandle(handle) //nolint:errcheck
params := AttachVirtualDiskParameters{Version: 2}
if err := AttachVirtualDisk(
handle,
AttachVirtualDiskFlagNone,
&params,
); err != nil {
return fmt.Errorf("failed to attach virtual disk: %w", err)
}
return nil
}
// OpenVirtualDisk obtains a handle to a VHD opened with supplied access mask and flags.
func OpenVirtualDisk(
vhdPath string,
virtualDiskAccessMask VirtualDiskAccessMask,
openVirtualDiskFlags VirtualDiskFlag,
) (syscall.Handle, error) {
parameters := OpenVirtualDiskParameters{Version: 2}
handle, err := OpenVirtualDiskWithParameters(
vhdPath,
virtualDiskAccessMask,
openVirtualDiskFlags,
&parameters,
)
if err != nil {
return 0, err
}
return handle, nil
}
// OpenVirtualDiskWithParameters obtains a handle to a VHD opened with supplied access mask, flags and parameters.
func OpenVirtualDiskWithParameters(
vhdPath string,
virtualDiskAccessMask VirtualDiskAccessMask,
openVirtualDiskFlags VirtualDiskFlag,
parameters *OpenVirtualDiskParameters,
) (syscall.Handle, error) {
var (
handle syscall.Handle
defaultType VirtualStorageType
getInfoOnly int32
readOnly int32
)
if parameters.Version != 2 {
return handle, fmt.Errorf("only version 2 VHDs are supported, found version: %d", parameters.Version)
}
if parameters.Version2.GetInfoOnly {
getInfoOnly = 1
}
if parameters.Version2.ReadOnly {
readOnly = 1
}
params := &openVirtualDiskParameters{
version: parameters.Version,
version2: openVersion2{
getInfoOnly,
readOnly,
parameters.Version2.ResiliencyGUID,
},
}
if err := openVirtualDisk(
&defaultType,
vhdPath,
uint32(virtualDiskAccessMask),
uint32(openVirtualDiskFlags),
params,
&handle,
); err != nil {
return 0, fmt.Errorf("failed to open virtual disk: %w", err)
}
return handle, nil
}
// CreateVirtualDisk creates a virtual harddisk and returns a handle to the disk.
func CreateVirtualDisk(
path string,
virtualDiskAccessMask VirtualDiskAccessMask,
createVirtualDiskFlags CreateVirtualDiskFlag,
parameters *CreateVirtualDiskParameters,
) (syscall.Handle, error) {
var (
handle syscall.Handle
defaultType VirtualStorageType
)
if parameters.Version != 2 {
return handle, fmt.Errorf("only version 2 VHDs are supported, found version: %d", parameters.Version)
}
if err := createVirtualDisk(
&defaultType,
path,
uint32(virtualDiskAccessMask),
nil,
uint32(createVirtualDiskFlags),
0,
parameters,
nil,
&handle,
); err != nil {
return handle, fmt.Errorf("failed to create virtual disk: %w", err)
}
return handle, nil
}
// GetVirtualDiskPhysicalPath takes a handle to a virtual hard disk and returns the physical
// path of the disk on the machine. This path is in the form \\.\PhysicalDriveX where X is an integer
// that represents the particular enumeration of the physical disk on the caller's system.
func GetVirtualDiskPhysicalPath(handle syscall.Handle) (_ string, err error) {
var (
diskPathSizeInBytes uint32 = 256 * 2 // max path length 256 wide chars
diskPhysicalPathBuf [256]uint16
)
if err := getVirtualDiskPhysicalPath(
handle,
&diskPathSizeInBytes,
&diskPhysicalPathBuf[0],
); err != nil {
return "", fmt.Errorf("failed to get disk physical path: %w", err)
}
return windows.UTF16ToString(diskPhysicalPathBuf[:]), nil
}
// CreateDiffVhd is a helper function to create a differencing virtual disk.
//
//revive:disable-next-line:var-naming VHD, not Vhd
func CreateDiffVhd(diffVhdPath, baseVhdPath string, blockSizeInMB uint32) error {
// Setting `ParentPath` is how to signal to create a differencing disk.
createParams := &CreateVirtualDiskParameters{
Version: 2,
Version2: CreateVersion2{
ParentPath: windows.StringToUTF16Ptr(baseVhdPath),
BlockSizeInBytes: blockSizeInMB * 1024 * 1024,
OpenFlags: uint32(OpenVirtualDiskFlagCachedIO),
},
}
vhdHandle, err := CreateVirtualDisk(
diffVhdPath,
VirtualDiskAccessNone,
CreateVirtualDiskFlagNone,
createParams,
)
if err != nil {
return fmt.Errorf("failed to create differencing vhd: %w", err)
}
if err := syscall.CloseHandle(vhdHandle); err != nil {
return fmt.Errorf("failed to close differencing vhd handle: %w", err)
}
return nil
}

View File

@@ -0,0 +1,105 @@
//go:build windows
// Code generated by 'go generate' using "github.com/Microsoft/go-winio/tools/mkwinsyscall"; DO NOT EDIT.
package vhd
import (
"syscall"
"unsafe"
"golang.org/x/sys/windows"
)
var _ unsafe.Pointer
// Do the interface allocations only once for common
// Errno values.
const (
errnoERROR_IO_PENDING = 997
)
var (
errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
errERROR_EINVAL error = syscall.EINVAL
)
// errnoErr returns common boxed Errno values, to prevent
// allocations at runtime.
func errnoErr(e syscall.Errno) error {
switch e {
case 0:
return errERROR_EINVAL
case errnoERROR_IO_PENDING:
return errERROR_IO_PENDING
}
return e
}
var (
modvirtdisk = windows.NewLazySystemDLL("virtdisk.dll")
procAttachVirtualDisk = modvirtdisk.NewProc("AttachVirtualDisk")
procCreateVirtualDisk = modvirtdisk.NewProc("CreateVirtualDisk")
procDetachVirtualDisk = modvirtdisk.NewProc("DetachVirtualDisk")
procGetVirtualDiskPhysicalPath = modvirtdisk.NewProc("GetVirtualDiskPhysicalPath")
procOpenVirtualDisk = modvirtdisk.NewProc("OpenVirtualDisk")
)
func attachVirtualDisk(handle syscall.Handle, securityDescriptor *uintptr, attachVirtualDiskFlag uint32, providerSpecificFlags uint32, parameters *AttachVirtualDiskParameters, overlapped *syscall.Overlapped) (win32err error) {
r0, _, _ := syscall.SyscallN(procAttachVirtualDisk.Addr(), uintptr(handle), uintptr(unsafe.Pointer(securityDescriptor)), uintptr(attachVirtualDiskFlag), uintptr(providerSpecificFlags), uintptr(unsafe.Pointer(parameters)), uintptr(unsafe.Pointer(overlapped)))
if r0 != 0 {
win32err = syscall.Errno(r0)
}
return
}
func createVirtualDisk(virtualStorageType *VirtualStorageType, path string, virtualDiskAccessMask uint32, securityDescriptor *uintptr, createVirtualDiskFlags uint32, providerSpecificFlags uint32, parameters *CreateVirtualDiskParameters, overlapped *syscall.Overlapped, handle *syscall.Handle) (win32err error) {
var _p0 *uint16
_p0, win32err = syscall.UTF16PtrFromString(path)
if win32err != nil {
return
}
return _createVirtualDisk(virtualStorageType, _p0, virtualDiskAccessMask, securityDescriptor, createVirtualDiskFlags, providerSpecificFlags, parameters, overlapped, handle)
}
func _createVirtualDisk(virtualStorageType *VirtualStorageType, path *uint16, virtualDiskAccessMask uint32, securityDescriptor *uintptr, createVirtualDiskFlags uint32, providerSpecificFlags uint32, parameters *CreateVirtualDiskParameters, overlapped *syscall.Overlapped, handle *syscall.Handle) (win32err error) {
r0, _, _ := syscall.SyscallN(procCreateVirtualDisk.Addr(), uintptr(unsafe.Pointer(virtualStorageType)), uintptr(unsafe.Pointer(path)), uintptr(virtualDiskAccessMask), uintptr(unsafe.Pointer(securityDescriptor)), uintptr(createVirtualDiskFlags), uintptr(providerSpecificFlags), uintptr(unsafe.Pointer(parameters)), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(handle)))
if r0 != 0 {
win32err = syscall.Errno(r0)
}
return
}
func detachVirtualDisk(handle syscall.Handle, detachVirtualDiskFlags uint32, providerSpecificFlags uint32) (win32err error) {
r0, _, _ := syscall.SyscallN(procDetachVirtualDisk.Addr(), uintptr(handle), uintptr(detachVirtualDiskFlags), uintptr(providerSpecificFlags))
if r0 != 0 {
win32err = syscall.Errno(r0)
}
return
}
func getVirtualDiskPhysicalPath(handle syscall.Handle, diskPathSizeInBytes *uint32, buffer *uint16) (win32err error) {
r0, _, _ := syscall.SyscallN(procGetVirtualDiskPhysicalPath.Addr(), uintptr(handle), uintptr(unsafe.Pointer(diskPathSizeInBytes)), uintptr(unsafe.Pointer(buffer)))
if r0 != 0 {
win32err = syscall.Errno(r0)
}
return
}
func openVirtualDisk(virtualStorageType *VirtualStorageType, path string, virtualDiskAccessMask uint32, openVirtualDiskFlags uint32, parameters *openVirtualDiskParameters, handle *syscall.Handle) (win32err error) {
var _p0 *uint16
_p0, win32err = syscall.UTF16PtrFromString(path)
if win32err != nil {
return
}
return _openVirtualDisk(virtualStorageType, _p0, virtualDiskAccessMask, openVirtualDiskFlags, parameters, handle)
}
func _openVirtualDisk(virtualStorageType *VirtualStorageType, path *uint16, virtualDiskAccessMask uint32, openVirtualDiskFlags uint32, parameters *openVirtualDiskParameters, handle *syscall.Handle) (win32err error) {
r0, _, _ := syscall.SyscallN(procOpenVirtualDisk.Addr(), uintptr(unsafe.Pointer(virtualStorageType)), uintptr(unsafe.Pointer(path)), uintptr(virtualDiskAccessMask), uintptr(openVirtualDiskFlags), uintptr(unsafe.Pointer(parameters)), uintptr(unsafe.Pointer(handle)))
if r0 != 0 {
win32err = syscall.Errno(r0)
}
return
}

View File

@@ -1,4 +1,6 @@
// Code generated by 'go generate'; DO NOT EDIT.
//go:build windows
// Code generated by 'go generate' using "github.com/Microsoft/go-winio/tools/mkwinsyscall"; DO NOT EDIT.
package winio
@@ -19,6 +21,7 @@ const (
var (
errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
errERROR_EINVAL error = syscall.EINVAL
)
// errnoErr returns common boxed Errno values, to prevent
@@ -26,237 +29,86 @@ var (
func errnoErr(e syscall.Errno) error {
switch e {
case 0:
return nil
return errERROR_EINVAL
case errnoERROR_IO_PENDING:
return errERROR_IO_PENDING
}
// TODO: add more here, after collecting data on the common
// error values see on Windows. (perhaps when running
// all.bat?)
return e
}
var (
modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
modws2_32 = windows.NewLazySystemDLL("ws2_32.dll")
modntdll = windows.NewLazySystemDLL("ntdll.dll")
modadvapi32 = windows.NewLazySystemDLL("advapi32.dll")
modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
modntdll = windows.NewLazySystemDLL("ntdll.dll")
modws2_32 = windows.NewLazySystemDLL("ws2_32.dll")
procCancelIoEx = modkernel32.NewProc("CancelIoEx")
procCreateIoCompletionPort = modkernel32.NewProc("CreateIoCompletionPort")
procGetQueuedCompletionStatus = modkernel32.NewProc("GetQueuedCompletionStatus")
procSetFileCompletionNotificationModes = modkernel32.NewProc("SetFileCompletionNotificationModes")
procWSAGetOverlappedResult = modws2_32.NewProc("WSAGetOverlappedResult")
procConnectNamedPipe = modkernel32.NewProc("ConnectNamedPipe")
procCreateNamedPipeW = modkernel32.NewProc("CreateNamedPipeW")
procCreateFileW = modkernel32.NewProc("CreateFileW")
procGetNamedPipeInfo = modkernel32.NewProc("GetNamedPipeInfo")
procGetNamedPipeHandleStateW = modkernel32.NewProc("GetNamedPipeHandleStateW")
procLocalAlloc = modkernel32.NewProc("LocalAlloc")
procNtCreateNamedPipeFile = modntdll.NewProc("NtCreateNamedPipeFile")
procRtlNtStatusToDosErrorNoTeb = modntdll.NewProc("RtlNtStatusToDosErrorNoTeb")
procRtlDosPathNameToNtPathName_U = modntdll.NewProc("RtlDosPathNameToNtPathName_U")
procRtlDefaultNpAcl = modntdll.NewProc("RtlDefaultNpAcl")
procLookupAccountNameW = modadvapi32.NewProc("LookupAccountNameW")
procConvertSidToStringSidW = modadvapi32.NewProc("ConvertSidToStringSidW")
procConvertStringSecurityDescriptorToSecurityDescriptorW = modadvapi32.NewProc("ConvertStringSecurityDescriptorToSecurityDescriptorW")
procConvertSecurityDescriptorToStringSecurityDescriptorW = modadvapi32.NewProc("ConvertSecurityDescriptorToStringSecurityDescriptorW")
procLocalFree = modkernel32.NewProc("LocalFree")
procGetSecurityDescriptorLength = modadvapi32.NewProc("GetSecurityDescriptorLength")
procGetFileInformationByHandleEx = modkernel32.NewProc("GetFileInformationByHandleEx")
procSetFileInformationByHandle = modkernel32.NewProc("SetFileInformationByHandle")
procAdjustTokenPrivileges = modadvapi32.NewProc("AdjustTokenPrivileges")
procImpersonateSelf = modadvapi32.NewProc("ImpersonateSelf")
procRevertToSelf = modadvapi32.NewProc("RevertToSelf")
procOpenThreadToken = modadvapi32.NewProc("OpenThreadToken")
procGetCurrentThread = modkernel32.NewProc("GetCurrentThread")
procLookupPrivilegeValueW = modadvapi32.NewProc("LookupPrivilegeValueW")
procLookupPrivilegeNameW = modadvapi32.NewProc("LookupPrivilegeNameW")
procLookupPrivilegeDisplayNameW = modadvapi32.NewProc("LookupPrivilegeDisplayNameW")
procBackupRead = modkernel32.NewProc("BackupRead")
procBackupWrite = modkernel32.NewProc("BackupWrite")
procbind = modws2_32.NewProc("bind")
procAdjustTokenPrivileges = modadvapi32.NewProc("AdjustTokenPrivileges")
procConvertSidToStringSidW = modadvapi32.NewProc("ConvertSidToStringSidW")
procConvertStringSidToSidW = modadvapi32.NewProc("ConvertStringSidToSidW")
procImpersonateSelf = modadvapi32.NewProc("ImpersonateSelf")
procLookupAccountNameW = modadvapi32.NewProc("LookupAccountNameW")
procLookupAccountSidW = modadvapi32.NewProc("LookupAccountSidW")
procLookupPrivilegeDisplayNameW = modadvapi32.NewProc("LookupPrivilegeDisplayNameW")
procLookupPrivilegeNameW = modadvapi32.NewProc("LookupPrivilegeNameW")
procLookupPrivilegeValueW = modadvapi32.NewProc("LookupPrivilegeValueW")
procOpenThreadToken = modadvapi32.NewProc("OpenThreadToken")
procRevertToSelf = modadvapi32.NewProc("RevertToSelf")
procBackupRead = modkernel32.NewProc("BackupRead")
procBackupWrite = modkernel32.NewProc("BackupWrite")
procCancelIoEx = modkernel32.NewProc("CancelIoEx")
procConnectNamedPipe = modkernel32.NewProc("ConnectNamedPipe")
procCreateIoCompletionPort = modkernel32.NewProc("CreateIoCompletionPort")
procCreateNamedPipeW = modkernel32.NewProc("CreateNamedPipeW")
procDisconnectNamedPipe = modkernel32.NewProc("DisconnectNamedPipe")
procGetCurrentThread = modkernel32.NewProc("GetCurrentThread")
procGetNamedPipeHandleStateW = modkernel32.NewProc("GetNamedPipeHandleStateW")
procGetNamedPipeInfo = modkernel32.NewProc("GetNamedPipeInfo")
procGetQueuedCompletionStatus = modkernel32.NewProc("GetQueuedCompletionStatus")
procSetFileCompletionNotificationModes = modkernel32.NewProc("SetFileCompletionNotificationModes")
procNtCreateNamedPipeFile = modntdll.NewProc("NtCreateNamedPipeFile")
procRtlDefaultNpAcl = modntdll.NewProc("RtlDefaultNpAcl")
procRtlDosPathNameToNtPathName_U = modntdll.NewProc("RtlDosPathNameToNtPathName_U")
procRtlNtStatusToDosErrorNoTeb = modntdll.NewProc("RtlNtStatusToDosErrorNoTeb")
procWSAGetOverlappedResult = modws2_32.NewProc("WSAGetOverlappedResult")
)
func cancelIoEx(file syscall.Handle, o *syscall.Overlapped) (err error) {
r1, _, e1 := syscall.Syscall(procCancelIoEx.Addr(), 2, uintptr(file), uintptr(unsafe.Pointer(o)), 0)
if r1 == 0 {
if e1 != 0 {
err = errnoErr(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func createIoCompletionPort(file syscall.Handle, port syscall.Handle, key uintptr, threadCount uint32) (newport syscall.Handle, err error) {
r0, _, e1 := syscall.Syscall6(procCreateIoCompletionPort.Addr(), 4, uintptr(file), uintptr(port), uintptr(key), uintptr(threadCount), 0, 0)
newport = syscall.Handle(r0)
if newport == 0 {
if e1 != 0 {
err = errnoErr(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func getQueuedCompletionStatus(port syscall.Handle, bytes *uint32, key *uintptr, o **ioOperation, timeout uint32) (err error) {
r1, _, e1 := syscall.Syscall6(procGetQueuedCompletionStatus.Addr(), 5, uintptr(port), uintptr(unsafe.Pointer(bytes)), uintptr(unsafe.Pointer(key)), uintptr(unsafe.Pointer(o)), uintptr(timeout), 0)
if r1 == 0 {
if e1 != 0 {
err = errnoErr(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func setFileCompletionNotificationModes(h syscall.Handle, flags uint8) (err error) {
r1, _, e1 := syscall.Syscall(procSetFileCompletionNotificationModes.Addr(), 2, uintptr(h), uintptr(flags), 0)
if r1 == 0 {
if e1 != 0 {
err = errnoErr(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func wsaGetOverlappedResult(h syscall.Handle, o *syscall.Overlapped, bytes *uint32, wait bool, flags *uint32) (err error) {
func adjustTokenPrivileges(token windows.Token, releaseAll bool, input *byte, outputSize uint32, output *byte, requiredSize *uint32) (success bool, err error) {
var _p0 uint32
if wait {
if releaseAll {
_p0 = 1
} else {
_p0 = 0
}
r1, _, e1 := syscall.Syscall6(procWSAGetOverlappedResult.Addr(), 5, uintptr(h), uintptr(unsafe.Pointer(o)), uintptr(unsafe.Pointer(bytes)), uintptr(_p0), uintptr(unsafe.Pointer(flags)), 0)
r0, _, e1 := syscall.SyscallN(procAdjustTokenPrivileges.Addr(), uintptr(token), uintptr(_p0), uintptr(unsafe.Pointer(input)), uintptr(outputSize), uintptr(unsafe.Pointer(output)), uintptr(unsafe.Pointer(requiredSize)))
success = r0 != 0
if true {
err = errnoErr(e1)
}
return
}
func convertSidToStringSid(sid *byte, str **uint16) (err error) {
r1, _, e1 := syscall.SyscallN(procConvertSidToStringSidW.Addr(), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(str)))
if r1 == 0 {
if e1 != 0 {
err = errnoErr(e1)
} else {
err = syscall.EINVAL
}
err = errnoErr(e1)
}
return
}
func connectNamedPipe(pipe syscall.Handle, o *syscall.Overlapped) (err error) {
r1, _, e1 := syscall.Syscall(procConnectNamedPipe.Addr(), 2, uintptr(pipe), uintptr(unsafe.Pointer(o)), 0)
func convertStringSidToSid(str *uint16, sid **byte) (err error) {
r1, _, e1 := syscall.SyscallN(procConvertStringSidToSidW.Addr(), uintptr(unsafe.Pointer(str)), uintptr(unsafe.Pointer(sid)))
if r1 == 0 {
if e1 != 0 {
err = errnoErr(e1)
} else {
err = syscall.EINVAL
}
err = errnoErr(e1)
}
return
}
func createNamedPipe(name string, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *syscall.SecurityAttributes) (handle syscall.Handle, err error) {
var _p0 *uint16
_p0, err = syscall.UTF16PtrFromString(name)
if err != nil {
return
}
return _createNamedPipe(_p0, flags, pipeMode, maxInstances, outSize, inSize, defaultTimeout, sa)
}
func _createNamedPipe(name *uint16, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *syscall.SecurityAttributes) (handle syscall.Handle, err error) {
r0, _, e1 := syscall.Syscall9(procCreateNamedPipeW.Addr(), 8, uintptr(unsafe.Pointer(name)), uintptr(flags), uintptr(pipeMode), uintptr(maxInstances), uintptr(outSize), uintptr(inSize), uintptr(defaultTimeout), uintptr(unsafe.Pointer(sa)), 0)
handle = syscall.Handle(r0)
if handle == syscall.InvalidHandle {
if e1 != 0 {
err = errnoErr(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func createFile(name string, access uint32, mode uint32, sa *syscall.SecurityAttributes, createmode uint32, attrs uint32, templatefile syscall.Handle) (handle syscall.Handle, err error) {
var _p0 *uint16
_p0, err = syscall.UTF16PtrFromString(name)
if err != nil {
return
}
return _createFile(_p0, access, mode, sa, createmode, attrs, templatefile)
}
func _createFile(name *uint16, access uint32, mode uint32, sa *syscall.SecurityAttributes, createmode uint32, attrs uint32, templatefile syscall.Handle) (handle syscall.Handle, err error) {
r0, _, e1 := syscall.Syscall9(procCreateFileW.Addr(), 7, uintptr(unsafe.Pointer(name)), uintptr(access), uintptr(mode), uintptr(unsafe.Pointer(sa)), uintptr(createmode), uintptr(attrs), uintptr(templatefile), 0, 0)
handle = syscall.Handle(r0)
if handle == syscall.InvalidHandle {
if e1 != 0 {
err = errnoErr(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func getNamedPipeInfo(pipe syscall.Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error) {
r1, _, e1 := syscall.Syscall6(procGetNamedPipeInfo.Addr(), 5, uintptr(pipe), uintptr(unsafe.Pointer(flags)), uintptr(unsafe.Pointer(outSize)), uintptr(unsafe.Pointer(inSize)), uintptr(unsafe.Pointer(maxInstances)), 0)
func impersonateSelf(level uint32) (err error) {
r1, _, e1 := syscall.SyscallN(procImpersonateSelf.Addr(), uintptr(level))
if r1 == 0 {
if e1 != 0 {
err = errnoErr(e1)
} else {
err = syscall.EINVAL
}
err = errnoErr(e1)
}
return
}
func getNamedPipeHandleState(pipe syscall.Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) {
r1, _, e1 := syscall.Syscall9(procGetNamedPipeHandleStateW.Addr(), 7, uintptr(pipe), uintptr(unsafe.Pointer(state)), uintptr(unsafe.Pointer(curInstances)), uintptr(unsafe.Pointer(maxCollectionCount)), uintptr(unsafe.Pointer(collectDataTimeout)), uintptr(unsafe.Pointer(userName)), uintptr(maxUserNameSize), 0, 0)
if r1 == 0 {
if e1 != 0 {
err = errnoErr(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func localAlloc(uFlags uint32, length uint32) (ptr uintptr) {
r0, _, _ := syscall.Syscall(procLocalAlloc.Addr(), 2, uintptr(uFlags), uintptr(length), 0)
ptr = uintptr(r0)
return
}
func ntCreateNamedPipeFile(pipe *syscall.Handle, access uint32, oa *objectAttributes, iosb *ioStatusBlock, share uint32, disposition uint32, options uint32, typ uint32, readMode uint32, completionMode uint32, maxInstances uint32, inboundQuota uint32, outputQuota uint32, timeout *int64) (status ntstatus) {
r0, _, _ := syscall.Syscall15(procNtCreateNamedPipeFile.Addr(), 14, uintptr(unsafe.Pointer(pipe)), uintptr(access), uintptr(unsafe.Pointer(oa)), uintptr(unsafe.Pointer(iosb)), uintptr(share), uintptr(disposition), uintptr(options), uintptr(typ), uintptr(readMode), uintptr(completionMode), uintptr(maxInstances), uintptr(inboundQuota), uintptr(outputQuota), uintptr(unsafe.Pointer(timeout)), 0)
status = ntstatus(r0)
return
}
func rtlNtStatusToDosError(status ntstatus) (winerr error) {
r0, _, _ := syscall.Syscall(procRtlNtStatusToDosErrorNoTeb.Addr(), 1, uintptr(status), 0, 0)
if r0 != 0 {
winerr = syscall.Errno(r0)
}
return
}
func rtlDosPathNameToNtPathName(name *uint16, ntName *unicodeString, filePart uintptr, reserved uintptr) (status ntstatus) {
r0, _, _ := syscall.Syscall6(procRtlDosPathNameToNtPathName_U.Addr(), 4, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(ntName)), uintptr(filePart), uintptr(reserved), 0, 0)
status = ntstatus(r0)
return
}
func rtlDefaultNpAcl(dacl *uintptr) (status ntstatus) {
r0, _, _ := syscall.Syscall(procRtlDefaultNpAcl.Addr(), 1, uintptr(unsafe.Pointer(dacl)), 0, 0)
status = ntstatus(r0)
return
}
func lookupAccountName(systemName *uint16, accountName string, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) {
var _p0 *uint16
_p0, err = syscall.UTF16PtrFromString(accountName)
@@ -267,164 +119,55 @@ func lookupAccountName(systemName *uint16, accountName string, sid *byte, sidSiz
}
func _lookupAccountName(systemName *uint16, accountName *uint16, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) {
r1, _, e1 := syscall.Syscall9(procLookupAccountNameW.Addr(), 7, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(accountName)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(sidSize)), uintptr(unsafe.Pointer(refDomain)), uintptr(unsafe.Pointer(refDomainSize)), uintptr(unsafe.Pointer(sidNameUse)), 0, 0)
r1, _, e1 := syscall.SyscallN(procLookupAccountNameW.Addr(), uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(accountName)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(sidSize)), uintptr(unsafe.Pointer(refDomain)), uintptr(unsafe.Pointer(refDomainSize)), uintptr(unsafe.Pointer(sidNameUse)))
if r1 == 0 {
if e1 != 0 {
err = errnoErr(e1)
} else {
err = syscall.EINVAL
}
err = errnoErr(e1)
}
return
}
func convertSidToStringSid(sid *byte, str **uint16) (err error) {
r1, _, e1 := syscall.Syscall(procConvertSidToStringSidW.Addr(), 2, uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(str)), 0)
func lookupAccountSid(systemName *uint16, sid *byte, name *uint16, nameSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) {
r1, _, e1 := syscall.SyscallN(procLookupAccountSidW.Addr(), uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(nameSize)), uintptr(unsafe.Pointer(refDomain)), uintptr(unsafe.Pointer(refDomainSize)), uintptr(unsafe.Pointer(sidNameUse)))
if r1 == 0 {
if e1 != 0 {
err = errnoErr(e1)
} else {
err = syscall.EINVAL
}
err = errnoErr(e1)
}
return
}
func convertStringSecurityDescriptorToSecurityDescriptor(str string, revision uint32, sd *uintptr, size *uint32) (err error) {
func lookupPrivilegeDisplayName(systemName string, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) {
var _p0 *uint16
_p0, err = syscall.UTF16PtrFromString(str)
_p0, err = syscall.UTF16PtrFromString(systemName)
if err != nil {
return
}
return _convertStringSecurityDescriptorToSecurityDescriptor(_p0, revision, sd, size)
return _lookupPrivilegeDisplayName(_p0, name, buffer, size, languageId)
}
func _convertStringSecurityDescriptorToSecurityDescriptor(str *uint16, revision uint32, sd *uintptr, size *uint32) (err error) {
r1, _, e1 := syscall.Syscall6(procConvertStringSecurityDescriptorToSecurityDescriptorW.Addr(), 4, uintptr(unsafe.Pointer(str)), uintptr(revision), uintptr(unsafe.Pointer(sd)), uintptr(unsafe.Pointer(size)), 0, 0)
func _lookupPrivilegeDisplayName(systemName *uint16, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) {
r1, _, e1 := syscall.SyscallN(procLookupPrivilegeDisplayNameW.Addr(), uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(buffer)), uintptr(unsafe.Pointer(size)), uintptr(unsafe.Pointer(languageId)))
if r1 == 0 {
if e1 != 0 {
err = errnoErr(e1)
} else {
err = syscall.EINVAL
}
err = errnoErr(e1)
}
return
}
func convertSecurityDescriptorToStringSecurityDescriptor(sd *byte, revision uint32, secInfo uint32, sddl **uint16, sddlSize *uint32) (err error) {
r1, _, e1 := syscall.Syscall6(procConvertSecurityDescriptorToStringSecurityDescriptorW.Addr(), 5, uintptr(unsafe.Pointer(sd)), uintptr(revision), uintptr(secInfo), uintptr(unsafe.Pointer(sddl)), uintptr(unsafe.Pointer(sddlSize)), 0)
func lookupPrivilegeName(systemName string, luid *uint64, buffer *uint16, size *uint32) (err error) {
var _p0 *uint16
_p0, err = syscall.UTF16PtrFromString(systemName)
if err != nil {
return
}
return _lookupPrivilegeName(_p0, luid, buffer, size)
}
func _lookupPrivilegeName(systemName *uint16, luid *uint64, buffer *uint16, size *uint32) (err error) {
r1, _, e1 := syscall.SyscallN(procLookupPrivilegeNameW.Addr(), uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(luid)), uintptr(unsafe.Pointer(buffer)), uintptr(unsafe.Pointer(size)))
if r1 == 0 {
if e1 != 0 {
err = errnoErr(e1)
} else {
err = syscall.EINVAL
}
err = errnoErr(e1)
}
return
}
func localFree(mem uintptr) {
syscall.Syscall(procLocalFree.Addr(), 1, uintptr(mem), 0, 0)
return
}
func getSecurityDescriptorLength(sd uintptr) (len uint32) {
r0, _, _ := syscall.Syscall(procGetSecurityDescriptorLength.Addr(), 1, uintptr(sd), 0, 0)
len = uint32(r0)
return
}
func getFileInformationByHandleEx(h syscall.Handle, class uint32, buffer *byte, size uint32) (err error) {
r1, _, e1 := syscall.Syscall6(procGetFileInformationByHandleEx.Addr(), 4, uintptr(h), uintptr(class), uintptr(unsafe.Pointer(buffer)), uintptr(size), 0, 0)
if r1 == 0 {
if e1 != 0 {
err = errnoErr(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func setFileInformationByHandle(h syscall.Handle, class uint32, buffer *byte, size uint32) (err error) {
r1, _, e1 := syscall.Syscall6(procSetFileInformationByHandle.Addr(), 4, uintptr(h), uintptr(class), uintptr(unsafe.Pointer(buffer)), uintptr(size), 0, 0)
if r1 == 0 {
if e1 != 0 {
err = errnoErr(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func adjustTokenPrivileges(token windows.Token, releaseAll bool, input *byte, outputSize uint32, output *byte, requiredSize *uint32) (success bool, err error) {
var _p0 uint32
if releaseAll {
_p0 = 1
} else {
_p0 = 0
}
r0, _, e1 := syscall.Syscall6(procAdjustTokenPrivileges.Addr(), 6, uintptr(token), uintptr(_p0), uintptr(unsafe.Pointer(input)), uintptr(outputSize), uintptr(unsafe.Pointer(output)), uintptr(unsafe.Pointer(requiredSize)))
success = r0 != 0
if true {
if e1 != 0 {
err = errnoErr(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func impersonateSelf(level uint32) (err error) {
r1, _, e1 := syscall.Syscall(procImpersonateSelf.Addr(), 1, uintptr(level), 0, 0)
if r1 == 0 {
if e1 != 0 {
err = errnoErr(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func revertToSelf() (err error) {
r1, _, e1 := syscall.Syscall(procRevertToSelf.Addr(), 0, 0, 0, 0)
if r1 == 0 {
if e1 != 0 {
err = errnoErr(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func openThreadToken(thread syscall.Handle, accessMask uint32, openAsSelf bool, token *windows.Token) (err error) {
var _p0 uint32
if openAsSelf {
_p0 = 1
} else {
_p0 = 0
}
r1, _, e1 := syscall.Syscall6(procOpenThreadToken.Addr(), 4, uintptr(thread), uintptr(accessMask), uintptr(_p0), uintptr(unsafe.Pointer(token)), 0, 0)
if r1 == 0 {
if e1 != 0 {
err = errnoErr(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func getCurrentThread() (h syscall.Handle) {
r0, _, _ := syscall.Syscall(procGetCurrentThread.Addr(), 0, 0, 0, 0)
h = syscall.Handle(r0)
return
}
func lookupPrivilegeValue(systemName string, name string, luid *uint64) (err error) {
var _p0 *uint16
_p0, err = syscall.UTF16PtrFromString(systemName)
@@ -440,60 +183,34 @@ func lookupPrivilegeValue(systemName string, name string, luid *uint64) (err err
}
func _lookupPrivilegeValue(systemName *uint16, name *uint16, luid *uint64) (err error) {
r1, _, e1 := syscall.Syscall(procLookupPrivilegeValueW.Addr(), 3, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(luid)))
r1, _, e1 := syscall.SyscallN(procLookupPrivilegeValueW.Addr(), uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(luid)))
if r1 == 0 {
if e1 != 0 {
err = errnoErr(e1)
} else {
err = syscall.EINVAL
}
err = errnoErr(e1)
}
return
}
func lookupPrivilegeName(systemName string, luid *uint64, buffer *uint16, size *uint32) (err error) {
var _p0 *uint16
_p0, err = syscall.UTF16PtrFromString(systemName)
if err != nil {
return
func openThreadToken(thread windows.Handle, accessMask uint32, openAsSelf bool, token *windows.Token) (err error) {
var _p0 uint32
if openAsSelf {
_p0 = 1
}
return _lookupPrivilegeName(_p0, luid, buffer, size)
}
func _lookupPrivilegeName(systemName *uint16, luid *uint64, buffer *uint16, size *uint32) (err error) {
r1, _, e1 := syscall.Syscall6(procLookupPrivilegeNameW.Addr(), 4, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(luid)), uintptr(unsafe.Pointer(buffer)), uintptr(unsafe.Pointer(size)), 0, 0)
r1, _, e1 := syscall.SyscallN(procOpenThreadToken.Addr(), uintptr(thread), uintptr(accessMask), uintptr(_p0), uintptr(unsafe.Pointer(token)))
if r1 == 0 {
if e1 != 0 {
err = errnoErr(e1)
} else {
err = syscall.EINVAL
}
err = errnoErr(e1)
}
return
}
func lookupPrivilegeDisplayName(systemName string, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) {
var _p0 *uint16
_p0, err = syscall.UTF16PtrFromString(systemName)
if err != nil {
return
}
return _lookupPrivilegeDisplayName(_p0, name, buffer, size, languageId)
}
func _lookupPrivilegeDisplayName(systemName *uint16, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) {
r1, _, e1 := syscall.Syscall6(procLookupPrivilegeDisplayNameW.Addr(), 5, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(buffer)), uintptr(unsafe.Pointer(size)), uintptr(unsafe.Pointer(languageId)), 0)
func revertToSelf() (err error) {
r1, _, e1 := syscall.SyscallN(procRevertToSelf.Addr())
if r1 == 0 {
if e1 != 0 {
err = errnoErr(e1)
} else {
err = syscall.EINVAL
}
err = errnoErr(e1)
}
return
}
func backupRead(h syscall.Handle, b []byte, bytesRead *uint32, abort bool, processSecurity bool, context *uintptr) (err error) {
func backupRead(h windows.Handle, b []byte, bytesRead *uint32, abort bool, processSecurity bool, context *uintptr) (err error) {
var _p0 *byte
if len(b) > 0 {
_p0 = &b[0]
@@ -501,27 +218,19 @@ func backupRead(h syscall.Handle, b []byte, bytesRead *uint32, abort bool, proce
var _p1 uint32
if abort {
_p1 = 1
} else {
_p1 = 0
}
var _p2 uint32
if processSecurity {
_p2 = 1
} else {
_p2 = 0
}
r1, _, e1 := syscall.Syscall9(procBackupRead.Addr(), 7, uintptr(h), uintptr(unsafe.Pointer(_p0)), uintptr(len(b)), uintptr(unsafe.Pointer(bytesRead)), uintptr(_p1), uintptr(_p2), uintptr(unsafe.Pointer(context)), 0, 0)
r1, _, e1 := syscall.SyscallN(procBackupRead.Addr(), uintptr(h), uintptr(unsafe.Pointer(_p0)), uintptr(len(b)), uintptr(unsafe.Pointer(bytesRead)), uintptr(_p1), uintptr(_p2), uintptr(unsafe.Pointer(context)))
if r1 == 0 {
if e1 != 0 {
err = errnoErr(e1)
} else {
err = syscall.EINVAL
}
err = errnoErr(e1)
}
return
}
func backupWrite(h syscall.Handle, b []byte, bytesWritten *uint32, abort bool, processSecurity bool, context *uintptr) (err error) {
func backupWrite(h windows.Handle, b []byte, bytesWritten *uint32, abort bool, processSecurity bool, context *uintptr) (err error) {
var _p0 *byte
if len(b) > 0 {
_p0 = &b[0]
@@ -529,34 +238,141 @@ func backupWrite(h syscall.Handle, b []byte, bytesWritten *uint32, abort bool, p
var _p1 uint32
if abort {
_p1 = 1
} else {
_p1 = 0
}
var _p2 uint32
if processSecurity {
_p2 = 1
} else {
_p2 = 0
}
r1, _, e1 := syscall.Syscall9(procBackupWrite.Addr(), 7, uintptr(h), uintptr(unsafe.Pointer(_p0)), uintptr(len(b)), uintptr(unsafe.Pointer(bytesWritten)), uintptr(_p1), uintptr(_p2), uintptr(unsafe.Pointer(context)), 0, 0)
r1, _, e1 := syscall.SyscallN(procBackupWrite.Addr(), uintptr(h), uintptr(unsafe.Pointer(_p0)), uintptr(len(b)), uintptr(unsafe.Pointer(bytesWritten)), uintptr(_p1), uintptr(_p2), uintptr(unsafe.Pointer(context)))
if r1 == 0 {
if e1 != 0 {
err = errnoErr(e1)
} else {
err = syscall.EINVAL
}
err = errnoErr(e1)
}
return
}
func bind(s syscall.Handle, name unsafe.Pointer, namelen int32) (err error) {
r1, _, e1 := syscall.Syscall(procbind.Addr(), 3, uintptr(s), uintptr(name), uintptr(namelen))
if r1 == socketError {
if e1 != 0 {
err = errnoErr(e1)
} else {
err = syscall.EINVAL
}
func cancelIoEx(file windows.Handle, o *windows.Overlapped) (err error) {
r1, _, e1 := syscall.SyscallN(procCancelIoEx.Addr(), uintptr(file), uintptr(unsafe.Pointer(o)))
if r1 == 0 {
err = errnoErr(e1)
}
return
}
func connectNamedPipe(pipe windows.Handle, o *windows.Overlapped) (err error) {
r1, _, e1 := syscall.SyscallN(procConnectNamedPipe.Addr(), uintptr(pipe), uintptr(unsafe.Pointer(o)))
if r1 == 0 {
err = errnoErr(e1)
}
return
}
func createIoCompletionPort(file windows.Handle, port windows.Handle, key uintptr, threadCount uint32) (newport windows.Handle, err error) {
r0, _, e1 := syscall.SyscallN(procCreateIoCompletionPort.Addr(), uintptr(file), uintptr(port), uintptr(key), uintptr(threadCount))
newport = windows.Handle(r0)
if newport == 0 {
err = errnoErr(e1)
}
return
}
func createNamedPipe(name string, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *windows.SecurityAttributes) (handle windows.Handle, err error) {
var _p0 *uint16
_p0, err = syscall.UTF16PtrFromString(name)
if err != nil {
return
}
return _createNamedPipe(_p0, flags, pipeMode, maxInstances, outSize, inSize, defaultTimeout, sa)
}
func _createNamedPipe(name *uint16, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *windows.SecurityAttributes) (handle windows.Handle, err error) {
r0, _, e1 := syscall.SyscallN(procCreateNamedPipeW.Addr(), uintptr(unsafe.Pointer(name)), uintptr(flags), uintptr(pipeMode), uintptr(maxInstances), uintptr(outSize), uintptr(inSize), uintptr(defaultTimeout), uintptr(unsafe.Pointer(sa)))
handle = windows.Handle(r0)
if handle == windows.InvalidHandle {
err = errnoErr(e1)
}
return
}
func disconnectNamedPipe(pipe windows.Handle) (err error) {
r1, _, e1 := syscall.SyscallN(procDisconnectNamedPipe.Addr(), uintptr(pipe))
if r1 == 0 {
err = errnoErr(e1)
}
return
}
func getCurrentThread() (h windows.Handle) {
r0, _, _ := syscall.SyscallN(procGetCurrentThread.Addr())
h = windows.Handle(r0)
return
}
func getNamedPipeHandleState(pipe windows.Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) {
r1, _, e1 := syscall.SyscallN(procGetNamedPipeHandleStateW.Addr(), uintptr(pipe), uintptr(unsafe.Pointer(state)), uintptr(unsafe.Pointer(curInstances)), uintptr(unsafe.Pointer(maxCollectionCount)), uintptr(unsafe.Pointer(collectDataTimeout)), uintptr(unsafe.Pointer(userName)), uintptr(maxUserNameSize))
if r1 == 0 {
err = errnoErr(e1)
}
return
}
func getNamedPipeInfo(pipe windows.Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error) {
r1, _, e1 := syscall.SyscallN(procGetNamedPipeInfo.Addr(), uintptr(pipe), uintptr(unsafe.Pointer(flags)), uintptr(unsafe.Pointer(outSize)), uintptr(unsafe.Pointer(inSize)), uintptr(unsafe.Pointer(maxInstances)))
if r1 == 0 {
err = errnoErr(e1)
}
return
}
func getQueuedCompletionStatus(port windows.Handle, bytes *uint32, key *uintptr, o **ioOperation, timeout uint32) (err error) {
r1, _, e1 := syscall.SyscallN(procGetQueuedCompletionStatus.Addr(), uintptr(port), uintptr(unsafe.Pointer(bytes)), uintptr(unsafe.Pointer(key)), uintptr(unsafe.Pointer(o)), uintptr(timeout))
if r1 == 0 {
err = errnoErr(e1)
}
return
}
func setFileCompletionNotificationModes(h windows.Handle, flags uint8) (err error) {
r1, _, e1 := syscall.SyscallN(procSetFileCompletionNotificationModes.Addr(), uintptr(h), uintptr(flags))
if r1 == 0 {
err = errnoErr(e1)
}
return
}
func ntCreateNamedPipeFile(pipe *windows.Handle, access ntAccessMask, oa *objectAttributes, iosb *ioStatusBlock, share ntFileShareMode, disposition ntFileCreationDisposition, options ntFileOptions, typ uint32, readMode uint32, completionMode uint32, maxInstances uint32, inboundQuota uint32, outputQuota uint32, timeout *int64) (status ntStatus) {
r0, _, _ := syscall.SyscallN(procNtCreateNamedPipeFile.Addr(), uintptr(unsafe.Pointer(pipe)), uintptr(access), uintptr(unsafe.Pointer(oa)), uintptr(unsafe.Pointer(iosb)), uintptr(share), uintptr(disposition), uintptr(options), uintptr(typ), uintptr(readMode), uintptr(completionMode), uintptr(maxInstances), uintptr(inboundQuota), uintptr(outputQuota), uintptr(unsafe.Pointer(timeout)))
status = ntStatus(r0)
return
}
func rtlDefaultNpAcl(dacl *uintptr) (status ntStatus) {
r0, _, _ := syscall.SyscallN(procRtlDefaultNpAcl.Addr(), uintptr(unsafe.Pointer(dacl)))
status = ntStatus(r0)
return
}
func rtlDosPathNameToNtPathName(name *uint16, ntName *unicodeString, filePart uintptr, reserved uintptr) (status ntStatus) {
r0, _, _ := syscall.SyscallN(procRtlDosPathNameToNtPathName_U.Addr(), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(ntName)), uintptr(filePart), uintptr(reserved))
status = ntStatus(r0)
return
}
func rtlNtStatusToDosError(status ntStatus) (winerr error) {
r0, _, _ := syscall.SyscallN(procRtlNtStatusToDosErrorNoTeb.Addr(), uintptr(status))
if r0 != 0 {
winerr = syscall.Errno(r0)
}
return
}
func wsaGetOverlappedResult(h windows.Handle, o *windows.Overlapped, bytes *uint32, wait bool, flags *uint32) (err error) {
var _p0 uint32
if wait {
_p0 = 1
}
r1, _, e1 := syscall.SyscallN(procWSAGetOverlappedResult.Addr(), uintptr(h), uintptr(unsafe.Pointer(o)), uintptr(unsafe.Pointer(bytes)), uintptr(_p0), uintptr(unsafe.Pointer(flags)))
if r1 == 0 {
err = errnoErr(e1)
}
return
}

1
vendor/github.com/Microsoft/hcsshim/.gitattributes generated vendored Normal file
View File

@@ -0,0 +1 @@
* text=auto eol=lf

1
vendor/github.com/Microsoft/hcsshim/.gitignore generated vendored Normal file
View File

@@ -0,0 +1 @@
*.exe

17
vendor/github.com/Microsoft/hcsshim/.gometalinter.json generated vendored Normal file
View File

@@ -0,0 +1,17 @@
{
"Vendor": true,
"Deadline": "2m",
"Sort": [
"linter",
"severity",
"path",
"line"
],
"Skip": [
"internal\\schema2"
],
"EnableGC": true,
"Enable": [
"gofmt"
]
}

3
vendor/github.com/Microsoft/hcsshim/CODEOWNERS generated vendored Normal file
View File

@@ -0,0 +1,3 @@
* @microsoft/containerplat
/hcn/* @nagiesek

21
vendor/github.com/Microsoft/hcsshim/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2015 Microsoft
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

54
vendor/github.com/Microsoft/hcsshim/Protobuild.toml generated vendored Normal file
View File

@@ -0,0 +1,54 @@
version = "unstable"
generator = "gogoctrd"
plugins = ["grpc", "fieldpath"]
# Control protoc include paths. Below are usually some good defaults, but feel
# free to try it without them if it works for your project.
[includes]
# Include paths that will be added before all others. Typically, you want to
# treat the root of the project as an include, but this may not be necessary.
before = ["./protobuf"]
# Paths that should be treated as include roots in relation to the vendor
# directory. These will be calculated with the vendor directory nearest the
# target package.
packages = ["github.com/gogo/protobuf"]
# Paths that will be added untouched to the end of the includes. We use
# `/usr/local/include` to pickup the common install location of protobuf.
# This is the default.
after = ["/usr/local/include"]
# This section maps protobuf imports to Go packages. These will become
# `-M` directives in the call to the go protobuf generator.
[packages]
"gogoproto/gogo.proto" = "github.com/gogo/protobuf/gogoproto"
"google/protobuf/any.proto" = "github.com/gogo/protobuf/types"
"google/protobuf/empty.proto" = "github.com/gogo/protobuf/types"
"google/protobuf/descriptor.proto" = "github.com/gogo/protobuf/protoc-gen-gogo/descriptor"
"google/protobuf/field_mask.proto" = "github.com/gogo/protobuf/types"
"google/protobuf/timestamp.proto" = "github.com/gogo/protobuf/types"
"google/protobuf/duration.proto" = "github.com/gogo/protobuf/types"
"github/containerd/cgroups/stats/v1/metrics.proto" = "github.com/containerd/cgroups/stats/v1"
[[overrides]]
prefixes = ["github.com/Microsoft/hcsshim/internal/shimdiag"]
plugins = ["ttrpc"]
# Lock down runhcs config
[[descriptors]]
prefix = "github.com/Microsoft/hcsshim/cmd/containerd-shim-runhcs-v1/options"
target = "cmd/containerd-shim-runhcs-v1/options/next.pb.txt"
ignore_files = [
"google/protobuf/descriptor.proto",
"gogoproto/gogo.proto"
]
[[descriptors]]
prefix = "github.com/Microsoft/hcsshim/cmd/containerd-shim-runhcs-v1/stats"
target = "cmd/containerd-shim-runhcs-v1/stats/next.pb.txt"
ignore_files = [
"google/protobuf/descriptor.proto",
"gogoproto/gogo.proto"
]

Some files were not shown because too many files have changed in this diff Show More