diff --git a/go.mod b/go.mod index 9ed85b0bd..0f3da073a 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,12 @@ go 1.22.7 toolchain go1.23.3 +replace github.com/longhorn/types v0.0.0-20241123075624-48c550af4eab => github.com/chanyilin/types v0.0.0-20241127133205-f9c284b13214 + +replace github.com/longhorn/longhorn-spdk-engine v0.0.0-20241124131155-114edffb76fa => github.com/chanyilin/longhorn-spdk-engine v0.0.0-20241127134412-6c507c791f05 + +replace github.com/longhorn/go-spdk-helper v0.0.0-20241124090314-c396ae715a7f => github.com/chanyilin/go-spdk-helper v0.0.0-20241125130336-15bee7b0eec2 + require ( github.com/google/uuid v1.6.0 github.com/longhorn/backupstore v0.0.0-20241124092526-138305866a87 @@ -31,23 +37,21 @@ require ( github.com/RoaringBitmap/roaring v1.9.4 // indirect github.com/aws/aws-sdk-go v1.55.5 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/bits-and-blooms/bitset v1.12.0 // indirect + github.com/bits-and-blooms/bitset v1.16.0 // indirect github.com/c9s/goprocinfo v0.0.0-20210130143923-c95fcf8c64a8 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/emicklei/go-restful/v3 v3.11.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect - github.com/gammazero/deque v0.2.1 // indirect + github.com/gammazero/deque v1.0.0 // indirect github.com/gammazero/workerpool v1.1.3 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/swag v0.22.4 // indirect - github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/gofrs/flock v0.12.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.4 // indirect @@ -63,23 +67,22 @@ require ( github.com/longhorn/go-iscsi-helper v0.0.0-20241110033836-dd4b01aa15b8 // indirect github.com/longhorn/sparse-tools v0.0.0-20241023025917-7951cd783270 // indirect github.com/mailru/easyjson v0.7.7 // indirect - github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect github.com/mitchellh/go-ps v1.0.0 // indirect - github.com/moby/sys/mountinfo v0.7.1 // indirect + github.com/moby/sys/mountinfo v0.7.2 // indirect + github.com/moby/sys/userns v0.1.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/mschoch/smat v0.2.0 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/opencontainers/runc v1.1.14 // indirect - github.com/opencontainers/runtime-spec v1.1.0 // indirect + github.com/opencontainers/runc v1.2.2 // indirect github.com/pierrec/lz4/v4 v4.1.21 // indirect github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect - github.com/prometheus/client_golang v1.18.0 // indirect - github.com/prometheus/client_model v0.5.0 // indirect - github.com/prometheus/common v0.45.0 // indirect - github.com/prometheus/procfs v0.12.0 // indirect + github.com/prometheus/client_golang v1.20.5 // indirect + github.com/prometheus/client_model v0.6.1 // indirect + github.com/prometheus/common v0.60.1 // indirect + github.com/prometheus/procfs v0.15.1 // indirect github.com/rancher/go-fibmap v0.0.0-20160418233256-5fc9f8c1ed47 // indirect - github.com/rogpeppe/go-internal v1.12.0 // indirect + github.com/rogpeppe/go-internal v1.13.1 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/shirou/gopsutil/v3 v3.24.5 // indirect github.com/slok/goresilience v0.2.0 // indirect @@ -92,7 +95,7 @@ require ( golang.org/x/term v0.26.0 // indirect golang.org/x/text v0.20.0 // indirect golang.org/x/time v0.5.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20241118233622-e639e219e697 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect @@ -101,7 +104,7 @@ require ( k8s.io/client-go v0.31.3 // indirect k8s.io/klog/v2 v2.130.1 // indirect k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect - k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 // indirect + k8s.io/utils v0.0.0-20241104163129-6fe5fd82f078 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect sigs.k8s.io/yaml v1.4.0 // indirect diff --git a/go.sum b/go.sum index cbf56b701..9b7ade63f 100644 --- a/go.sum +++ b/go.sum @@ -20,14 +20,19 @@ github.com/aws/aws-sdk-go v1.55.5/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/bits-and-blooms/bitset v1.12.0 h1:U/q1fAF7xXRhFCrhROzIfffYnu+dlS38vCZtmFVPHmA= github.com/bits-and-blooms/bitset v1.12.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= +github.com/bits-and-blooms/bitset v1.16.0 h1:G3lirLlhFTcW/7ym/SLtYYLHQS0hBOcC8fPNJxbTYm4= +github.com/bits-and-blooms/bitset v1.16.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= github.com/c9s/goprocinfo v0.0.0-20210130143923-c95fcf8c64a8 h1:SjZ2GvvOononHOpK84APFuMvxqsk3tEIaKH/z4Rpu3g= github.com/c9s/goprocinfo v0.0.0-20210130143923-c95fcf8c64a8/go.mod h1:uEyr4WpAH4hio6LFriaPkL938XnrvLpNPmQHBdrmbIE= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= -github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/chanyilin/go-spdk-helper v0.0.0-20241125130336-15bee7b0eec2 h1:I51W69mVJW5M7y5skFz8xBEoJ/HNTtwnZFQ/JdSLXsE= +github.com/chanyilin/go-spdk-helper v0.0.0-20241125130336-15bee7b0eec2/go.mod h1:F4KxpqJXmghH0E3GH0XRSr7M0v5DROFEwaecPbhnGY4= +github.com/chanyilin/longhorn-spdk-engine v0.0.0-20241127134412-6c507c791f05 h1:Dg2c0dIswoMyrC5v2bF10zI4UtJpH3DoKl4hRmVH39w= +github.com/chanyilin/longhorn-spdk-engine v0.0.0-20241127134412-6c507c791f05/go.mod h1:/YpdZE594NV5cHBm/55dNlEU8gy1c8Zwpt2sx2HrOOg= +github.com/chanyilin/types v0.0.0-20241127133205-f9c284b13214 h1:O416DcnlwUcB8TsNqqrfprVT/M3w4Tv3nmH3Q6zSUJU= +github.com/chanyilin/types v0.0.0-20241127133205-f9c284b13214/go.mod h1:dIPa2yMBPOa514bn3pohT7kbVAQcZbZSWItpgxunuPs= github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc= github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -41,8 +46,8 @@ github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2 github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= -github.com/gammazero/deque v0.2.1 h1:qSdsbG6pgp6nL7A0+K/B7s12mcCY/5l5SIUpMOl+dC0= -github.com/gammazero/deque v0.2.1/go.mod h1:LFroj8x4cMYCukHJDbxFCkT+r9AndaJnFMuZDV34tuU= +github.com/gammazero/deque v1.0.0 h1:LTmimT8H7bXkkCy6gZX7zNLtkbz4NdS2z8LZuor3j34= +github.com/gammazero/deque v1.0.0/go.mod h1:iflpYvtGfM3U8S8j+sZEKIak3SAKYpA5/SQewgfXDKo= github.com/gammazero/workerpool v1.1.3 h1:WixN4xzukFoN0XSeXF6puqEqFTl2mECI9S6W44HWy9Q= github.com/gammazero/workerpool v1.1.3/go.mod h1:wPjyBLDbyKnUn2XwwyD3EEwo9dHutia9/fwNmSHWACc= github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= @@ -60,9 +65,6 @@ github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+ github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= -github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= -github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E= github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= @@ -96,6 +98,8 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= +github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= @@ -111,25 +115,19 @@ github.com/longhorn/go-common-libs v0.0.0-20241124035508-d6221574e626 h1:6RHxLM2 github.com/longhorn/go-common-libs v0.0.0-20241124035508-d6221574e626/go.mod h1:gSa+qB058kcNlCaOOwIFPHb3tvqMTmKcxtL7HPTS4o4= github.com/longhorn/go-iscsi-helper v0.0.0-20241110033836-dd4b01aa15b8 h1:vM7FiS3/EVzJGW7AXp0Kcz+15MOHF+VTHz0mlsP+Ngo= github.com/longhorn/go-iscsi-helper v0.0.0-20241110033836-dd4b01aa15b8/go.mod h1:UvAltu/RQZV5i18GcUcGGWA91dzfFR/ylIgKcItsnjk= -github.com/longhorn/go-spdk-helper v0.0.0-20241124090314-c396ae715a7f h1:P/XoCIN6+4q05tCTRAsSsVLMC8c0NV31HCkn+6xKrsc= -github.com/longhorn/go-spdk-helper v0.0.0-20241124090314-c396ae715a7f/go.mod h1:F4KxpqJXmghH0E3GH0XRSr7M0v5DROFEwaecPbhnGY4= github.com/longhorn/longhorn-engine v1.8.0-dev-20241117 h1:2sW/dPj69/XrMDjsh2LBZ2cyOXb5MQBI7HJCuDc2vjs= github.com/longhorn/longhorn-engine v1.8.0-dev-20241117/go.mod h1:3VnMqI8YqJ76XdRvnMWJNp1U1ITAyOwOjKtbYPqLqQw= -github.com/longhorn/longhorn-spdk-engine v0.0.0-20241124131155-114edffb76fa h1:Ck8LhqtqSkqEcXLbWN/2Y/M4RVkJ17VIGhTOpJnAmeM= -github.com/longhorn/longhorn-spdk-engine v0.0.0-20241124131155-114edffb76fa/go.mod h1:A2HD+pUl9CIcOR5zCAFsH5kTndRvniLUnwG8mV3GrLY= github.com/longhorn/sparse-tools v0.0.0-20241023025917-7951cd783270 h1:F13lddDaeUX8dBwRqOT/aXtb2C1szwqIFgW4KpZgCGw= github.com/longhorn/sparse-tools v0.0.0-20241023025917-7951cd783270/go.mod h1:iUJCZtOKG/9xv2rfrUAYZntFTzP5dZtvy4Kwe6dMcUc= -github.com/longhorn/types v0.0.0-20241123075624-48c550af4eab h1:vW/sSHB0U/GPnornD1cdoKSEe9bdBwVKP68cZUs1Xh0= -github.com/longhorn/types v0.0.0-20241123075624-48c550af4eab/go.mod h1:dIPa2yMBPOa514bn3pohT7kbVAQcZbZSWItpgxunuPs= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= -github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= github.com/mitchellh/go-ps v1.0.0 h1:i6ampVEEF4wQFF+bkYfwYgY+F/uYJDktmvLPf7qIgjc= github.com/mitchellh/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg= -github.com/moby/sys/mountinfo v0.7.1 h1:/tTvQaSJRr2FshkhXiIpux6fQ2Zvc4j7tAhMTStAG2g= -github.com/moby/sys/mountinfo v0.7.1/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI= +github.com/moby/sys/mountinfo v0.7.2 h1:1shs6aH5s4o5H2zQLn796ADW1wMrIwHsyJ2v9KouLrg= +github.com/moby/sys/mountinfo v0.7.2/go.mod h1:1YOa8w8Ih7uW0wALDUgT1dTTSBrZ+HiBLGws92L2RU4= +github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g= +github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -143,10 +141,8 @@ github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw= github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= -github.com/opencontainers/runc v1.1.14 h1:rgSuzbmgz5DUJjeSnw337TxDbRuqjs6iqQck/2weR6w= -github.com/opencontainers/runc v1.1.14/go.mod h1:E4C2z+7BxR7GHXp0hAY53mek+x49X1LjPNeMTfRGvOA= -github.com/opencontainers/runtime-spec v1.1.0 h1:HHUyrt9mwHUjtasSbXSMvs4cyFxh+Bll4AjJ9odEGpg= -github.com/opencontainers/runtime-spec v1.1.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runc v1.2.2 h1:jTg3Vw2A5f0N9PoxFTEwUhvpANGaNPT3689Yfd/zaX0= +github.com/opencontainers/runc v1.2.2/go.mod h1:/PXzF0h531HTMsYQnmxXkBD7YaGShm/2zcRB79dksUc= github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ= github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= @@ -160,22 +156,22 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU= github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= -github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= -github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= +github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y= +github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= -github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= +github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= +github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM= -github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY= +github.com/prometheus/common v0.60.1 h1:FUas6GcOw66yB/73KC+BOZoFJmbo/1pojoILArPAaSc= +github.com/prometheus/common v0.60.1/go.mod h1:h0LYf1R1deLSKtD4Vdg8gy4RuOvENW2J/h19V5NADQw= github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= -github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= +github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= +github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/rancher/go-fibmap v0.0.0-20160418233256-5fc9f8c1ed47 h1:JSipdfqjzjD9EMzehVJaS48FXXfC8Bec4japPmWE5pM= github.com/rancher/go-fibmap v0.0.0-20160418233256-5fc9f8c1ed47/go.mod h1:aLaSmp4RuKnOBJO5jFdPH+qkSfLByIGGZVczecL9okc= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= -github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/shirou/gopsutil/v3 v3.24.5 h1:i0t8kL+kQTvpAYToeuiVk3TgDeKOFioZO3Ztz/iZ9pI= @@ -244,7 +240,6 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= @@ -267,8 +262,8 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241118233622-e639e219e697 h1:LWZqQOEjDyONlF1H6afSWpAL/znlREo2tHfLoe+8LMA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241118233622-e639e219e697/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU= google.golang.org/grpc v1.68.0 h1:aHQeeJbo8zAkAa3pRzrVjZlbz6uSfeOXlJNQM0RAbz0= google.golang.org/grpc v1.68.0/go.mod h1:fmSPC5AsjSBCK54MyHRx48kpOti1/jRfOlwEWywNjWA= google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io= @@ -298,8 +293,8 @@ k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7F k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98= k8s.io/mount-utils v0.31.3 h1:CANy3prUYvvDCc2X7ZKgpjpDhAidx4gjGh/WwDrCPq8= k8s.io/mount-utils v0.31.3/go.mod h1:HV/VYBUGqYUj4vt82YltzpWvgv8FPg0G9ItyInT3NPU= -k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A= -k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +k8s.io/utils v0.0.0-20241104163129-6fe5fd82f078 h1:jGnCPejIetjiy2gqaJ5V0NLwTpF4wbQ6cZIItJCSHno= +k8s.io/utils v0.0.0-20241104163129-6fe5fd82f078/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= diff --git a/pkg/api/backing_image.go b/pkg/api/backing_image.go new file mode 100644 index 000000000..58e5ef9d1 --- /dev/null +++ b/pkg/api/backing_image.go @@ -0,0 +1,62 @@ +package api + +import ( + rpc "github.com/longhorn/types/pkg/generated/imrpc" + "google.golang.org/protobuf/types/known/emptypb" +) + +type BackingImage struct { + Name string `json:"name"` + BackingImageUUID string `json:"backing_image_uuid"` + DiskUUID string `json:"disk_uuid"` + Size uint64 `json:"size"` + ExpectedChecksum string `json:"expected_checksum"` + + Status BackingImageStatus `json:"status"` +} + +type BackingImageStatus struct { + Progress int `json:"progress"` + State string `json:"state"` + CurrentChecksum string `json:"currentChecksum"` + ErrorMsg string `json:"errorMsg"` +} + +func RPCToBackingImage(obj *rpc.SPDKBackingImageResponse) *BackingImage { + return &BackingImage{ + Name: obj.Spec.Name, + BackingImageUUID: obj.Spec.BackingImageUuid, + DiskUUID: obj.Spec.DiskUuid, + Size: obj.Spec.Size, + ExpectedChecksum: obj.Spec.Checksum, + + Status: BackingImageStatus{ + Progress: int(obj.Status.Progress), + State: obj.Status.State, + CurrentChecksum: obj.Status.Checksum, + ErrorMsg: obj.Status.ErrorMsg, + }, + } +} + +func RPCToBackingImageList(obj *rpc.SPDKBackingImageListResponse) map[string]*BackingImage { + ret := map[string]*BackingImage{} + for name, bi := range obj.BackingImages { + ret[name] = RPCToBackingImage(bi) + } + return ret +} + +type BackingImageStream struct { + stream rpc.ProxyEngineService_SPDKBackingImageWatchClient +} + +func NewBackingImageStream(stream rpc.ProxyEngineService_SPDKBackingImageWatchClient) *BackingImageStream { + return &BackingImageStream{ + stream, + } +} + +func (s *BackingImageStream) Recv() (*emptypb.Empty, error) { + return s.stream.Recv() +} diff --git a/pkg/client/instance.go b/pkg/client/instance.go index ac47cf5ef..d6bc615b5 100644 --- a/pkg/client/instance.go +++ b/pkg/client/instance.go @@ -95,9 +95,10 @@ type EngineCreateRequest struct { } type ReplicaCreateRequest struct { - DiskName string - DiskUUID string - ExposeRequired bool + DiskName string + DiskUUID string + ExposeRequired bool + BackingImageName string } type InstanceCreateRequest struct { @@ -152,10 +153,11 @@ func (c *InstanceServiceClient) InstanceCreate(req *InstanceCreateRequest) (*api } case types.InstanceTypeReplica: spdkInstanceSpec = &rpc.SpdkInstanceSpec{ - Size: req.Size, - DiskName: req.Replica.DiskName, - DiskUuid: req.Replica.DiskUUID, - ExposeRequired: req.Replica.ExposeRequired, + Size: req.Size, + DiskName: req.Replica.DiskName, + DiskUuid: req.Replica.DiskUUID, + ExposeRequired: req.Replica.ExposeRequired, + BackingImageName: req.Replica.BackingImageName, } default: return nil, fmt.Errorf("failed to create instance: invalid instance type %v", req.InstanceType) diff --git a/pkg/client/proxy_backing_image.go b/pkg/client/proxy_backing_image.go new file mode 100644 index 000000000..ec9eff785 --- /dev/null +++ b/pkg/client/proxy_backing_image.go @@ -0,0 +1,94 @@ +package client + +import ( + "context" + "fmt" + + "github.com/longhorn/longhorn-instance-manager/pkg/api" + "github.com/longhorn/longhorn-instance-manager/pkg/types" + rpc "github.com/longhorn/types/pkg/generated/imrpc" + "github.com/pkg/errors" + "google.golang.org/protobuf/types/known/emptypb" +) + +func (c *ProxyClient) SPDKBackingImageCreate(name, backingImageUUID, diskUUID, checksum, fromAddress, srcLvsUUID string, size uint64) (*api.BackingImage, error) { + if name == "" || backingImageUUID == "" || checksum == "" || diskUUID == "" || size == 0 { + return nil, fmt.Errorf("failed to create backing image: missing required parameters") + } + + client := c.service + ctx, cancel := context.WithTimeout(context.Background(), types.GRPCServiceTimeout) + defer cancel() + + resp, err := client.SPDKBackingImageCreate(ctx, &rpc.SPDKBackingImageCreateRequest{ + Name: name, + BackingImageUuid: backingImageUUID, + DiskUuid: diskUUID, + Size: size, + Checksum: checksum, + FromAddress: fromAddress, + SrcLvsUuid: srcLvsUUID, + }) + if err != nil { + return nil, err + } + + return api.RPCToBackingImage(resp), nil +} + +func (c *ProxyClient) SPDKBackingImageDelete(name, diskUUID string) error { + if name == "" || diskUUID == "" { + return fmt.Errorf("failed to delete backing image: missing required parameters") + } + + client := c.service + ctx, cancel := context.WithTimeout(context.Background(), types.GRPCServiceTimeout) + defer cancel() + + _, err := client.SPDKBackingImageDelete(ctx, &rpc.SPDKBackingImageDeleteRequest{ + Name: name, + DiskUuid: diskUUID, + }) + return err +} + +func (c *ProxyClient) SPDKBackingImageGet(name, diskUUID string) (*api.BackingImage, error) { + if name == "" || diskUUID == "" { + return nil, fmt.Errorf("failed to get backing image: missing required parameters") + } + + client := c.service + ctx, cancel := context.WithTimeout(context.Background(), types.GRPCServiceTimeout) + defer cancel() + + resp, err := client.SPDKBackingImageGet(ctx, &rpc.SPDKBackingImageGetRequest{ + Name: name, + DiskUuid: diskUUID, + }) + if err != nil { + return nil, err + } + return api.RPCToBackingImage(resp), nil +} + +func (c *ProxyClient) SPDKBackingImageList() (map[string]*api.BackingImage, error) { + client := c.service + ctx, cancel := context.WithTimeout(context.Background(), types.GRPCServiceTimeout) + defer cancel() + + resp, err := client.SPDKBackingImageList(ctx, &emptypb.Empty{}) + if err != nil { + return nil, errors.Wrap(err, "failed to list backing images") + } + return api.RPCToBackingImageList(resp), nil +} + +func (c *ProxyClient) SPDKBackingImageWatch(ctx context.Context) (*api.BackingImageStream, error) { + client := c.service + stream, err := client.SPDKBackingImageWatch(ctx, &emptypb.Empty{}) + if err != nil { + return nil, errors.Wrap(err, "failed to open backing image update stream") + } + + return api.NewBackingImageStream(stream), nil +} diff --git a/pkg/instance/instance.go b/pkg/instance/instance.go index a534ed39c..b477c0e88 100644 --- a/pkg/instance/instance.go +++ b/pkg/instance/instance.go @@ -157,7 +157,7 @@ func (ops V2DataEngineInstanceOps) InstanceCreate(req *rpc.InstanceCreateRequest } return engineResponseToInstanceResponse(engine), nil case types.InstanceTypeReplica: - replica, err := c.ReplicaCreate(req.Spec.Name, req.Spec.SpdkInstanceSpec.DiskName, req.Spec.SpdkInstanceSpec.DiskUuid, req.Spec.SpdkInstanceSpec.Size, req.Spec.PortCount) + replica, err := c.ReplicaCreate(req.Spec.Name, req.Spec.SpdkInstanceSpec.DiskName, req.Spec.SpdkInstanceSpec.DiskUuid, req.Spec.SpdkInstanceSpec.Size, req.Spec.PortCount, req.Spec.SpdkInstanceSpec.BackingImageName) if err != nil { return nil, err } diff --git a/pkg/meta/version.go b/pkg/meta/version.go index 39e060291..fb4b81f5d 100644 --- a/pkg/meta/version.go +++ b/pkg/meta/version.go @@ -12,6 +12,10 @@ const ( // InstanceManagerDiskServiceAPIVersion used to communicate with the user e.g. longhorn-manager InstanceManagerDiskServiceAPIVersion = 1 InstanceManagerDiskServiceAPIMinVersion = 1 + + // InstanceManagerBackingImageServiceAPIVersion is used for compatibility check for longhorn-manager + InstanceManagerBackingImageServiceAPIVersion = 1 + InstanceManagerBackingImageServiceAPIMinVersion = 1 ) // Following variables are filled in by main.go @@ -66,3 +70,23 @@ func GetDiskServiceVersion() DiskServiceVersionOutput { InstanceManagerDiskServiceAPIMinVersion: InstanceManagerDiskServiceAPIMinVersion, } } + +type BackingImageServiceVersionOutput struct { + Version string `json:"version"` + GitCommit string `json:"gitCommit"` + BuildDate string `json:"buildDate"` + + InstanceManagerBackingImageServiceAPIVersion int `json:"instanceManagerBackingImageServiceAPIVersion"` + InstanceManagerBackingImageServiceAPIMinVersion int `json:"instanceManagerBackingImageServiceAPIMinVersion"` +} + +func GetBackingImageServiceVersion() BackingImageServiceVersionOutput { + return BackingImageServiceVersionOutput{ + Version: Version, + GitCommit: GitCommit, + BuildDate: BuildDate, + + InstanceManagerBackingImageServiceAPIVersion: InstanceManagerBackingImageServiceAPIVersion, + InstanceManagerBackingImageServiceAPIMinVersion: InstanceManagerBackingImageServiceAPIMinVersion, + } +} diff --git a/pkg/proxy/backing_image.go b/pkg/proxy/backing_image.go new file mode 100644 index 000000000..630bd10ad --- /dev/null +++ b/pkg/proxy/backing_image.go @@ -0,0 +1,212 @@ +package proxy + +import ( + "fmt" + "time" + + grpccodes "google.golang.org/grpc/codes" + grpcstatus "google.golang.org/grpc/status" + + "github.com/pkg/errors" + "github.com/sirupsen/logrus" + "golang.org/x/net/context" + "golang.org/x/sync/errgroup" + "google.golang.org/protobuf/types/known/emptypb" + + spdkapi "github.com/longhorn/longhorn-spdk-engine/pkg/api" + spdkclient "github.com/longhorn/longhorn-spdk-engine/pkg/client" + rpc "github.com/longhorn/types/pkg/generated/imrpc" +) + +const ( + maxMonitorRetryCount = 10 + monitorRetryPollInterval = 1 * time.Second + spdkTgtReadinessProbeTimeout = 60 * time.Second +) + +func (p *Proxy) SPDKBackingImageCreate(ctx context.Context, req *rpc.SPDKBackingImageCreateRequest) (*rpc.SPDKBackingImageResponse, error) { + log := logrus.WithFields(logrus.Fields{ + "name": req.Name, + "backingImageUUID": req.BackingImageUuid, + "diskUuid": req.DiskUuid, + "size": req.Size, + "Checksum": req.Checksum, + "FromAddress": req.FromAddress, + "SrcLvsUuid": req.SrcLvsUuid, + }) + + log.Info("Backing Image Server: Creating SPDk Backing Image") + + if req.Name == "" || req.BackingImageUuid == "" || req.DiskUuid == "" || req.Checksum == "" || req.Size == 0 { + return nil, grpcstatus.Error(grpccodes.InvalidArgument, "failed to create spdk backing image due to parameters missing") + } + + ret, err := p.spdkLocalClient.BackingImageCreate(req.Name, req.BackingImageUuid, req.DiskUuid, req.Size, req.Checksum, req.FromAddress, req.SrcLvsUuid) + if err != nil { + return nil, grpcstatus.Error(grpccodes.Internal, err.Error()) + } + return spdkBackingImageToBackingImageResponse(ret), nil +} + +func (p *Proxy) SPDKBackingImageDelete(ctx context.Context, req *rpc.SPDKBackingImageDeleteRequest) (*emptypb.Empty, error) { + log := logrus.WithFields(logrus.Fields{ + "name": req.Name, + "diskUuid": req.DiskUuid, + }) + log.Info("Backing Image Server: Deleting SPDk Backing Image") + if req.Name == "" || req.DiskUuid == "" { + return nil, grpcstatus.Error(grpccodes.InvalidArgument, "failed to create spdk backing image due to parameters missing") + } + return &emptypb.Empty{}, p.spdkLocalClient.BackingImageDelete(req.Name, req.DiskUuid) +} + +func (p *Proxy) SPDKBackingImageGet(ctx context.Context, req *rpc.SPDKBackingImageGetRequest) (*rpc.SPDKBackingImageResponse, error) { + log := logrus.WithFields(logrus.Fields{ + "name": req.Name, + "diskUuid": req.DiskUuid, + }) + log.Info("Backing Image Server: Get SPDk Backing Image") + if req.Name == "" || req.DiskUuid == "" { + return nil, grpcstatus.Error(grpccodes.InvalidArgument, "failed to create spdk backing image due to parameters missing") + } + ret, err := p.spdkLocalClient.BackingImageGet(req.Name, req.DiskUuid) + if err != nil { + return nil, grpcstatus.Error(grpccodes.Internal, err.Error()) + } + return spdkBackingImageToBackingImageResponse(ret), nil +} + +func (p *Proxy) SPDKBackingImageList(ctx context.Context, req *emptypb.Empty) (*rpc.SPDKBackingImageListResponse, error) { + logrus.Info("Backing Image Server: List SPDk Backing Image") + + backingImages := map[string]*rpc.SPDKBackingImageResponse{} + + ret, err := p.spdkLocalClient.BackingImageList() + if err != nil { + return nil, grpcstatus.Error(grpccodes.Internal, err.Error()) + } + for name, bi := range ret { + // name is in the form of "bi-%s-disk-%s" because one instance-manager manages multiple disks + backingImages[name] = spdkBackingImageToBackingImageResponse(bi) + } + return &rpc.SPDKBackingImageListResponse{BackingImages: backingImages}, nil +} + +func (p *Proxy) SPDKBackingImageWatch(req *emptypb.Empty, srv rpc.ProxyEngineService_SPDKBackingImageWatchServer) error { + logrus.Info("Start watching SPDK backing image") + + done := make(chan struct{}) + + // Create a client for watching SPDK backing image + spdkClient, err := spdkclient.NewSPDKClient(p.spdkServiceAddress) + if err != nil { + done <- struct{}{} + return grpcstatus.Error(grpccodes.Internal, errors.Wrapf(err, "failed to create SPDK client").Error()) + } + + go func() { + <-done + logrus.Info("Stopped clients for watching SPDK backing image") + spdkClient.Close() + close(done) + }() + + notifyChan := make(chan struct{}, 1024) + defer close(notifyChan) + + g, ctx := errgroup.WithContext(p.ctx) + + g.Go(func() error { + defer func() { + // Close the clients for closing streams and unblocking notifier Recv() with error. + done <- struct{}{} + }() + err := p.handleNotify(ctx, notifyChan, srv) + if err != nil { + logrus.WithError(err).Error("Failed to handle notify") + } + return err + }) + + g.Go(func() error { + return p.watchSPDKBackingImage(ctx, req, spdkClient, notifyChan) + }) + + if err := g.Wait(); err != nil { + logrus.WithError(err).Error("Failed to watch backing images") + return errors.Wrap(err, "failed to watch backing images") + } + + return nil +} + +func (p *Proxy) handleNotify(ctx context.Context, notifyChan chan struct{}, srv rpc.ProxyEngineService_SPDKBackingImageWatchServer) error { + logrus.Info("Start handling notify") + + for { + select { + case <-ctx.Done(): + logrus.Info("Stopped handling notify due to the context done") + return ctx.Err() + case <-notifyChan: + if err := srv.Send(&emptypb.Empty{}); err != nil { + return errors.Wrap(err, "failed to send backing image response") + } + } + } +} + +func (p *Proxy) watchSPDKBackingImage(ctx context.Context, req *emptypb.Empty, client *spdkclient.SPDKClient, notifyChan chan struct{}) error { + logrus.Info("Start watching SPDK replicas") + + notifier, err := client.BackingImageWatch(context.Background()) + if err != nil { + return errors.Wrap(err, "failed to create SPDK replica watch notifier") + } + + failureCount := 0 + for { + if failureCount >= maxMonitorRetryCount { + logrus.Errorf("Continuously receiving errors for %v times, stopping watching SPDK backing images", maxMonitorRetryCount) + return fmt.Errorf("continuously receiving errors for %v times, stopping watching SPDK backing images", maxMonitorRetryCount) + } + + select { + case <-ctx.Done(): + logrus.Info("Stopped watching SPDK backing images") + return ctx.Err() + default: + _, err := notifier.Recv() + if err != nil { + status, ok := grpcstatus.FromError(err) + if ok && status.Code() == grpccodes.Canceled { + logrus.WithError(err).Warn("SPDK backing image watch is canceled") + return err + } + logrus.WithError(err).Error("Failed to receive next item in SPDK backing image watch") + time.Sleep(monitorRetryPollInterval) + failureCount++ + } else { + notifyChan <- struct{}{} + } + } + } +} + +func spdkBackingImageToBackingImageResponse(bi *spdkapi.BackingImage) *rpc.SPDKBackingImageResponse { + return &rpc.SPDKBackingImageResponse{ + Spec: &rpc.SPDKBackingImageSpec{ + Name: bi.Name, + BackingImageUuid: bi.BackingImageUUID, + DiskUuid: bi.LvsUUID, + Size: bi.Size, + Checksum: bi.ExpectedChecksum, + }, + Status: &rpc.SPDKBackingImageStatus{ + Progress: bi.Progress, + State: bi.State, + Checksum: bi.CurrentChecksum, + ErrorMsg: bi.ErrorMsg, + }, + } +} diff --git a/pkg/proxy/proxy.go b/pkg/proxy/proxy.go index 79f0b3110..a26f15e61 100644 --- a/pkg/proxy/proxy.go +++ b/pkg/proxy/proxy.go @@ -6,8 +6,11 @@ import ( eclient "github.com/longhorn/longhorn-engine/pkg/controller/client" "github.com/longhorn/types/pkg/generated/enginerpc" + "github.com/pkg/errors" "github.com/sirupsen/logrus" "golang.org/x/net/context" + grpccodes "google.golang.org/grpc/codes" + grpcstatus "google.golang.org/grpc/status" "google.golang.org/protobuf/types/known/emptypb" spdkclient "github.com/longhorn/longhorn-spdk-engine/pkg/client" @@ -58,18 +61,31 @@ type Proxy struct { logsDir string HealthChecker HealthChecker ops map[rpc.DataEngine]ProxyOps + + spdkServiceAddress string + spdkLocalClient *spdkclient.SPDKClient } func NewProxy(ctx context.Context, logsDir, diskServiceAddress, spdkServiceAddress string) (*Proxy, error) { + ops := map[rpc.DataEngine]ProxyOps{ rpc.DataEngine_DATA_ENGINE_V1: V1DataEngineProxyOps{}, rpc.DataEngine_DATA_ENGINE_V2: V2DataEngineProxyOps{}, } + + spdkLocalClient, err := spdkclient.NewSPDKClient(spdkServiceAddress) + if err != nil { + return nil, grpcstatus.Error(grpccodes.Internal, errors.Wrapf(err, "failed to create SPDK client").Error()) + } + p := &Proxy{ ctx: ctx, logsDir: logsDir, HealthChecker: &GRPCHealthChecker{}, ops: ops, + + spdkServiceAddress: spdkServiceAddress, + spdkLocalClient: spdkLocalClient, } go p.startMonitoring() diff --git a/vendor/github.com/bits-and-blooms/bitset/README.md b/vendor/github.com/bits-and-blooms/bitset/README.md index 848234e2f..f48d52a1d 100644 --- a/vendor/github.com/bits-and-blooms/bitset/README.md +++ b/vendor/github.com/bits-and-blooms/bitset/README.md @@ -127,6 +127,23 @@ E.g., The memory usage of a bitset using `N` bits is at least `N/8` bytes. The number of bits in a bitset is at least as large as one plus the greatest bit index you have accessed. Thus it is possible to run out of memory while using a bitset. If you have lots of bits, you might prefer compressed bitsets, like the [Roaring bitmaps](http://roaringbitmap.org) and its [Go implementation](https://github.com/RoaringBitmap/roaring). +The `roaring` library allows you to go back and forth between compressed Roaring bitmaps and the conventional bitset instances: +```Go + mybitset := roaringbitmap.ToBitSet() + newroaringbitmap := roaring.FromBitSet(mybitset) +``` + + +### Goroutine safety + +In general, it not safe to access +the same BitSet using different goroutines--they are +unsynchronized for performance. Should you want to access +a BitSet from more than one goroutine, you should +provide synchronization. Typically this is done by using channels to pass +the *BitSet around (in Go style; so there is only ever one owner), +or by using `sync.Mutex` to serialize operations on BitSets. + ## Implementation Note Go 1.9 introduced a native `math/bits` library. We provide backward compatibility to Go 1.7, which might be removed. diff --git a/vendor/github.com/bits-and-blooms/bitset/bitset.go b/vendor/github.com/bits-and-blooms/bitset/bitset.go index 8fb9e9fa2..5ad1745d4 100644 --- a/vendor/github.com/bits-and-blooms/bitset/bitset.go +++ b/vendor/github.com/bits-and-blooms/bitset/bitset.go @@ -68,9 +68,16 @@ var base64Encoding = base64.URLEncoding // Base64StdEncoding Marshal/Unmarshal BitSet with base64.StdEncoding(Default: base64.URLEncoding) func Base64StdEncoding() { base64Encoding = base64.StdEncoding } -// LittleEndian Marshal/Unmarshal Binary as Little Endian(Default: binary.BigEndian) +// LittleEndian sets Marshal/Unmarshal Binary as Little Endian (Default: binary.BigEndian) func LittleEndian() { binaryOrder = binary.LittleEndian } +// BigEndian sets Marshal/Unmarshal Binary as Big Endian (Default: binary.BigEndian) +func BigEndian() { binaryOrder = binary.BigEndian } + +// BinaryOrder returns the current binary order, see also LittleEndian() +// and BigEndian() to change the order. +func BinaryOrder() binary.ByteOrder { return binaryOrder } + // A BitSet is a set of bits. The zero value of a BitSet is an empty set of length 0. type BitSet struct { length uint @@ -94,17 +101,27 @@ func (b *BitSet) SetBitsetFrom(buf []uint64) { b.set = buf } -// From is a constructor used to create a BitSet from an array of integers +// From is a constructor used to create a BitSet from an array of words func From(buf []uint64) *BitSet { return FromWithLength(uint(len(buf))*64, buf) } -// FromWithLength constructs from an array of integers and length. -func FromWithLength(len uint, set []uint64) *BitSet { - return &BitSet{len, set} +// FromWithLength constructs from an array of words and length in bits. +// This function is for advanced users, most users should prefer +// the From function. +// As a user of FromWithLength, you are responsible for ensuring +// that the length is correct: your slice should have length at +// least (length+63)/64 in 64-bit words. +func FromWithLength(length uint, set []uint64) *BitSet { + if len(set) < wordsNeeded(length) { + panic("BitSet.FromWithLength: slice is too short") + } + return &BitSet{length, set} } -// Bytes returns the bitset as array of integers +// Bytes returns the bitset as array of 64-bit words, giving direct access to the internal representation. +// It is not a copy, so changes to the returned slice will affect the bitset. +// It is meant for advanced users. func (b *BitSet) Bytes() []uint64 { return b.set } @@ -118,7 +135,7 @@ func wordsNeeded(i uint) int { } // wordsNeededUnbound calculates the number of words needed for i bits, possibly exceeding the capacity. -// This function is useful if you know that the capacity cannot be exceeded (e.g., you have an existing bitmap). +// This function is useful if you know that the capacity cannot be exceeded (e.g., you have an existing BitSet). func wordsNeededUnbound(i uint) int { return int((i + (wordSize - 1)) >> log2WordSize) } @@ -147,13 +164,30 @@ func New(length uint) (bset *BitSet) { return bset } +// MustNew creates a new BitSet with the given length bits. +// It panics if length exceeds the possible capacity or by a lack of memory. +func MustNew(length uint) (bset *BitSet) { + if length >= Cap() { + panic("You are exceeding the capacity") + } + + return &BitSet{ + length, + make([]uint64, wordsNeeded(length)), // may panic on lack of memory + } +} + // Cap returns the total possible capacity, or number of bits +// that can be stored in the BitSet theoretically. Under 32-bit system, +// it is 4294967295 and under 64-bit system, it is 18446744073709551615. +// Note that this is further limited by the maximum allocation size in Go, +// and your available memory, as any Go data structure. func Cap() uint { return ^uint(0) } // Len returns the number of bits in the BitSet. -// Note the difference to method Count, see example. +// Note that it differ from Count function. func (b *BitSet) Len() uint { return b.length } @@ -184,12 +218,32 @@ func (b *BitSet) Test(i uint) bool { return b.set[i>>log2WordSize]&(1<> log2WordSize) + subWordIndex := wordsIndex(i) + + // The word that the index falls within, shifted so the index is at bit 0 + var firstWord, secondWord uint64 + if firstWordIndex < len(b.set) { + firstWord = b.set[firstWordIndex] >> subWordIndex + } + + // The next word, masked to only include the necessary bits and shifted to cover the + // top of the word + if (firstWordIndex + 1) < len(b.set) { + secondWord = b.set[firstWordIndex+1] << uint64(wordSize-subWordIndex) + } + + return firstWord | secondWord +} + // Set bit i to 1, the capacity of the bitset is automatically // increased accordingly. -// If i>= Cap(), this function will panic. // Warning: using a very large value for 'i' // may lead to a memory shortage and a panic: the caller is responsible // for providing sensible parameters in line with their memory capacity. +// The memory usage is at least slightly over i/8 bytes. func (b *BitSet) Set(i uint) *BitSet { if i >= b.length { // if we need more bits, make 'em b.extendSet(i) @@ -198,7 +252,7 @@ func (b *BitSet) Set(i uint) *BitSet { return b } -// Clear bit i to 0 +// Clear bit i to 0. This never cause a memory allocation. It is always safe. func (b *BitSet) Clear(i uint) *BitSet { if i >= b.length { return b @@ -208,7 +262,6 @@ func (b *BitSet) Clear(i uint) *BitSet { } // SetTo sets bit i to value. -// If i>= Cap(), this function will panic. // Warning: using a very large value for 'i' // may lead to a memory shortage and a panic: the caller is responsible // for providing sensible parameters in line with their memory capacity. @@ -220,7 +273,6 @@ func (b *BitSet) SetTo(i uint, value bool) *BitSet { } // Flip bit at i. -// If i>= Cap(), this function will panic. // Warning: using a very large value for 'i' // may lead to a memory shortage and a panic: the caller is responsible // for providing sensible parameters in line with their memory capacity. @@ -233,7 +285,6 @@ func (b *BitSet) Flip(i uint) *BitSet { } // FlipRange bit in [start, end). -// If end>= Cap(), this function will panic. // Warning: using a very large value for 'end' // may lead to a memory shortage and a panic: the caller is responsible // for providing sensible parameters in line with their memory capacity. @@ -275,6 +326,7 @@ func (b *BitSet) FlipRange(start, end uint) *BitSet { // memory usage until the GC runs. Normally this should not be a problem, but if you // have an extremely large BitSet its important to understand that the old BitSet will // remain in memory until the GC frees it. +// If you are memory constrained, this function may cause a panic. func (b *BitSet) Shrink(lastbitindex uint) *BitSet { length := lastbitindex + 1 idx := wordsNeeded(length) @@ -294,6 +346,11 @@ func (b *BitSet) Shrink(lastbitindex uint) *BitSet { // Compact shrinks BitSet to so that we preserve all set bits, while minimizing // memory usage. Compact calls Shrink. +// A new slice is allocated to store the new bits, so you may see an increase in +// memory usage until the GC runs. Normally this should not be a problem, but if you +// have an extremely large BitSet its important to understand that the old BitSet will +// remain in memory until the GC frees it. +// If you are memory constrained, this function may cause a panic. func (b *BitSet) Compact() *BitSet { idx := len(b.set) - 1 for ; idx >= 0 && b.set[idx] == 0; idx-- { @@ -353,7 +410,8 @@ func (b *BitSet) InsertAt(idx uint) *BitSet { return b } -// String creates a string representation of the Bitmap +// String creates a string representation of the BitSet. It is only intended for +// human-readable output and not for serialization. func (b *BitSet) String() string { // follows code from https://github.com/RoaringBitmap/roaring var buffer bytes.Buffer @@ -541,7 +599,8 @@ func (b *BitSet) NextClear(i uint) (uint, bool) { return 0, false } -// ClearAll clears the entire BitSet +// ClearAll clears the entire BitSet. +// It does not free the memory. func (b *BitSet) ClearAll() *BitSet { if b != nil && b.set != nil { for i := range b.set { @@ -551,6 +610,18 @@ func (b *BitSet) ClearAll() *BitSet { return b } +// SetAll sets the entire BitSet +func (b *BitSet) SetAll() *BitSet { + if b != nil && b.set != nil { + for i := range b.set { + b.set[i] = allBits + } + + b.cleanLastWord() + } + return b +} + // wordCount returns the number of words used in a bit set func (b *BitSet) wordCount() int { return wordsNeededUnbound(b.length) @@ -725,7 +796,7 @@ func (b *BitSet) Intersection(compare *BitSet) (result *BitSet) { return } -// IntersectionCardinality computes the cardinality of the union +// IntersectionCardinality computes the cardinality of the intersection func (b *BitSet) IntersectionCardinality(compare *BitSet) uint { panicIfNull(b) panicIfNull(compare) @@ -944,7 +1015,9 @@ func (b *BitSet) IsStrictSuperSet(other *BitSet) bool { return b.Count() > other.Count() && b.IsSuperSet(other) } -// DumpAsBits dumps a bit set as a string of bits +// DumpAsBits dumps a bit set as a string of bits. Following the usual convention in Go, +// the least significant bits are printed last (index 0 is at the end of the string). +// This is useful for debugging and testing. It is not suitable for serialization. func (b *BitSet) DumpAsBits() string { if b.set == nil { return "." @@ -1007,6 +1080,15 @@ func writeUint64Array(writer io.Writer, data []uint64) error { // WriteTo writes a BitSet to a stream. The format is: // 1. uint64 length // 2. []uint64 set +// The length is the number of bits in the BitSet. +// +// The set is a slice of uint64s containing between length and length + 63 bits. +// It is interpreted as a big-endian array of uint64s by default (see BinaryOrder()) +// meaning that the first 8 bits are stored at byte index 7, the next 8 bits are stored +// at byte index 6... the bits 64 to 71 are stored at byte index 8, etc. +// If you change the binary order, you need to do so for both reading and writing. +// We recommend using the default binary order. +// // Upon success, the number of bytes written is returned. // // Performance: if this function is used to write to a disk or network @@ -1037,6 +1119,7 @@ func (b *BitSet) WriteTo(stream io.Writer) (int64, error) { // The format is: // 1. uint64 length // 2. []uint64 set +// See WriteTo for details. // Upon success, the number of bytes read is returned. // If the current BitSet is not large enough to hold the data, // it is extended. In case of error, the BitSet is either @@ -1088,6 +1171,7 @@ func (b *BitSet) ReadFrom(stream io.Reader) (int64, error) { } // MarshalBinary encodes a BitSet into a binary form and returns the result. +// Please see WriteTo for details. func (b *BitSet) MarshalBinary() ([]byte, error) { var buf bytes.Buffer _, err := b.WriteTo(&buf) @@ -1099,6 +1183,7 @@ func (b *BitSet) MarshalBinary() ([]byte, error) { } // UnmarshalBinary decodes the binary form generated by MarshalBinary. +// Please see WriteTo for details. func (b *BitSet) UnmarshalBinary(data []byte) error { buf := bytes.NewReader(data) _, err := b.ReadFrom(buf) @@ -1135,3 +1220,155 @@ func (b *BitSet) UnmarshalJSON(data []byte) error { _, err = b.ReadFrom(bytes.NewReader(buf)) return err } + +// Rank returns the nunber of set bits up to and including the index +// that are set in the bitset. +// See https://en.wikipedia.org/wiki/Ranking#Ranking_in_statistics +func (b *BitSet) Rank(index uint) uint { + if index >= b.length { + return b.Count() + } + leftover := (index + 1) & 63 + answer := uint(popcntSlice(b.set[:(index+1)>>6])) + if leftover != 0 { + answer += uint(popcount(b.set[(index+1)>>6] << (64 - leftover))) + } + return answer +} + +// Select returns the index of the jth set bit, where j is the argument. +// The caller is responsible to ensure that 0 <= j < Count(): when j is +// out of range, the function returns the length of the bitset (b.length). +// +// Note that this function differs in convention from the Rank function which +// returns 1 when ranking the smallest value. We follow the conventional +// textbook definition of Select and Rank. +func (b *BitSet) Select(index uint) uint { + leftover := index + for idx, word := range b.set { + w := uint(popcount(word)) + if w > leftover { + return uint(idx)*64 + select64(word, leftover) + } + leftover -= w + } + return b.length +} + +// top detects the top bit set +func (b *BitSet) top() (uint, bool) { + panicIfNull(b) + + idx := len(b.set) - 1 + for ; idx >= 0 && b.set[idx] == 0; idx-- { + } + + // no set bits + if idx < 0 { + return 0, false + } + + return uint(idx)*wordSize + len64(b.set[idx]) - 1, true +} + +// ShiftLeft shifts the bitset like << operation would do. +// +// Left shift may require bitset size extension. We try to avoid the +// unnecessary memory operations by detecting the leftmost set bit. +// The function will panic if shift causes excess of capacity. +func (b *BitSet) ShiftLeft(bits uint) { + panicIfNull(b) + + if bits == 0 { + return + } + + top, ok := b.top() + if !ok { + return + } + + // capacity check + if top+bits < bits { + panic("You are exceeding the capacity") + } + + // destination set + dst := b.set + + // not using extendSet() to avoid unneeded data copying + nsize := wordsNeeded(top + bits) + if len(b.set) < nsize { + dst = make([]uint64, nsize) + } + if top+bits >= b.length { + b.length = top + bits + 1 + } + + pad, idx := top%wordSize, top>>log2WordSize + shift, pages := bits%wordSize, bits>>log2WordSize + if bits%wordSize == 0 { // happy case: just add pages + copy(dst[pages:nsize], b.set) + } else { + if pad+shift >= wordSize { + dst[idx+pages+1] = b.set[idx] >> (wordSize - shift) + } + + for i := int(idx); i >= 0; i-- { + if i > 0 { + dst[i+int(pages)] = (b.set[i] << shift) | (b.set[i-1] >> (wordSize - shift)) + } else { + dst[i+int(pages)] = b.set[i] << shift + } + } + } + + // zeroing extra pages + for i := 0; i < int(pages); i++ { + dst[i] = 0 + } + + b.set = dst +} + +// ShiftRight shifts the bitset like >> operation would do. +func (b *BitSet) ShiftRight(bits uint) { + panicIfNull(b) + + if bits == 0 { + return + } + + top, ok := b.top() + if !ok { + return + } + + if bits >= top { + b.set = make([]uint64, wordsNeeded(b.length)) + return + } + + pad, idx := top%wordSize, top>>log2WordSize + shift, pages := bits%wordSize, bits>>log2WordSize + if bits%wordSize == 0 { // happy case: just clear pages + b.set = b.set[pages:] + b.length -= pages * wordSize + } else { + for i := 0; i <= int(idx-pages); i++ { + if i < int(idx-pages) { + b.set[i] = (b.set[i+int(pages)] >> shift) | (b.set[i+int(pages)+1] << (wordSize - shift)) + } else { + b.set[i] = b.set[i+int(pages)] >> shift + } + } + + if pad < shift { + b.set[int(idx-pages)] = 0 + } + } + + for i := int(idx-pages) + 1; i <= int(idx); i++ { + b.set[i] = 0 + } +} diff --git a/vendor/github.com/bits-and-blooms/bitset/leading_zeros_18.go b/vendor/github.com/bits-and-blooms/bitset/leading_zeros_18.go new file mode 100644 index 000000000..72af1d6fc --- /dev/null +++ b/vendor/github.com/bits-and-blooms/bitset/leading_zeros_18.go @@ -0,0 +1,43 @@ +//go:build !go1.9 +// +build !go1.9 + +package bitset + +var len8tab = "" + + "\x00\x01\x02\x02\x03\x03\x03\x03\x04\x04\x04\x04\x04\x04\x04\x04" + + "\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05" + + "\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06" + + "\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06" + + "\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07" + + "\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07" + + "\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07" + + "\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07" + + "\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08" + + "\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08" + + "\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08" + + "\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08" + + "\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08" + + "\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08" + + "\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08" + + "\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08" + +// len64 returns the minimum number of bits required to represent x; the result is 0 for x == 0. +func len64(x uint64) (n uint) { + if x >= 1<<32 { + x >>= 32 + n = 32 + } + if x >= 1<<16 { + x >>= 16 + n += 16 + } + if x >= 1<<8 { + x >>= 8 + n += 8 + } + return n + uint(len8tab[x]) +} + +func leadingZeroes64(v uint64) uint { + return 64 - len64(v) +} diff --git a/vendor/github.com/bits-and-blooms/bitset/leading_zeros_19.go b/vendor/github.com/bits-and-blooms/bitset/leading_zeros_19.go new file mode 100644 index 000000000..74a794241 --- /dev/null +++ b/vendor/github.com/bits-and-blooms/bitset/leading_zeros_19.go @@ -0,0 +1,14 @@ +//go:build go1.9 +// +build go1.9 + +package bitset + +import "math/bits" + +func len64(v uint64) uint { + return uint(bits.Len64(v)) +} + +func leadingZeroes64(v uint64) uint { + return uint(bits.LeadingZeros64(v)) +} diff --git a/vendor/github.com/bits-and-blooms/bitset/select.go b/vendor/github.com/bits-and-blooms/bitset/select.go new file mode 100644 index 000000000..f15e74a2c --- /dev/null +++ b/vendor/github.com/bits-and-blooms/bitset/select.go @@ -0,0 +1,45 @@ +package bitset + +func select64(w uint64, j uint) uint { + seen := 0 + // Divide 64bit + part := w & 0xFFFFFFFF + n := uint(popcount(part)) + if n <= j { + part = w >> 32 + seen += 32 + j -= n + } + ww := part + + // Divide 32bit + part = ww & 0xFFFF + + n = uint(popcount(part)) + if n <= j { + part = ww >> 16 + seen += 16 + j -= n + } + ww = part + + // Divide 16bit + part = ww & 0xFF + n = uint(popcount(part)) + if n <= j { + part = ww >> 8 + seen += 8 + j -= n + } + ww = part + + // Lookup in final byte + counter := 0 + for ; counter < 8; counter++ { + j -= uint((ww >> counter) & 1) + if j+1 == 0 { + break + } + } + return uint(seen + counter) +} diff --git a/vendor/github.com/coreos/go-systemd/v22/LICENSE b/vendor/github.com/coreos/go-systemd/v22/LICENSE deleted file mode 100644 index 37ec93a14..000000000 --- a/vendor/github.com/coreos/go-systemd/v22/LICENSE +++ /dev/null @@ -1,191 +0,0 @@ -Apache License -Version 2.0, January 2004 -http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - -"License" shall mean the terms and conditions for use, reproduction, and -distribution as defined by Sections 1 through 9 of this document. - -"Licensor" shall mean the copyright owner or entity authorized by the copyright -owner that is granting the License. - -"Legal Entity" shall mean the union of the acting entity and all other entities -that control, are controlled by, or are under common control with that entity. -For the purposes of this definition, "control" means (i) the power, direct or -indirect, to cause the direction or management of such entity, whether by -contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the -outstanding shares, or (iii) beneficial ownership of such entity. - -"You" (or "Your") shall mean an individual or Legal Entity exercising -permissions granted by this License. - -"Source" form shall mean the preferred form for making modifications, including -but not limited to software source code, documentation source, and configuration -files. - -"Object" form shall mean any form resulting from mechanical transformation or -translation of a Source form, including but not limited to compiled object code, -generated documentation, and conversions to other media types. - -"Work" shall mean the work of authorship, whether in Source or Object form, made -available under the License, as indicated by a copyright notice that is included -in or attached to the work (an example is provided in the Appendix below). - -"Derivative Works" shall mean any work, whether in Source or Object form, that -is based on (or derived from) the Work and for which the editorial revisions, -annotations, elaborations, or other modifications represent, as a whole, an -original work of authorship. For the purposes of this License, Derivative Works -shall not include works that remain separable from, or merely link (or bind by -name) to the interfaces of, the Work and Derivative Works thereof. - -"Contribution" shall mean any work of authorship, including the original version -of the Work and any modifications or additions to that Work or Derivative Works -thereof, that is intentionally submitted to Licensor for inclusion in the Work -by the copyright owner or by an individual or Legal Entity authorized to submit -on behalf of the copyright owner. For the purposes of this definition, -"submitted" means any form of electronic, verbal, or written communication sent -to the Licensor or its representatives, including but not limited to -communication on electronic mailing lists, source code control systems, and -issue tracking systems that are managed by, or on behalf of, the Licensor for -the purpose of discussing and improving the Work, but excluding communication -that is conspicuously marked or otherwise designated in writing by the copyright -owner as "Not a Contribution." - -"Contributor" shall mean Licensor and any individual or Legal Entity on behalf -of whom a Contribution has been received by Licensor and subsequently -incorporated within the Work. - -2. Grant of Copyright License. - -Subject to the terms and conditions of this License, each Contributor hereby -grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, -irrevocable copyright license to reproduce, prepare Derivative Works of, -publicly display, publicly perform, sublicense, and distribute the Work and such -Derivative Works in Source or Object form. - -3. Grant of Patent License. - -Subject to the terms and conditions of this License, each Contributor hereby -grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, -irrevocable (except as stated in this section) patent license to make, have -made, use, offer to sell, sell, import, and otherwise transfer the Work, where -such license applies only to those patent claims licensable by such Contributor -that are necessarily infringed by their Contribution(s) alone or by combination -of their Contribution(s) with the Work to which such Contribution(s) was -submitted. If You institute patent litigation against any entity (including a -cross-claim or counterclaim in a lawsuit) alleging that the Work or a -Contribution incorporated within the Work constitutes direct or contributory -patent infringement, then any patent licenses granted to You under this License -for that Work shall terminate as of the date such litigation is filed. - -4. Redistribution. - -You may reproduce and distribute copies of the Work or Derivative Works thereof -in any medium, with or without modifications, and in Source or Object form, -provided that You meet the following conditions: - -You must give any other recipients of the Work or Derivative Works a copy of -this License; and -You must cause any modified files to carry prominent notices stating that You -changed the files; and -You must retain, in the Source form of any Derivative Works that You distribute, -all copyright, patent, trademark, and attribution notices from the Source form -of the Work, excluding those notices that do not pertain to any part of the -Derivative Works; and -If the Work includes a "NOTICE" text file as part of its distribution, then any -Derivative Works that You distribute must include a readable copy of the -attribution notices contained within such NOTICE file, excluding those notices -that do not pertain to any part of the Derivative Works, in at least one of the -following places: within a NOTICE text file distributed as part of the -Derivative Works; within the Source form or documentation, if provided along -with the Derivative Works; or, within a display generated by the Derivative -Works, if and wherever such third-party notices normally appear. The contents of -the NOTICE file are for informational purposes only and do not modify the -License. You may add Your own attribution notices within Derivative Works that -You distribute, alongside or as an addendum to the NOTICE text from the Work, -provided that such additional attribution notices cannot be construed as -modifying the License. -You may add Your own copyright statement to Your modifications and may provide -additional or different license terms and conditions for use, reproduction, or -distribution of Your modifications, or for any such Derivative Works as a whole, -provided Your use, reproduction, and distribution of the Work otherwise complies -with the conditions stated in this License. - -5. Submission of Contributions. - -Unless You explicitly state otherwise, any Contribution intentionally submitted -for inclusion in the Work by You to the Licensor shall be under the terms and -conditions of this License, without any additional terms or conditions. -Notwithstanding the above, nothing herein shall supersede or modify the terms of -any separate license agreement you may have executed with Licensor regarding -such Contributions. - -6. Trademarks. - -This License does not grant permission to use the trade names, trademarks, -service marks, or product names of the Licensor, except as required for -reasonable and customary use in describing the origin of the Work and -reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. - -Unless required by applicable law or agreed to in writing, Licensor provides the -Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, -including, without limitation, any warranties or conditions of TITLE, -NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are -solely responsible for determining the appropriateness of using or -redistributing the Work and assume any risks associated with Your exercise of -permissions under this License. - -8. Limitation of Liability. - -In no event and under no legal theory, whether in tort (including negligence), -contract, or otherwise, unless required by applicable law (such as deliberate -and grossly negligent acts) or agreed to in writing, shall any Contributor be -liable to You for damages, including any direct, indirect, special, incidental, -or consequential damages of any character arising as a result of this License or -out of the use or inability to use the Work (including but not limited to -damages for loss of goodwill, work stoppage, computer failure or malfunction, or -any and all other commercial damages or losses), even if such Contributor has -been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. - -While redistributing the Work or Derivative Works thereof, You may choose to -offer, and charge a fee for, acceptance of support, warranty, indemnity, or -other liability obligations and/or rights consistent with this License. However, -in accepting such obligations, You may act only on Your own behalf and on Your -sole responsibility, not on behalf of any other Contributor, and only if You -agree to indemnify, defend, and hold each Contributor harmless for any liability -incurred by, or claims asserted against, such Contributor by reason of your -accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work - -To apply the Apache License to your work, attach the following boilerplate -notice, with the fields enclosed by brackets "[]" replaced with your own -identifying information. (Don't include the brackets!) The text should be -enclosed in the appropriate comment syntax for the file format. We also -recommend that a file or class name and description of purpose be included on -the same "printed page" as the copyright notice for easier identification within -third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/vendor/github.com/coreos/go-systemd/v22/NOTICE b/vendor/github.com/coreos/go-systemd/v22/NOTICE deleted file mode 100644 index 23a0ada2f..000000000 --- a/vendor/github.com/coreos/go-systemd/v22/NOTICE +++ /dev/null @@ -1,5 +0,0 @@ -CoreOS Project -Copyright 2018 CoreOS, Inc - -This product includes software developed at CoreOS, Inc. -(http://www.coreos.com/). diff --git a/vendor/github.com/coreos/go-systemd/v22/dbus/dbus.go b/vendor/github.com/coreos/go-systemd/v22/dbus/dbus.go deleted file mode 100644 index 147f756fe..000000000 --- a/vendor/github.com/coreos/go-systemd/v22/dbus/dbus.go +++ /dev/null @@ -1,266 +0,0 @@ -// Copyright 2015 CoreOS, Inc. -// -// 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. - -// Integration with the systemd D-Bus API. See http://www.freedesktop.org/wiki/Software/systemd/dbus/ -package dbus - -import ( - "context" - "encoding/hex" - "fmt" - "os" - "strconv" - "strings" - "sync" - - "github.com/godbus/dbus/v5" -) - -const ( - alpha = `abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ` - num = `0123456789` - alphanum = alpha + num - signalBuffer = 100 -) - -// needsEscape checks whether a byte in a potential dbus ObjectPath needs to be escaped -func needsEscape(i int, b byte) bool { - // Escape everything that is not a-z-A-Z-0-9 - // Also escape 0-9 if it's the first character - return strings.IndexByte(alphanum, b) == -1 || - (i == 0 && strings.IndexByte(num, b) != -1) -} - -// PathBusEscape sanitizes a constituent string of a dbus ObjectPath using the -// rules that systemd uses for serializing special characters. -func PathBusEscape(path string) string { - // Special case the empty string - if len(path) == 0 { - return "_" - } - n := []byte{} - for i := 0; i < len(path); i++ { - c := path[i] - if needsEscape(i, c) { - e := fmt.Sprintf("_%x", c) - n = append(n, []byte(e)...) - } else { - n = append(n, c) - } - } - return string(n) -} - -// pathBusUnescape is the inverse of PathBusEscape. -func pathBusUnescape(path string) string { - if path == "_" { - return "" - } - n := []byte{} - for i := 0; i < len(path); i++ { - c := path[i] - if c == '_' && i+2 < len(path) { - res, err := hex.DecodeString(path[i+1 : i+3]) - if err == nil { - n = append(n, res...) - } - i += 2 - } else { - n = append(n, c) - } - } - return string(n) -} - -// Conn is a connection to systemd's dbus endpoint. -type Conn struct { - // sysconn/sysobj are only used to call dbus methods - sysconn *dbus.Conn - sysobj dbus.BusObject - - // sigconn/sigobj are only used to receive dbus signals - sigconn *dbus.Conn - sigobj dbus.BusObject - - jobListener struct { - jobs map[dbus.ObjectPath]chan<- string - sync.Mutex - } - subStateSubscriber struct { - updateCh chan<- *SubStateUpdate - errCh chan<- error - sync.Mutex - ignore map[dbus.ObjectPath]int64 - cleanIgnore int64 - } - propertiesSubscriber struct { - updateCh chan<- *PropertiesUpdate - errCh chan<- error - sync.Mutex - } -} - -// Deprecated: use NewWithContext instead. -func New() (*Conn, error) { - return NewWithContext(context.Background()) -} - -// NewWithContext establishes a connection to any available bus and authenticates. -// Callers should call Close() when done with the connection. -func NewWithContext(ctx context.Context) (*Conn, error) { - conn, err := NewSystemConnectionContext(ctx) - if err != nil && os.Geteuid() == 0 { - return NewSystemdConnectionContext(ctx) - } - return conn, err -} - -// Deprecated: use NewSystemConnectionContext instead. -func NewSystemConnection() (*Conn, error) { - return NewSystemConnectionContext(context.Background()) -} - -// NewSystemConnectionContext establishes a connection to the system bus and authenticates. -// Callers should call Close() when done with the connection. -func NewSystemConnectionContext(ctx context.Context) (*Conn, error) { - return NewConnection(func() (*dbus.Conn, error) { - return dbusAuthHelloConnection(ctx, dbus.SystemBusPrivate) - }) -} - -// Deprecated: use NewUserConnectionContext instead. -func NewUserConnection() (*Conn, error) { - return NewUserConnectionContext(context.Background()) -} - -// NewUserConnectionContext establishes a connection to the session bus and -// authenticates. This can be used to connect to systemd user instances. -// Callers should call Close() when done with the connection. -func NewUserConnectionContext(ctx context.Context) (*Conn, error) { - return NewConnection(func() (*dbus.Conn, error) { - return dbusAuthHelloConnection(ctx, dbus.SessionBusPrivate) - }) -} - -// Deprecated: use NewSystemdConnectionContext instead. -func NewSystemdConnection() (*Conn, error) { - return NewSystemdConnectionContext(context.Background()) -} - -// NewSystemdConnectionContext establishes a private, direct connection to systemd. -// This can be used for communicating with systemd without a dbus daemon. -// Callers should call Close() when done with the connection. -func NewSystemdConnectionContext(ctx context.Context) (*Conn, error) { - return NewConnection(func() (*dbus.Conn, error) { - // We skip Hello when talking directly to systemd. - return dbusAuthConnection(ctx, func(opts ...dbus.ConnOption) (*dbus.Conn, error) { - return dbus.Dial("unix:path=/run/systemd/private", opts...) - }) - }) -} - -// Close closes an established connection. -func (c *Conn) Close() { - c.sysconn.Close() - c.sigconn.Close() -} - -// Connected returns whether conn is connected -func (c *Conn) Connected() bool { - return c.sysconn.Connected() && c.sigconn.Connected() -} - -// NewConnection establishes a connection to a bus using a caller-supplied function. -// This allows connecting to remote buses through a user-supplied mechanism. -// The supplied function may be called multiple times, and should return independent connections. -// The returned connection must be fully initialised: the org.freedesktop.DBus.Hello call must have succeeded, -// and any authentication should be handled by the function. -func NewConnection(dialBus func() (*dbus.Conn, error)) (*Conn, error) { - sysconn, err := dialBus() - if err != nil { - return nil, err - } - - sigconn, err := dialBus() - if err != nil { - sysconn.Close() - return nil, err - } - - c := &Conn{ - sysconn: sysconn, - sysobj: systemdObject(sysconn), - sigconn: sigconn, - sigobj: systemdObject(sigconn), - } - - c.subStateSubscriber.ignore = make(map[dbus.ObjectPath]int64) - c.jobListener.jobs = make(map[dbus.ObjectPath]chan<- string) - - // Setup the listeners on jobs so that we can get completions - c.sigconn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0, - "type='signal', interface='org.freedesktop.systemd1.Manager', member='JobRemoved'") - - c.dispatch() - return c, nil -} - -// GetManagerProperty returns the value of a property on the org.freedesktop.systemd1.Manager -// interface. The value is returned in its string representation, as defined at -// https://developer.gnome.org/glib/unstable/gvariant-text.html. -func (c *Conn) GetManagerProperty(prop string) (string, error) { - variant, err := c.sysobj.GetProperty("org.freedesktop.systemd1.Manager." + prop) - if err != nil { - return "", err - } - return variant.String(), nil -} - -func dbusAuthConnection(ctx context.Context, createBus func(opts ...dbus.ConnOption) (*dbus.Conn, error)) (*dbus.Conn, error) { - conn, err := createBus(dbus.WithContext(ctx)) - if err != nil { - return nil, err - } - - // Only use EXTERNAL method, and hardcode the uid (not username) - // to avoid a username lookup (which requires a dynamically linked - // libc) - methods := []dbus.Auth{dbus.AuthExternal(strconv.Itoa(os.Getuid()))} - - err = conn.Auth(methods) - if err != nil { - conn.Close() - return nil, err - } - - return conn, nil -} - -func dbusAuthHelloConnection(ctx context.Context, createBus func(opts ...dbus.ConnOption) (*dbus.Conn, error)) (*dbus.Conn, error) { - conn, err := dbusAuthConnection(ctx, createBus) - if err != nil { - return nil, err - } - - if err = conn.Hello(); err != nil { - conn.Close() - return nil, err - } - - return conn, nil -} - -func systemdObject(conn *dbus.Conn) dbus.BusObject { - return conn.Object("org.freedesktop.systemd1", dbus.ObjectPath("/org/freedesktop/systemd1")) -} diff --git a/vendor/github.com/coreos/go-systemd/v22/dbus/methods.go b/vendor/github.com/coreos/go-systemd/v22/dbus/methods.go deleted file mode 100644 index 074148cb4..000000000 --- a/vendor/github.com/coreos/go-systemd/v22/dbus/methods.go +++ /dev/null @@ -1,864 +0,0 @@ -// Copyright 2015, 2018 CoreOS, Inc. -// -// 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 dbus - -import ( - "context" - "errors" - "fmt" - "path" - "strconv" - - "github.com/godbus/dbus/v5" -) - -// Who can be used to specify which process to kill in the unit via the KillUnitWithTarget API -type Who string - -const ( - // All sends the signal to all processes in the unit - All Who = "all" - // Main sends the signal to the main process of the unit - Main Who = "main" - // Control sends the signal to the control process of the unit - Control Who = "control" -) - -func (c *Conn) jobComplete(signal *dbus.Signal) { - var id uint32 - var job dbus.ObjectPath - var unit string - var result string - dbus.Store(signal.Body, &id, &job, &unit, &result) - c.jobListener.Lock() - out, ok := c.jobListener.jobs[job] - if ok { - out <- result - delete(c.jobListener.jobs, job) - } - c.jobListener.Unlock() -} - -func (c *Conn) startJob(ctx context.Context, ch chan<- string, job string, args ...interface{}) (int, error) { - if ch != nil { - c.jobListener.Lock() - defer c.jobListener.Unlock() - } - - var p dbus.ObjectPath - err := c.sysobj.CallWithContext(ctx, job, 0, args...).Store(&p) - if err != nil { - return 0, err - } - - if ch != nil { - c.jobListener.jobs[p] = ch - } - - // ignore error since 0 is fine if conversion fails - jobID, _ := strconv.Atoi(path.Base(string(p))) - - return jobID, nil -} - -// Deprecated: use StartUnitContext instead. -func (c *Conn) StartUnit(name string, mode string, ch chan<- string) (int, error) { - return c.StartUnitContext(context.Background(), name, mode, ch) -} - -// StartUnitContext enqueues a start job and depending jobs, if any (unless otherwise -// specified by the mode string). -// -// Takes the unit to activate, plus a mode string. The mode needs to be one of -// replace, fail, isolate, ignore-dependencies, ignore-requirements. If -// "replace" the call will start the unit and its dependencies, possibly -// replacing already queued jobs that conflict with this. If "fail" the call -// will start the unit and its dependencies, but will fail if this would change -// an already queued job. If "isolate" the call will start the unit in question -// and terminate all units that aren't dependencies of it. If -// "ignore-dependencies" it will start a unit but ignore all its dependencies. -// If "ignore-requirements" it will start a unit but only ignore the -// requirement dependencies. It is not recommended to make use of the latter -// two options. -// -// If the provided channel is non-nil, a result string will be sent to it upon -// job completion: one of done, canceled, timeout, failed, dependency, skipped. -// done indicates successful execution of a job. canceled indicates that a job -// has been canceled before it finished execution. timeout indicates that the -// job timeout was reached. failed indicates that the job failed. dependency -// indicates that a job this job has been depending on failed and the job hence -// has been removed too. skipped indicates that a job was skipped because it -// didn't apply to the units current state. -// -// If no error occurs, the ID of the underlying systemd job will be returned. There -// does exist the possibility for no error to be returned, but for the returned job -// ID to be 0. In this case, the actual underlying ID is not 0 and this datapoint -// should not be considered authoritative. -// -// If an error does occur, it will be returned to the user alongside a job ID of 0. -func (c *Conn) StartUnitContext(ctx context.Context, name string, mode string, ch chan<- string) (int, error) { - return c.startJob(ctx, ch, "org.freedesktop.systemd1.Manager.StartUnit", name, mode) -} - -// Deprecated: use StopUnitContext instead. -func (c *Conn) StopUnit(name string, mode string, ch chan<- string) (int, error) { - return c.StopUnitContext(context.Background(), name, mode, ch) -} - -// StopUnitContext is similar to StartUnitContext, but stops the specified unit -// rather than starting it. -func (c *Conn) StopUnitContext(ctx context.Context, name string, mode string, ch chan<- string) (int, error) { - return c.startJob(ctx, ch, "org.freedesktop.systemd1.Manager.StopUnit", name, mode) -} - -// Deprecated: use ReloadUnitContext instead. -func (c *Conn) ReloadUnit(name string, mode string, ch chan<- string) (int, error) { - return c.ReloadUnitContext(context.Background(), name, mode, ch) -} - -// ReloadUnitContext reloads a unit. Reloading is done only if the unit -// is already running, and fails otherwise. -func (c *Conn) ReloadUnitContext(ctx context.Context, name string, mode string, ch chan<- string) (int, error) { - return c.startJob(ctx, ch, "org.freedesktop.systemd1.Manager.ReloadUnit", name, mode) -} - -// Deprecated: use RestartUnitContext instead. -func (c *Conn) RestartUnit(name string, mode string, ch chan<- string) (int, error) { - return c.RestartUnitContext(context.Background(), name, mode, ch) -} - -// RestartUnitContext restarts a service. If a service is restarted that isn't -// running it will be started. -func (c *Conn) RestartUnitContext(ctx context.Context, name string, mode string, ch chan<- string) (int, error) { - return c.startJob(ctx, ch, "org.freedesktop.systemd1.Manager.RestartUnit", name, mode) -} - -// Deprecated: use TryRestartUnitContext instead. -func (c *Conn) TryRestartUnit(name string, mode string, ch chan<- string) (int, error) { - return c.TryRestartUnitContext(context.Background(), name, mode, ch) -} - -// TryRestartUnitContext is like RestartUnitContext, except that a service that -// isn't running is not affected by the restart. -func (c *Conn) TryRestartUnitContext(ctx context.Context, name string, mode string, ch chan<- string) (int, error) { - return c.startJob(ctx, ch, "org.freedesktop.systemd1.Manager.TryRestartUnit", name, mode) -} - -// Deprecated: use ReloadOrRestartUnitContext instead. -func (c *Conn) ReloadOrRestartUnit(name string, mode string, ch chan<- string) (int, error) { - return c.ReloadOrRestartUnitContext(context.Background(), name, mode, ch) -} - -// ReloadOrRestartUnitContext attempts a reload if the unit supports it and use -// a restart otherwise. -func (c *Conn) ReloadOrRestartUnitContext(ctx context.Context, name string, mode string, ch chan<- string) (int, error) { - return c.startJob(ctx, ch, "org.freedesktop.systemd1.Manager.ReloadOrRestartUnit", name, mode) -} - -// Deprecated: use ReloadOrTryRestartUnitContext instead. -func (c *Conn) ReloadOrTryRestartUnit(name string, mode string, ch chan<- string) (int, error) { - return c.ReloadOrTryRestartUnitContext(context.Background(), name, mode, ch) -} - -// ReloadOrTryRestartUnitContext attempts a reload if the unit supports it, -// and use a "Try" flavored restart otherwise. -func (c *Conn) ReloadOrTryRestartUnitContext(ctx context.Context, name string, mode string, ch chan<- string) (int, error) { - return c.startJob(ctx, ch, "org.freedesktop.systemd1.Manager.ReloadOrTryRestartUnit", name, mode) -} - -// Deprecated: use StartTransientUnitContext instead. -func (c *Conn) StartTransientUnit(name string, mode string, properties []Property, ch chan<- string) (int, error) { - return c.StartTransientUnitContext(context.Background(), name, mode, properties, ch) -} - -// StartTransientUnitContext may be used to create and start a transient unit, which -// will be released as soon as it is not running or referenced anymore or the -// system is rebooted. name is the unit name including suffix, and must be -// unique. mode is the same as in StartUnitContext, properties contains properties -// of the unit. -func (c *Conn) StartTransientUnitContext(ctx context.Context, name string, mode string, properties []Property, ch chan<- string) (int, error) { - return c.startJob(ctx, ch, "org.freedesktop.systemd1.Manager.StartTransientUnit", name, mode, properties, make([]PropertyCollection, 0)) -} - -// Deprecated: use KillUnitContext instead. -func (c *Conn) KillUnit(name string, signal int32) { - c.KillUnitContext(context.Background(), name, signal) -} - -// KillUnitContext takes the unit name and a UNIX signal number to send. -// All of the unit's processes are killed. -func (c *Conn) KillUnitContext(ctx context.Context, name string, signal int32) { - c.KillUnitWithTarget(ctx, name, All, signal) -} - -// KillUnitWithTarget is like KillUnitContext, but allows you to specify which -// process in the unit to send the signal to. -func (c *Conn) KillUnitWithTarget(ctx context.Context, name string, target Who, signal int32) error { - return c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.KillUnit", 0, name, string(target), signal).Store() -} - -// Deprecated: use ResetFailedUnitContext instead. -func (c *Conn) ResetFailedUnit(name string) error { - return c.ResetFailedUnitContext(context.Background(), name) -} - -// ResetFailedUnitContext resets the "failed" state of a specific unit. -func (c *Conn) ResetFailedUnitContext(ctx context.Context, name string) error { - return c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.ResetFailedUnit", 0, name).Store() -} - -// Deprecated: use SystemStateContext instead. -func (c *Conn) SystemState() (*Property, error) { - return c.SystemStateContext(context.Background()) -} - -// SystemStateContext returns the systemd state. Equivalent to -// systemctl is-system-running. -func (c *Conn) SystemStateContext(ctx context.Context) (*Property, error) { - var err error - var prop dbus.Variant - - obj := c.sysconn.Object("org.freedesktop.systemd1", "/org/freedesktop/systemd1") - err = obj.CallWithContext(ctx, "org.freedesktop.DBus.Properties.Get", 0, "org.freedesktop.systemd1.Manager", "SystemState").Store(&prop) - if err != nil { - return nil, err - } - - return &Property{Name: "SystemState", Value: prop}, nil -} - -// getProperties takes the unit path and returns all of its dbus object properties, for the given dbus interface. -func (c *Conn) getProperties(ctx context.Context, path dbus.ObjectPath, dbusInterface string) (map[string]interface{}, error) { - var err error - var props map[string]dbus.Variant - - if !path.IsValid() { - return nil, fmt.Errorf("invalid unit name: %v", path) - } - - obj := c.sysconn.Object("org.freedesktop.systemd1", path) - err = obj.CallWithContext(ctx, "org.freedesktop.DBus.Properties.GetAll", 0, dbusInterface).Store(&props) - if err != nil { - return nil, err - } - - out := make(map[string]interface{}, len(props)) - for k, v := range props { - out[k] = v.Value() - } - - return out, nil -} - -// Deprecated: use GetUnitPropertiesContext instead. -func (c *Conn) GetUnitProperties(unit string) (map[string]interface{}, error) { - return c.GetUnitPropertiesContext(context.Background(), unit) -} - -// GetUnitPropertiesContext takes the (unescaped) unit name and returns all of -// its dbus object properties. -func (c *Conn) GetUnitPropertiesContext(ctx context.Context, unit string) (map[string]interface{}, error) { - path := unitPath(unit) - return c.getProperties(ctx, path, "org.freedesktop.systemd1.Unit") -} - -// Deprecated: use GetUnitPathPropertiesContext instead. -func (c *Conn) GetUnitPathProperties(path dbus.ObjectPath) (map[string]interface{}, error) { - return c.GetUnitPathPropertiesContext(context.Background(), path) -} - -// GetUnitPathPropertiesContext takes the (escaped) unit path and returns all -// of its dbus object properties. -func (c *Conn) GetUnitPathPropertiesContext(ctx context.Context, path dbus.ObjectPath) (map[string]interface{}, error) { - return c.getProperties(ctx, path, "org.freedesktop.systemd1.Unit") -} - -// Deprecated: use GetAllPropertiesContext instead. -func (c *Conn) GetAllProperties(unit string) (map[string]interface{}, error) { - return c.GetAllPropertiesContext(context.Background(), unit) -} - -// GetAllPropertiesContext takes the (unescaped) unit name and returns all of -// its dbus object properties. -func (c *Conn) GetAllPropertiesContext(ctx context.Context, unit string) (map[string]interface{}, error) { - path := unitPath(unit) - return c.getProperties(ctx, path, "") -} - -func (c *Conn) getProperty(ctx context.Context, unit string, dbusInterface string, propertyName string) (*Property, error) { - var err error - var prop dbus.Variant - - path := unitPath(unit) - if !path.IsValid() { - return nil, errors.New("invalid unit name: " + unit) - } - - obj := c.sysconn.Object("org.freedesktop.systemd1", path) - err = obj.CallWithContext(ctx, "org.freedesktop.DBus.Properties.Get", 0, dbusInterface, propertyName).Store(&prop) - if err != nil { - return nil, err - } - - return &Property{Name: propertyName, Value: prop}, nil -} - -// Deprecated: use GetUnitPropertyContext instead. -func (c *Conn) GetUnitProperty(unit string, propertyName string) (*Property, error) { - return c.GetUnitPropertyContext(context.Background(), unit, propertyName) -} - -// GetUnitPropertyContext takes an (unescaped) unit name, and a property name, -// and returns the property value. -func (c *Conn) GetUnitPropertyContext(ctx context.Context, unit string, propertyName string) (*Property, error) { - return c.getProperty(ctx, unit, "org.freedesktop.systemd1.Unit", propertyName) -} - -// Deprecated: use GetServicePropertyContext instead. -func (c *Conn) GetServiceProperty(service string, propertyName string) (*Property, error) { - return c.GetServicePropertyContext(context.Background(), service, propertyName) -} - -// GetServiceProperty returns property for given service name and property name. -func (c *Conn) GetServicePropertyContext(ctx context.Context, service string, propertyName string) (*Property, error) { - return c.getProperty(ctx, service, "org.freedesktop.systemd1.Service", propertyName) -} - -// Deprecated: use GetUnitTypePropertiesContext instead. -func (c *Conn) GetUnitTypeProperties(unit string, unitType string) (map[string]interface{}, error) { - return c.GetUnitTypePropertiesContext(context.Background(), unit, unitType) -} - -// GetUnitTypePropertiesContext returns the extra properties for a unit, specific to the unit type. -// Valid values for unitType: Service, Socket, Target, Device, Mount, Automount, Snapshot, Timer, Swap, Path, Slice, Scope. -// Returns "dbus.Error: Unknown interface" error if the unitType is not the correct type of the unit. -func (c *Conn) GetUnitTypePropertiesContext(ctx context.Context, unit string, unitType string) (map[string]interface{}, error) { - path := unitPath(unit) - return c.getProperties(ctx, path, "org.freedesktop.systemd1."+unitType) -} - -// Deprecated: use SetUnitPropertiesContext instead. -func (c *Conn) SetUnitProperties(name string, runtime bool, properties ...Property) error { - return c.SetUnitPropertiesContext(context.Background(), name, runtime, properties...) -} - -// SetUnitPropertiesContext may be used to modify certain unit properties at runtime. -// Not all properties may be changed at runtime, but many resource management -// settings (primarily those in systemd.cgroup(5)) may. The changes are applied -// instantly, and stored on disk for future boots, unless runtime is true, in which -// case the settings only apply until the next reboot. name is the name of the unit -// to modify. properties are the settings to set, encoded as an array of property -// name and value pairs. -func (c *Conn) SetUnitPropertiesContext(ctx context.Context, name string, runtime bool, properties ...Property) error { - return c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.SetUnitProperties", 0, name, runtime, properties).Store() -} - -// Deprecated: use GetUnitTypePropertyContext instead. -func (c *Conn) GetUnitTypeProperty(unit string, unitType string, propertyName string) (*Property, error) { - return c.GetUnitTypePropertyContext(context.Background(), unit, unitType, propertyName) -} - -// GetUnitTypePropertyContext takes a property name, a unit name, and a unit type, -// and returns a property value. For valid values of unitType, see GetUnitTypePropertiesContext. -func (c *Conn) GetUnitTypePropertyContext(ctx context.Context, unit string, unitType string, propertyName string) (*Property, error) { - return c.getProperty(ctx, unit, "org.freedesktop.systemd1."+unitType, propertyName) -} - -type UnitStatus struct { - Name string // The primary unit name as string - Description string // The human readable description string - LoadState string // The load state (i.e. whether the unit file has been loaded successfully) - ActiveState string // The active state (i.e. whether the unit is currently started or not) - SubState string // The sub state (a more fine-grained version of the active state that is specific to the unit type, which the active state is not) - Followed string // A unit that is being followed in its state by this unit, if there is any, otherwise the empty string. - Path dbus.ObjectPath // The unit object path - JobId uint32 // If there is a job queued for the job unit the numeric job id, 0 otherwise - JobType string // The job type as string - JobPath dbus.ObjectPath // The job object path -} - -type storeFunc func(retvalues ...interface{}) error - -func (c *Conn) listUnitsInternal(f storeFunc) ([]UnitStatus, error) { - result := make([][]interface{}, 0) - err := f(&result) - if err != nil { - return nil, err - } - - resultInterface := make([]interface{}, len(result)) - for i := range result { - resultInterface[i] = result[i] - } - - status := make([]UnitStatus, len(result)) - statusInterface := make([]interface{}, len(status)) - for i := range status { - statusInterface[i] = &status[i] - } - - err = dbus.Store(resultInterface, statusInterface...) - if err != nil { - return nil, err - } - - return status, nil -} - -// GetUnitByPID returns the unit object path of the unit a process ID -// belongs to. It takes a UNIX PID and returns the object path. The PID must -// refer to an existing system process -func (c *Conn) GetUnitByPID(ctx context.Context, pid uint32) (dbus.ObjectPath, error) { - var result dbus.ObjectPath - - err := c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.GetUnitByPID", 0, pid).Store(&result) - - return result, err -} - -// GetUnitNameByPID returns the name of the unit a process ID belongs to. It -// takes a UNIX PID and returns the object path. The PID must refer to an -// existing system process -func (c *Conn) GetUnitNameByPID(ctx context.Context, pid uint32) (string, error) { - path, err := c.GetUnitByPID(ctx, pid) - if err != nil { - return "", err - } - - return unitName(path), nil -} - -// Deprecated: use ListUnitsContext instead. -func (c *Conn) ListUnits() ([]UnitStatus, error) { - return c.ListUnitsContext(context.Background()) -} - -// ListUnitsContext returns an array with all currently loaded units. Note that -// units may be known by multiple names at the same time, and hence there might -// be more unit names loaded than actual units behind them. -// Also note that a unit is only loaded if it is active and/or enabled. -// Units that are both disabled and inactive will thus not be returned. -func (c *Conn) ListUnitsContext(ctx context.Context) ([]UnitStatus, error) { - return c.listUnitsInternal(c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.ListUnits", 0).Store) -} - -// Deprecated: use ListUnitsFilteredContext instead. -func (c *Conn) ListUnitsFiltered(states []string) ([]UnitStatus, error) { - return c.ListUnitsFilteredContext(context.Background(), states) -} - -// ListUnitsFilteredContext returns an array with units filtered by state. -// It takes a list of units' statuses to filter. -func (c *Conn) ListUnitsFilteredContext(ctx context.Context, states []string) ([]UnitStatus, error) { - return c.listUnitsInternal(c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.ListUnitsFiltered", 0, states).Store) -} - -// Deprecated: use ListUnitsByPatternsContext instead. -func (c *Conn) ListUnitsByPatterns(states []string, patterns []string) ([]UnitStatus, error) { - return c.ListUnitsByPatternsContext(context.Background(), states, patterns) -} - -// ListUnitsByPatternsContext returns an array with units. -// It takes a list of units' statuses and names to filter. -// Note that units may be known by multiple names at the same time, -// and hence there might be more unit names loaded than actual units behind them. -func (c *Conn) ListUnitsByPatternsContext(ctx context.Context, states []string, patterns []string) ([]UnitStatus, error) { - return c.listUnitsInternal(c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.ListUnitsByPatterns", 0, states, patterns).Store) -} - -// Deprecated: use ListUnitsByNamesContext instead. -func (c *Conn) ListUnitsByNames(units []string) ([]UnitStatus, error) { - return c.ListUnitsByNamesContext(context.Background(), units) -} - -// ListUnitsByNamesContext returns an array with units. It takes a list of units' -// names and returns an UnitStatus array. Comparing to ListUnitsByPatternsContext -// method, this method returns statuses even for inactive or non-existing -// units. Input array should contain exact unit names, but not patterns. -// -// Requires systemd v230 or higher. -func (c *Conn) ListUnitsByNamesContext(ctx context.Context, units []string) ([]UnitStatus, error) { - return c.listUnitsInternal(c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.ListUnitsByNames", 0, units).Store) -} - -type UnitFile struct { - Path string - Type string -} - -func (c *Conn) listUnitFilesInternal(f storeFunc) ([]UnitFile, error) { - result := make([][]interface{}, 0) - err := f(&result) - if err != nil { - return nil, err - } - - resultInterface := make([]interface{}, len(result)) - for i := range result { - resultInterface[i] = result[i] - } - - files := make([]UnitFile, len(result)) - fileInterface := make([]interface{}, len(files)) - for i := range files { - fileInterface[i] = &files[i] - } - - err = dbus.Store(resultInterface, fileInterface...) - if err != nil { - return nil, err - } - - return files, nil -} - -// Deprecated: use ListUnitFilesContext instead. -func (c *Conn) ListUnitFiles() ([]UnitFile, error) { - return c.ListUnitFilesContext(context.Background()) -} - -// ListUnitFiles returns an array of all available units on disk. -func (c *Conn) ListUnitFilesContext(ctx context.Context) ([]UnitFile, error) { - return c.listUnitFilesInternal(c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.ListUnitFiles", 0).Store) -} - -// Deprecated: use ListUnitFilesByPatternsContext instead. -func (c *Conn) ListUnitFilesByPatterns(states []string, patterns []string) ([]UnitFile, error) { - return c.ListUnitFilesByPatternsContext(context.Background(), states, patterns) -} - -// ListUnitFilesByPatternsContext returns an array of all available units on disk matched the patterns. -func (c *Conn) ListUnitFilesByPatternsContext(ctx context.Context, states []string, patterns []string) ([]UnitFile, error) { - return c.listUnitFilesInternal(c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.ListUnitFilesByPatterns", 0, states, patterns).Store) -} - -type LinkUnitFileChange EnableUnitFileChange - -// Deprecated: use LinkUnitFilesContext instead. -func (c *Conn) LinkUnitFiles(files []string, runtime bool, force bool) ([]LinkUnitFileChange, error) { - return c.LinkUnitFilesContext(context.Background(), files, runtime, force) -} - -// LinkUnitFilesContext links unit files (that are located outside of the -// usual unit search paths) into the unit search path. -// -// It takes a list of absolute paths to unit files to link and two -// booleans. -// -// The first boolean controls whether the unit shall be -// enabled for runtime only (true, /run), or persistently (false, -// /etc). -// -// The second controls whether symlinks pointing to other units shall -// be replaced if necessary. -// -// This call returns a list of the changes made. The list consists of -// structures with three strings: the type of the change (one of symlink -// or unlink), the file name of the symlink and the destination of the -// symlink. -func (c *Conn) LinkUnitFilesContext(ctx context.Context, files []string, runtime bool, force bool) ([]LinkUnitFileChange, error) { - result := make([][]interface{}, 0) - err := c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.LinkUnitFiles", 0, files, runtime, force).Store(&result) - if err != nil { - return nil, err - } - - resultInterface := make([]interface{}, len(result)) - for i := range result { - resultInterface[i] = result[i] - } - - changes := make([]LinkUnitFileChange, len(result)) - changesInterface := make([]interface{}, len(changes)) - for i := range changes { - changesInterface[i] = &changes[i] - } - - err = dbus.Store(resultInterface, changesInterface...) - if err != nil { - return nil, err - } - - return changes, nil -} - -// Deprecated: use EnableUnitFilesContext instead. -func (c *Conn) EnableUnitFiles(files []string, runtime bool, force bool) (bool, []EnableUnitFileChange, error) { - return c.EnableUnitFilesContext(context.Background(), files, runtime, force) -} - -// EnableUnitFilesContext may be used to enable one or more units in the system -// (by creating symlinks to them in /etc or /run). -// -// It takes a list of unit files to enable (either just file names or full -// absolute paths if the unit files are residing outside the usual unit -// search paths), and two booleans: the first controls whether the unit shall -// be enabled for runtime only (true, /run), or persistently (false, /etc). -// The second one controls whether symlinks pointing to other units shall -// be replaced if necessary. -// -// This call returns one boolean and an array with the changes made. The -// boolean signals whether the unit files contained any enablement -// information (i.e. an [Install]) section. The changes list consists of -// structures with three strings: the type of the change (one of symlink -// or unlink), the file name of the symlink and the destination of the -// symlink. -func (c *Conn) EnableUnitFilesContext(ctx context.Context, files []string, runtime bool, force bool) (bool, []EnableUnitFileChange, error) { - var carries_install_info bool - - result := make([][]interface{}, 0) - err := c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.EnableUnitFiles", 0, files, runtime, force).Store(&carries_install_info, &result) - if err != nil { - return false, nil, err - } - - resultInterface := make([]interface{}, len(result)) - for i := range result { - resultInterface[i] = result[i] - } - - changes := make([]EnableUnitFileChange, len(result)) - changesInterface := make([]interface{}, len(changes)) - for i := range changes { - changesInterface[i] = &changes[i] - } - - err = dbus.Store(resultInterface, changesInterface...) - if err != nil { - return false, nil, err - } - - return carries_install_info, changes, nil -} - -type EnableUnitFileChange struct { - Type string // Type of the change (one of symlink or unlink) - Filename string // File name of the symlink - Destination string // Destination of the symlink -} - -// Deprecated: use DisableUnitFilesContext instead. -func (c *Conn) DisableUnitFiles(files []string, runtime bool) ([]DisableUnitFileChange, error) { - return c.DisableUnitFilesContext(context.Background(), files, runtime) -} - -// DisableUnitFilesContext may be used to disable one or more units in the -// system (by removing symlinks to them from /etc or /run). -// -// It takes a list of unit files to disable (either just file names or full -// absolute paths if the unit files are residing outside the usual unit -// search paths), and one boolean: whether the unit was enabled for runtime -// only (true, /run), or persistently (false, /etc). -// -// This call returns an array with the changes made. The changes list -// consists of structures with three strings: the type of the change (one of -// symlink or unlink), the file name of the symlink and the destination of the -// symlink. -func (c *Conn) DisableUnitFilesContext(ctx context.Context, files []string, runtime bool) ([]DisableUnitFileChange, error) { - result := make([][]interface{}, 0) - err := c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.DisableUnitFiles", 0, files, runtime).Store(&result) - if err != nil { - return nil, err - } - - resultInterface := make([]interface{}, len(result)) - for i := range result { - resultInterface[i] = result[i] - } - - changes := make([]DisableUnitFileChange, len(result)) - changesInterface := make([]interface{}, len(changes)) - for i := range changes { - changesInterface[i] = &changes[i] - } - - err = dbus.Store(resultInterface, changesInterface...) - if err != nil { - return nil, err - } - - return changes, nil -} - -type DisableUnitFileChange struct { - Type string // Type of the change (one of symlink or unlink) - Filename string // File name of the symlink - Destination string // Destination of the symlink -} - -// Deprecated: use MaskUnitFilesContext instead. -func (c *Conn) MaskUnitFiles(files []string, runtime bool, force bool) ([]MaskUnitFileChange, error) { - return c.MaskUnitFilesContext(context.Background(), files, runtime, force) -} - -// MaskUnitFilesContext masks one or more units in the system. -// -// The files argument contains a list of units to mask (either just file names -// or full absolute paths if the unit files are residing outside the usual unit -// search paths). -// -// The runtime argument is used to specify whether the unit was enabled for -// runtime only (true, /run/systemd/..), or persistently (false, -// /etc/systemd/..). -func (c *Conn) MaskUnitFilesContext(ctx context.Context, files []string, runtime bool, force bool) ([]MaskUnitFileChange, error) { - result := make([][]interface{}, 0) - err := c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.MaskUnitFiles", 0, files, runtime, force).Store(&result) - if err != nil { - return nil, err - } - - resultInterface := make([]interface{}, len(result)) - for i := range result { - resultInterface[i] = result[i] - } - - changes := make([]MaskUnitFileChange, len(result)) - changesInterface := make([]interface{}, len(changes)) - for i := range changes { - changesInterface[i] = &changes[i] - } - - err = dbus.Store(resultInterface, changesInterface...) - if err != nil { - return nil, err - } - - return changes, nil -} - -type MaskUnitFileChange struct { - Type string // Type of the change (one of symlink or unlink) - Filename string // File name of the symlink - Destination string // Destination of the symlink -} - -// Deprecated: use UnmaskUnitFilesContext instead. -func (c *Conn) UnmaskUnitFiles(files []string, runtime bool) ([]UnmaskUnitFileChange, error) { - return c.UnmaskUnitFilesContext(context.Background(), files, runtime) -} - -// UnmaskUnitFilesContext unmasks one or more units in the system. -// -// It takes the list of unit files to mask (either just file names or full -// absolute paths if the unit files are residing outside the usual unit search -// paths), and a boolean runtime flag to specify whether the unit was enabled -// for runtime only (true, /run/systemd/..), or persistently (false, -// /etc/systemd/..). -func (c *Conn) UnmaskUnitFilesContext(ctx context.Context, files []string, runtime bool) ([]UnmaskUnitFileChange, error) { - result := make([][]interface{}, 0) - err := c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.UnmaskUnitFiles", 0, files, runtime).Store(&result) - if err != nil { - return nil, err - } - - resultInterface := make([]interface{}, len(result)) - for i := range result { - resultInterface[i] = result[i] - } - - changes := make([]UnmaskUnitFileChange, len(result)) - changesInterface := make([]interface{}, len(changes)) - for i := range changes { - changesInterface[i] = &changes[i] - } - - err = dbus.Store(resultInterface, changesInterface...) - if err != nil { - return nil, err - } - - return changes, nil -} - -type UnmaskUnitFileChange struct { - Type string // Type of the change (one of symlink or unlink) - Filename string // File name of the symlink - Destination string // Destination of the symlink -} - -// Deprecated: use ReloadContext instead. -func (c *Conn) Reload() error { - return c.ReloadContext(context.Background()) -} - -// ReloadContext instructs systemd to scan for and reload unit files. This is -// an equivalent to systemctl daemon-reload. -func (c *Conn) ReloadContext(ctx context.Context) error { - return c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.Reload", 0).Store() -} - -func unitPath(name string) dbus.ObjectPath { - return dbus.ObjectPath("/org/freedesktop/systemd1/unit/" + PathBusEscape(name)) -} - -// unitName returns the unescaped base element of the supplied escaped path. -func unitName(dpath dbus.ObjectPath) string { - return pathBusUnescape(path.Base(string(dpath))) -} - -// JobStatus holds a currently queued job definition. -type JobStatus struct { - Id uint32 // The numeric job id - Unit string // The primary unit name for this job - JobType string // The job type as string - Status string // The job state as string - JobPath dbus.ObjectPath // The job object path - UnitPath dbus.ObjectPath // The unit object path -} - -// Deprecated: use ListJobsContext instead. -func (c *Conn) ListJobs() ([]JobStatus, error) { - return c.ListJobsContext(context.Background()) -} - -// ListJobsContext returns an array with all currently queued jobs. -func (c *Conn) ListJobsContext(ctx context.Context) ([]JobStatus, error) { - return c.listJobsInternal(ctx) -} - -func (c *Conn) listJobsInternal(ctx context.Context) ([]JobStatus, error) { - result := make([][]interface{}, 0) - if err := c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.ListJobs", 0).Store(&result); err != nil { - return nil, err - } - - resultInterface := make([]interface{}, len(result)) - for i := range result { - resultInterface[i] = result[i] - } - - status := make([]JobStatus, len(result)) - statusInterface := make([]interface{}, len(status)) - for i := range status { - statusInterface[i] = &status[i] - } - - if err := dbus.Store(resultInterface, statusInterface...); err != nil { - return nil, err - } - - return status, nil -} - -// Freeze the cgroup associated with the unit. -// Note that FreezeUnit and ThawUnit are only supported on systems running with cgroup v2. -func (c *Conn) FreezeUnit(ctx context.Context, unit string) error { - return c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.FreezeUnit", 0, unit).Store() -} - -// Unfreeze the cgroup associated with the unit. -func (c *Conn) ThawUnit(ctx context.Context, unit string) error { - return c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.ThawUnit", 0, unit).Store() -} diff --git a/vendor/github.com/coreos/go-systemd/v22/dbus/properties.go b/vendor/github.com/coreos/go-systemd/v22/dbus/properties.go deleted file mode 100644 index fb42b6273..000000000 --- a/vendor/github.com/coreos/go-systemd/v22/dbus/properties.go +++ /dev/null @@ -1,237 +0,0 @@ -// Copyright 2015 CoreOS, Inc. -// -// 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 dbus - -import ( - "github.com/godbus/dbus/v5" -) - -// From the systemd docs: -// -// The properties array of StartTransientUnit() may take many of the settings -// that may also be configured in unit files. Not all parameters are currently -// accepted though, but we plan to cover more properties with future release. -// Currently you may set the Description, Slice and all dependency types of -// units, as well as RemainAfterExit, ExecStart for service units, -// TimeoutStopUSec and PIDs for scope units, and CPUAccounting, CPUShares, -// BlockIOAccounting, BlockIOWeight, BlockIOReadBandwidth, -// BlockIOWriteBandwidth, BlockIODeviceWeight, MemoryAccounting, MemoryLimit, -// DevicePolicy, DeviceAllow for services/scopes/slices. These fields map -// directly to their counterparts in unit files and as normal D-Bus object -// properties. The exception here is the PIDs field of scope units which is -// used for construction of the scope only and specifies the initial PIDs to -// add to the scope object. - -type Property struct { - Name string - Value dbus.Variant -} - -type PropertyCollection struct { - Name string - Properties []Property -} - -type execStart struct { - Path string // the binary path to execute - Args []string // an array with all arguments to pass to the executed command, starting with argument 0 - UncleanIsFailure bool // a boolean whether it should be considered a failure if the process exits uncleanly -} - -// PropExecStart sets the ExecStart service property. The first argument is a -// slice with the binary path to execute followed by the arguments to pass to -// the executed command. See -// http://www.freedesktop.org/software/systemd/man/systemd.service.html#ExecStart= -func PropExecStart(command []string, uncleanIsFailure bool) Property { - execStarts := []execStart{ - { - Path: command[0], - Args: command, - UncleanIsFailure: uncleanIsFailure, - }, - } - - return Property{ - Name: "ExecStart", - Value: dbus.MakeVariant(execStarts), - } -} - -// PropRemainAfterExit sets the RemainAfterExit service property. See -// http://www.freedesktop.org/software/systemd/man/systemd.service.html#RemainAfterExit= -func PropRemainAfterExit(b bool) Property { - return Property{ - Name: "RemainAfterExit", - Value: dbus.MakeVariant(b), - } -} - -// PropType sets the Type service property. See -// http://www.freedesktop.org/software/systemd/man/systemd.service.html#Type= -func PropType(t string) Property { - return Property{ - Name: "Type", - Value: dbus.MakeVariant(t), - } -} - -// PropDescription sets the Description unit property. See -// http://www.freedesktop.org/software/systemd/man/systemd.unit#Description= -func PropDescription(desc string) Property { - return Property{ - Name: "Description", - Value: dbus.MakeVariant(desc), - } -} - -func propDependency(name string, units []string) Property { - return Property{ - Name: name, - Value: dbus.MakeVariant(units), - } -} - -// PropRequires sets the Requires unit property. See -// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#Requires= -func PropRequires(units ...string) Property { - return propDependency("Requires", units) -} - -// PropRequiresOverridable sets the RequiresOverridable unit property. See -// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#RequiresOverridable= -func PropRequiresOverridable(units ...string) Property { - return propDependency("RequiresOverridable", units) -} - -// PropRequisite sets the Requisite unit property. See -// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#Requisite= -func PropRequisite(units ...string) Property { - return propDependency("Requisite", units) -} - -// PropRequisiteOverridable sets the RequisiteOverridable unit property. See -// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#RequisiteOverridable= -func PropRequisiteOverridable(units ...string) Property { - return propDependency("RequisiteOverridable", units) -} - -// PropWants sets the Wants unit property. See -// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#Wants= -func PropWants(units ...string) Property { - return propDependency("Wants", units) -} - -// PropBindsTo sets the BindsTo unit property. See -// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#BindsTo= -func PropBindsTo(units ...string) Property { - return propDependency("BindsTo", units) -} - -// PropRequiredBy sets the RequiredBy unit property. See -// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#RequiredBy= -func PropRequiredBy(units ...string) Property { - return propDependency("RequiredBy", units) -} - -// PropRequiredByOverridable sets the RequiredByOverridable unit property. See -// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#RequiredByOverridable= -func PropRequiredByOverridable(units ...string) Property { - return propDependency("RequiredByOverridable", units) -} - -// PropWantedBy sets the WantedBy unit property. See -// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#WantedBy= -func PropWantedBy(units ...string) Property { - return propDependency("WantedBy", units) -} - -// PropBoundBy sets the BoundBy unit property. See -// http://www.freedesktop.org/software/systemd/main/systemd.unit.html#BoundBy= -func PropBoundBy(units ...string) Property { - return propDependency("BoundBy", units) -} - -// PropConflicts sets the Conflicts unit property. See -// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#Conflicts= -func PropConflicts(units ...string) Property { - return propDependency("Conflicts", units) -} - -// PropConflictedBy sets the ConflictedBy unit property. See -// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#ConflictedBy= -func PropConflictedBy(units ...string) Property { - return propDependency("ConflictedBy", units) -} - -// PropBefore sets the Before unit property. See -// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#Before= -func PropBefore(units ...string) Property { - return propDependency("Before", units) -} - -// PropAfter sets the After unit property. See -// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#After= -func PropAfter(units ...string) Property { - return propDependency("After", units) -} - -// PropOnFailure sets the OnFailure unit property. See -// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#OnFailure= -func PropOnFailure(units ...string) Property { - return propDependency("OnFailure", units) -} - -// PropTriggers sets the Triggers unit property. See -// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#Triggers= -func PropTriggers(units ...string) Property { - return propDependency("Triggers", units) -} - -// PropTriggeredBy sets the TriggeredBy unit property. See -// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#TriggeredBy= -func PropTriggeredBy(units ...string) Property { - return propDependency("TriggeredBy", units) -} - -// PropPropagatesReloadTo sets the PropagatesReloadTo unit property. See -// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#PropagatesReloadTo= -func PropPropagatesReloadTo(units ...string) Property { - return propDependency("PropagatesReloadTo", units) -} - -// PropRequiresMountsFor sets the RequiresMountsFor unit property. See -// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#RequiresMountsFor= -func PropRequiresMountsFor(units ...string) Property { - return propDependency("RequiresMountsFor", units) -} - -// PropSlice sets the Slice unit property. See -// http://www.freedesktop.org/software/systemd/man/systemd.resource-control.html#Slice= -func PropSlice(slice string) Property { - return Property{ - Name: "Slice", - Value: dbus.MakeVariant(slice), - } -} - -// PropPids sets the PIDs field of scope units used in the initial construction -// of the scope only and specifies the initial PIDs to add to the scope object. -// See https://www.freedesktop.org/wiki/Software/systemd/ControlGroupInterface/#properties -func PropPids(pids ...uint32) Property { - return Property{ - Name: "PIDs", - Value: dbus.MakeVariant(pids), - } -} diff --git a/vendor/github.com/coreos/go-systemd/v22/dbus/set.go b/vendor/github.com/coreos/go-systemd/v22/dbus/set.go deleted file mode 100644 index 17c5d4856..000000000 --- a/vendor/github.com/coreos/go-systemd/v22/dbus/set.go +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2015 CoreOS, Inc. -// -// 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 dbus - -type set struct { - data map[string]bool -} - -func (s *set) Add(value string) { - s.data[value] = true -} - -func (s *set) Remove(value string) { - delete(s.data, value) -} - -func (s *set) Contains(value string) (exists bool) { - _, exists = s.data[value] - return -} - -func (s *set) Length() int { - return len(s.data) -} - -func (s *set) Values() (values []string) { - for val := range s.data { - values = append(values, val) - } - return -} - -func newSet() *set { - return &set{make(map[string]bool)} -} diff --git a/vendor/github.com/coreos/go-systemd/v22/dbus/subscription.go b/vendor/github.com/coreos/go-systemd/v22/dbus/subscription.go deleted file mode 100644 index 7e370fea2..000000000 --- a/vendor/github.com/coreos/go-systemd/v22/dbus/subscription.go +++ /dev/null @@ -1,333 +0,0 @@ -// Copyright 2015 CoreOS, Inc. -// -// 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 dbus - -import ( - "errors" - "log" - "time" - - "github.com/godbus/dbus/v5" -) - -const ( - cleanIgnoreInterval = int64(10 * time.Second) - ignoreInterval = int64(30 * time.Millisecond) -) - -// Subscribe sets up this connection to subscribe to all systemd dbus events. -// This is required before calling SubscribeUnits. When the connection closes -// systemd will automatically stop sending signals so there is no need to -// explicitly call Unsubscribe(). -func (c *Conn) Subscribe() error { - c.sigconn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0, - "type='signal',interface='org.freedesktop.systemd1.Manager',member='UnitNew'") - c.sigconn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0, - "type='signal',interface='org.freedesktop.DBus.Properties',member='PropertiesChanged'") - - return c.sigobj.Call("org.freedesktop.systemd1.Manager.Subscribe", 0).Store() -} - -// Unsubscribe this connection from systemd dbus events. -func (c *Conn) Unsubscribe() error { - return c.sigobj.Call("org.freedesktop.systemd1.Manager.Unsubscribe", 0).Store() -} - -func (c *Conn) dispatch() { - ch := make(chan *dbus.Signal, signalBuffer) - - c.sigconn.Signal(ch) - - go func() { - for { - signal, ok := <-ch - if !ok { - return - } - - if signal.Name == "org.freedesktop.systemd1.Manager.JobRemoved" { - c.jobComplete(signal) - } - - if c.subStateSubscriber.updateCh == nil && - c.propertiesSubscriber.updateCh == nil { - continue - } - - var unitPath dbus.ObjectPath - switch signal.Name { - case "org.freedesktop.systemd1.Manager.JobRemoved": - unitName := signal.Body[2].(string) - c.sysobj.Call("org.freedesktop.systemd1.Manager.GetUnit", 0, unitName).Store(&unitPath) - case "org.freedesktop.systemd1.Manager.UnitNew": - unitPath = signal.Body[1].(dbus.ObjectPath) - case "org.freedesktop.DBus.Properties.PropertiesChanged": - if signal.Body[0].(string) == "org.freedesktop.systemd1.Unit" { - unitPath = signal.Path - - if len(signal.Body) >= 2 { - if changed, ok := signal.Body[1].(map[string]dbus.Variant); ok { - c.sendPropertiesUpdate(unitPath, changed) - } - } - } - } - - if unitPath == dbus.ObjectPath("") { - continue - } - - c.sendSubStateUpdate(unitPath) - } - }() -} - -// SubscribeUnits returns two unbuffered channels which will receive all changed units every -// interval. Deleted units are sent as nil. -func (c *Conn) SubscribeUnits(interval time.Duration) (<-chan map[string]*UnitStatus, <-chan error) { - return c.SubscribeUnitsCustom(interval, 0, func(u1, u2 *UnitStatus) bool { return *u1 != *u2 }, nil) -} - -// SubscribeUnitsCustom is like SubscribeUnits but lets you specify the buffer -// size of the channels, the comparison function for detecting changes and a filter -// function for cutting down on the noise that your channel receives. -func (c *Conn) SubscribeUnitsCustom(interval time.Duration, buffer int, isChanged func(*UnitStatus, *UnitStatus) bool, filterUnit func(string) bool) (<-chan map[string]*UnitStatus, <-chan error) { - old := make(map[string]*UnitStatus) - statusChan := make(chan map[string]*UnitStatus, buffer) - errChan := make(chan error, buffer) - - go func() { - for { - timerChan := time.After(interval) - - units, err := c.ListUnits() - if err == nil { - cur := make(map[string]*UnitStatus) - for i := range units { - if filterUnit != nil && filterUnit(units[i].Name) { - continue - } - cur[units[i].Name] = &units[i] - } - - // add all new or changed units - changed := make(map[string]*UnitStatus) - for n, u := range cur { - if oldU, ok := old[n]; !ok || isChanged(oldU, u) { - changed[n] = u - } - delete(old, n) - } - - // add all deleted units - for oldN := range old { - changed[oldN] = nil - } - - old = cur - - if len(changed) != 0 { - statusChan <- changed - } - } else { - errChan <- err - } - - <-timerChan - } - }() - - return statusChan, errChan -} - -type SubStateUpdate struct { - UnitName string - SubState string -} - -// SetSubStateSubscriber writes to updateCh when any unit's substate changes. -// Although this writes to updateCh on every state change, the reported state -// may be more recent than the change that generated it (due to an unavoidable -// race in the systemd dbus interface). That is, this method provides a good -// way to keep a current view of all units' states, but is not guaranteed to -// show every state transition they go through. Furthermore, state changes -// will only be written to the channel with non-blocking writes. If updateCh -// is full, it attempts to write an error to errCh; if errCh is full, the error -// passes silently. -func (c *Conn) SetSubStateSubscriber(updateCh chan<- *SubStateUpdate, errCh chan<- error) { - if c == nil { - msg := "nil receiver" - select { - case errCh <- errors.New(msg): - default: - log.Printf("full error channel while reporting: %s\n", msg) - } - return - } - - c.subStateSubscriber.Lock() - defer c.subStateSubscriber.Unlock() - c.subStateSubscriber.updateCh = updateCh - c.subStateSubscriber.errCh = errCh -} - -func (c *Conn) sendSubStateUpdate(unitPath dbus.ObjectPath) { - c.subStateSubscriber.Lock() - defer c.subStateSubscriber.Unlock() - - if c.subStateSubscriber.updateCh == nil { - return - } - - isIgnored := c.shouldIgnore(unitPath) - defer c.cleanIgnore() - if isIgnored { - return - } - - info, err := c.GetUnitPathProperties(unitPath) - if err != nil { - select { - case c.subStateSubscriber.errCh <- err: - default: - log.Printf("full error channel while reporting: %s\n", err) - } - return - } - defer c.updateIgnore(unitPath, info) - - name, ok := info["Id"].(string) - if !ok { - msg := "failed to cast info.Id" - select { - case c.subStateSubscriber.errCh <- errors.New(msg): - default: - log.Printf("full error channel while reporting: %s\n", err) - } - return - } - substate, ok := info["SubState"].(string) - if !ok { - msg := "failed to cast info.SubState" - select { - case c.subStateSubscriber.errCh <- errors.New(msg): - default: - log.Printf("full error channel while reporting: %s\n", msg) - } - return - } - - update := &SubStateUpdate{name, substate} - select { - case c.subStateSubscriber.updateCh <- update: - default: - msg := "update channel is full" - select { - case c.subStateSubscriber.errCh <- errors.New(msg): - default: - log.Printf("full error channel while reporting: %s\n", msg) - } - return - } -} - -// The ignore functions work around a wart in the systemd dbus interface. -// Requesting the properties of an unloaded unit will cause systemd to send a -// pair of UnitNew/UnitRemoved signals. Because we need to get a unit's -// properties on UnitNew (as that's the only indication of a new unit coming up -// for the first time), we would enter an infinite loop if we did not attempt -// to detect and ignore these spurious signals. The signal themselves are -// indistinguishable from relevant ones, so we (somewhat hackishly) ignore an -// unloaded unit's signals for a short time after requesting its properties. -// This means that we will miss e.g. a transient unit being restarted -// *immediately* upon failure and also a transient unit being started -// immediately after requesting its status (with systemctl status, for example, -// because this causes a UnitNew signal to be sent which then causes us to fetch -// the properties). - -func (c *Conn) shouldIgnore(path dbus.ObjectPath) bool { - t, ok := c.subStateSubscriber.ignore[path] - return ok && t >= time.Now().UnixNano() -} - -func (c *Conn) updateIgnore(path dbus.ObjectPath, info map[string]interface{}) { - loadState, ok := info["LoadState"].(string) - if !ok { - return - } - - // unit is unloaded - it will trigger bad systemd dbus behavior - if loadState == "not-found" { - c.subStateSubscriber.ignore[path] = time.Now().UnixNano() + ignoreInterval - } -} - -// without this, ignore would grow unboundedly over time -func (c *Conn) cleanIgnore() { - now := time.Now().UnixNano() - if c.subStateSubscriber.cleanIgnore < now { - c.subStateSubscriber.cleanIgnore = now + cleanIgnoreInterval - - for p, t := range c.subStateSubscriber.ignore { - if t < now { - delete(c.subStateSubscriber.ignore, p) - } - } - } -} - -// PropertiesUpdate holds a map of a unit's changed properties -type PropertiesUpdate struct { - UnitName string - Changed map[string]dbus.Variant -} - -// SetPropertiesSubscriber writes to updateCh when any unit's properties -// change. Every property change reported by systemd will be sent; that is, no -// transitions will be "missed" (as they might be with SetSubStateSubscriber). -// However, state changes will only be written to the channel with non-blocking -// writes. If updateCh is full, it attempts to write an error to errCh; if -// errCh is full, the error passes silently. -func (c *Conn) SetPropertiesSubscriber(updateCh chan<- *PropertiesUpdate, errCh chan<- error) { - c.propertiesSubscriber.Lock() - defer c.propertiesSubscriber.Unlock() - c.propertiesSubscriber.updateCh = updateCh - c.propertiesSubscriber.errCh = errCh -} - -// we don't need to worry about shouldIgnore() here because -// sendPropertiesUpdate doesn't call GetProperties() -func (c *Conn) sendPropertiesUpdate(unitPath dbus.ObjectPath, changedProps map[string]dbus.Variant) { - c.propertiesSubscriber.Lock() - defer c.propertiesSubscriber.Unlock() - - if c.propertiesSubscriber.updateCh == nil { - return - } - - update := &PropertiesUpdate{unitName(unitPath), changedProps} - - select { - case c.propertiesSubscriber.updateCh <- update: - default: - msg := "update channel is full" - select { - case c.propertiesSubscriber.errCh <- errors.New(msg): - default: - log.Printf("full error channel while reporting: %s\n", msg) - } - return - } -} diff --git a/vendor/github.com/coreos/go-systemd/v22/dbus/subscription_set.go b/vendor/github.com/coreos/go-systemd/v22/dbus/subscription_set.go deleted file mode 100644 index 5b408d584..000000000 --- a/vendor/github.com/coreos/go-systemd/v22/dbus/subscription_set.go +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2015 CoreOS, Inc. -// -// 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 dbus - -import ( - "time" -) - -// SubscriptionSet returns a subscription set which is like conn.Subscribe but -// can filter to only return events for a set of units. -type SubscriptionSet struct { - *set - conn *Conn -} - -func (s *SubscriptionSet) filter(unit string) bool { - return !s.Contains(unit) -} - -// Subscribe starts listening for dbus events for all of the units in the set. -// Returns channels identical to conn.SubscribeUnits. -func (s *SubscriptionSet) Subscribe() (<-chan map[string]*UnitStatus, <-chan error) { - // TODO: Make fully evented by using systemd 209 with properties changed values - return s.conn.SubscribeUnitsCustom(time.Second, 0, - mismatchUnitStatus, - func(unit string) bool { return s.filter(unit) }, - ) -} - -// NewSubscriptionSet returns a new subscription set. -func (conn *Conn) NewSubscriptionSet() *SubscriptionSet { - return &SubscriptionSet{newSet(), conn} -} - -// mismatchUnitStatus returns true if the provided UnitStatus objects -// are not equivalent. false is returned if the objects are equivalent. -// Only the Name, Description and state-related fields are used in -// the comparison. -func mismatchUnitStatus(u1, u2 *UnitStatus) bool { - return u1.Name != u2.Name || - u1.Description != u2.Description || - u1.LoadState != u2.LoadState || - u1.ActiveState != u2.ActiveState || - u1.SubState != u2.SubState -} diff --git a/vendor/github.com/gammazero/deque/README.md b/vendor/github.com/gammazero/deque/README.md index eb06369eb..ee2dbb888 100644 --- a/vendor/github.com/gammazero/deque/README.md +++ b/vendor/github.com/gammazero/deque/README.md @@ -22,9 +22,9 @@ Deque generalizes a queue and a stack, to efficiently add and remove items at ei ## Ring-buffer Performance -This deque implementation is optimized for CPU and GC performance. The circular buffer automatically re-sizes by powers of two, growing when additional capacity is needed and shrinking when only a quarter of the capacity is used, and uses bitwise arithmetic for all calculations. Since growth is by powers of two, adding elements will only cause O(log n) allocations. A minimum capacity can be set so that there is no resizing at or below that specified amount. +This deque implementation is optimized for CPU and GC performance. The circular buffer automatically re-sizes by powers of two, growing when additional capacity is needed and shrinking when only a quarter of the capacity is used, and uses bitwise arithmetic for all calculations. Since growth is by powers of two, adding elements will only cause O(log n) allocations. A base capacity can be set, with `SetBaseCap`, so that there is no resizing at or below that specified amount. The Deque can also be grown, using `Grow`, to ensure sufficient storage for n additional items, to prevent resizing when adding a number of itmes. -The ring-buffer implementation improves memory and time performance with fewer GC pauses, compared to implementations based on slices and linked lists. By wrapping around the buffer, previously used space is reused, making allocation unnecessary until all buffer capacity is used. If the deque is only filled and then completely emptied before being filled again, then the ring structure offers little benefit for memory reuse over a slice. +The ring-buffer implementation improves memory and time performance with fewer GC pauses, compared to implementations based on slices or linked lists. By wrapping around the buffer, previously used space is reused, making allocation unnecessary until all buffer capacity is used. The ring buffer implementation performs best when resizes are infrequest, as is the case when items moving in and out of the Deque are balanced or when the base capacity is large enough to rarely require a resize. For maximum speed, this deque implementation leaves concurrency safety up to the application to provide, however the application chooses, if needed at all. @@ -34,9 +34,9 @@ Since it is OK for the deque to contain a `nil` value, it is necessary to either ## Generics -Deque uses generics to create a Deque that contains items of the type specified. To create a Deque that holds a specific type, provide a type argument to New or with the variable declaration. For example: +Deque uses generics to create a Deque that contains items of the type specified. To create a Deque that holds a specific type, provide a type argument with the `Deque` variable declaration. For example: ```go - stringDeque := deque.New[string]() + stringDeque := new(deque.Deque[string]) var intDeque deque.Deque[int] ``` diff --git a/vendor/github.com/gammazero/deque/deque.go b/vendor/github.com/gammazero/deque/deque.go index a1743c161..ff1099620 100644 --- a/vendor/github.com/gammazero/deque/deque.go +++ b/vendor/github.com/gammazero/deque/deque.go @@ -8,59 +8,33 @@ const minCapacity = 16 // Deque represents a single instance of the deque data structure. A Deque // instance contains items of the type specified by the type argument. -type Deque[T any] struct { - buf []T - head int - tail int - count int - minCap int -} - -// New creates a new Deque, optionally setting the current and minimum capacity -// when non-zero values are given for these. The Deque instance returns -// operates on items of the type specified by the type argument. For example, -// to create a Deque that contains strings, // -// stringDeque := deque.New[string]() +// For example, to create a Deque that contains strings do one of the +// following: // -// To create a Deque with capacity to store 2048 ints without resizing, and -// that will not resize below space for 32 items when removing items: +// var stringDeque deque.Deque[string] +// stringDeque := new(deque.Deque[string]) +// stringDeque := &deque.Deque[string]{} // -// d := deque.New[int](2048, 32) +// To create a Deque that will never resize to have space for less than 64 +// items, specify a base capacity: // -// To create a Deque that has not yet allocated memory, but after it does will -// never resize to have space for less than 64 items: +// var d deque.Deque[int] +// d.SetBaseCap(64) // -// d := deque.New[int](0, 64) +// To ensure the Deque can store 1000 items without needing to resize while +// items are added: // -// Any size values supplied here are rounded up to the nearest power of 2. -func New[T any](size ...int) *Deque[T] { - var capacity, minimum int - if len(size) >= 1 { - capacity = size[0] - if len(size) >= 2 { - minimum = size[1] - } - } - - minCap := minCapacity - for minCap < minimum { - minCap <<= 1 - } - - var buf []T - if capacity != 0 { - bufSize := minCap - for bufSize < capacity { - bufSize <<= 1 - } - buf = make([]T, bufSize) - } - - return &Deque[T]{ - buf: buf, - minCap: minCap, - } +// d.Grow(1000) +// +// Any values supplied to SetBaseCap and Grow are rounded up to the nearest +// power of 2, since the Deque grows by powers of 2. +type Deque[T any] struct { + buf []T + head int + tail int + count int + minCap int } // Cap returns the current capacity of the Deque. If q is nil, q.Cap() is zero. @@ -72,7 +46,7 @@ func (q *Deque[T]) Cap() int { } // Len returns the number of elements currently stored in the queue. If q is -// nil, q.Len() is zero. +// nil, q.Len() returns zero. func (q *Deque[T]) Len() int { if q == nil { return 0 @@ -172,9 +146,7 @@ func (q *Deque[T]) Back() T { // and when full the oldest is popped from the other end. All the log entries // in the buffer must be readable without altering the buffer contents. func (q *Deque[T]) At(i int) T { - if i < 0 || i >= q.count { - panic(outOfRangeText(i, q.Len())) - } + q.checkRange(i) // bitwise modulus return q.buf[(q.head+i)&(len(q.buf)-1)] } @@ -183,9 +155,7 @@ func (q *Deque[T]) At(i int) T { // as At but perform the opposite operation. If the index is invalid, the call // panics. func (q *Deque[T]) Set(i int, item T) { - if i < 0 || i >= q.count { - panic(outOfRangeText(i, q.Len())) - } + q.checkRange(i) // bitwise modulus q.buf[(q.head+i)&(len(q.buf)-1)] = item } @@ -207,6 +177,37 @@ func (q *Deque[T]) Clear() { q.count = 0 } +// Grow grows deque's capacity, if necessary, to guarantee space for another n +// items. After Grow(n), at least n items can be written to the deque without +// another allocation. If n is negative, Grow panics. +func (q *Deque[T]) Grow(n int) { + if n < 0 { + panic("deque.Grow: negative count") + } + c := q.Cap() + l := q.Len() + // If already big enough. + if n <= c-l { + return + } + + if c == 0 { + c = minCapacity + } + + newLen := l + n + for c < newLen { + c <<= 1 + } + if l == 0 { + q.buf = make([]T, c) + q.head = 0 + q.tail = 0 + } else { + q.resize(c) + } +} + // Rotate rotates the deque n steps front-to-back. If n is negative, rotates // back-to-front. Having Deque provide Rotate avoids resizing that could happen // if implementing rotation using only Pop and Push methods. If q.Len() is one @@ -288,16 +289,21 @@ func (q *Deque[T]) RIndex(f func(T) bool) int { // Insert is used to insert an element into the middle of the queue, before the // element at the specified index. Insert(0,e) is the same as PushFront(e) and -// Insert(Len(),e) is the same as PushBack(e). Accepts only non-negative index -// values, and panics if index is out of range. +// Insert(Len(),e) is the same as PushBack(e). Out of range indexes result in +// pushing the item onto the front of back of the deque. // // Important: Deque is optimized for O(1) operations at the ends of the queue, // not for operations in the the middle. Complexity of this function is // constant plus linear in the lesser of the distances between the index and // either of the ends of the queue. func (q *Deque[T]) Insert(at int, item T) { - if at < 0 || at > q.count { - panic(outOfRangeText(at, q.Len())) + if at <= 0 { + q.PushFront(item) + return + } + if at >= q.Len() { + q.PushBack(item) + return } if at*2 < q.count { q.PushFront(item) @@ -329,10 +335,7 @@ func (q *Deque[T]) Insert(at int, item T) { // constant plus linear in the lesser of the distances between the index and // either of the ends of the queue. func (q *Deque[T]) Remove(at int) T { - if at < 0 || at >= q.Len() { - panic(outOfRangeText(at, q.Len())) - } - + q.checkRange(at) rm := (q.head + at) & (len(q.buf) - 1) if at*2 < q.count { for i := 0; i < at; i++ { @@ -351,18 +354,33 @@ func (q *Deque[T]) Remove(at int) T { return q.PopBack() } -// SetMinCapacity sets a minimum capacity of 2^minCapacityExp. If the value of -// the minimum capacity is less than or equal to the minimum allowed, then -// capacity is set to the minimum allowed. This may be called at anytime to set -// a new minimum capacity. -// -// Setting a larger minimum capacity may be used to prevent resizing when the -// number of stored items changes frequently across a wide range. -func (q *Deque[T]) SetMinCapacity(minCapacityExp uint) { - if 1< minCapacity { - q.minCap = 1 << minCapacityExp - } else { - q.minCap = minCapacity +// SetBaseCap sets a base capacity so that at least the specified number of +// items can always be stored without resizing. +func (q *Deque[T]) SetBaseCap(baseCap int) { + minCap := minCapacity + for minCap < baseCap { + minCap <<= 1 + } + q.minCap = minCap +} + +// Swap exchanges the two values at idxA and idxB. It panics if either index is +// out of range. +func (q *Deque[T]) Swap(idxA, idxB int) { + q.checkRange(idxA) + q.checkRange(idxB) + if idxA == idxB { + return + } + + realA := (q.head + idxA) & (len(q.buf) - 1) + realB := (q.head + idxB) & (len(q.buf) - 1) + q.buf[realA], q.buf[realB] = q.buf[realB], q.buf[realA] +} + +func (q *Deque[T]) checkRange(i int) { + if i < 0 || i >= q.count { + panic(fmt.Sprintf("deque: index out of range %d with length %d", i, q.Len())) } } @@ -388,21 +406,21 @@ func (q *Deque[T]) growIfFull() { q.buf = make([]T, q.minCap) return } - q.resize() + q.resize(q.count << 1) } // shrinkIfExcess resize down if the buffer 1/4 full. func (q *Deque[T]) shrinkIfExcess() { if len(q.buf) > q.minCap && (q.count<<2) == len(q.buf) { - q.resize() + q.resize(q.count << 1) } } // resize resizes the deque to fit exactly twice its current contents. This is // used to grow the queue when it is full, and also to shrink it when it is // only a quarter full. -func (q *Deque[T]) resize() { - newBuf := make([]T, q.count<<1) +func (q *Deque[T]) resize(newSize int) { + newBuf := make([]T, newSize) if q.tail > q.head { copy(newBuf, q.buf[q.head:q.tail]) } else { @@ -414,7 +432,3 @@ func (q *Deque[T]) resize() { q.tail = q.count q.buf = newBuf } - -func outOfRangeText(i, len int) string { - return fmt.Sprintf("deque: index out of range %d with length %d", i, len) -} diff --git a/vendor/github.com/gammazero/deque/doc.go b/vendor/github.com/gammazero/deque/doc.go index 6cfead994..dfff00adb 100644 --- a/vendor/github.com/gammazero/deque/doc.go +++ b/vendor/github.com/gammazero/deque/doc.go @@ -33,6 +33,6 @@ Deque.Len() before reading from the deque. Deque uses generics to create a Deque that contains items of the type specified. To create a Deque that holds a specific type, provide a type -argument to New or with the variable declaration. +argument with the Deque variable declaration. */ package deque diff --git a/vendor/github.com/godbus/dbus/v5/CONTRIBUTING.md b/vendor/github.com/godbus/dbus/v5/CONTRIBUTING.md deleted file mode 100644 index c88f9b2bd..000000000 --- a/vendor/github.com/godbus/dbus/v5/CONTRIBUTING.md +++ /dev/null @@ -1,50 +0,0 @@ -# How to Contribute - -## Getting Started - -- Fork the repository on GitHub -- Read the [README](README.markdown) for build and test instructions -- Play with the project, submit bugs, submit patches! - -## Contribution Flow - -This is a rough outline of what a contributor's workflow looks like: - -- Create a topic branch from where you want to base your work (usually master). -- Make commits of logical units. -- Make sure your commit messages are in the proper format (see below). -- Push your changes to a topic branch in your fork of the repository. -- Make sure the tests pass, and add any new tests as appropriate. -- Submit a pull request to the original repository. - -Thanks for your contributions! - -### Format of the Commit Message - -We follow a rough convention for commit messages that is designed to answer two -questions: what changed and why. The subject line should feature the what and -the body of the commit should describe the why. - -``` -scripts: add the test-cluster command - -this uses tmux to setup a test cluster that you can easily kill and -start for debugging. - -Fixes #38 -``` - -The format can be described more formally as follows: - -``` -: - - - -