From aa56c3ba5a00cac0a4f3c7e23b5c92327f89e32d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 18 Oct 2022 15:36:00 +0000 Subject: [PATCH] build(deps): bump github.com/coreos/butane in /mantle Bumps [github.com/coreos/butane](https://github.com/coreos/butane) from 0.14.0 to 0.16.0. - [Release notes](https://github.com/coreos/butane/releases) - [Changelog](https://github.com/coreos/butane/blob/main/docs/release-notes.md) - [Commits](https://github.com/coreos/butane/compare/v0.14.0...v0.16.0) --- updated-dependencies: - dependency-name: github.com/coreos/butane dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- mantle/go.mod | 6 +- mantle/go.sum | 33 +- .../vendor/github.com/clarketm/json/decode.go | 120 ++--- .../vendor/github.com/clarketm/json/encode.go | 114 +++-- .../vendor/github.com/clarketm/json/fuzz.go | 1 + .../github.com/clarketm/json/scanner.go | 31 +- .../coreos/butane/base/util/file.go | 14 +- .../github.com/coreos/butane/base/util/url.go | 23 +- .../coreos/butane/base/v0_2/translate.go | 37 +- .../coreos/butane/base/v0_3/translate.go | 37 +- .../coreos/butane/base/v0_4/translate.go | 36 +- .../coreos/butane/base/v0_5_exp/translate.go | 36 +- .../coreos/butane/config/common/errors.go | 8 + .../github.com/coreos/butane/config/config.go | 20 +- .../butane/config/fcos/v1_5_exp/schema.go | 10 + .../butane/config/fcos/v1_5_exp/translate.go | 74 ++- .../butane/config/fcos/v1_5_exp/validate.go | 12 + .../butane/config/flatcar/v1_0/schema.go | 23 + .../butane/config/flatcar/v1_0/translate.go | 60 +++ .../butane/config/flatcar/v1_1_exp/schema.go | 23 + .../config/flatcar/v1_1_exp/translate.go | 60 +++ .../config/openshift/v4_10/translate.go | 7 + .../config/openshift/v4_11/result/schema.go | 48 ++ .../butane/config/openshift/v4_11/schema.go | 39 ++ .../{v4_11_exp => v4_11}/translate.go | 42 +- .../{v4_11_exp => v4_11}/validate.go | 2 +- .../config/openshift/v4_12/result/schema.go | 48 ++ .../butane/config/openshift/v4_12/schema.go | 39 ++ .../config/openshift/v4_12/translate.go | 279 ++++++++++ .../butane/config/openshift/v4_12/validate.go | 43 ++ .../{v4_11_exp => v4_13_exp}/result/schema.go | 0 .../{v4_11_exp => v4_13_exp}/schema.go | 2 +- .../config/openshift/v4_13_exp/translate.go | 321 ++++++++++++ .../config/openshift/v4_13_exp/validate.go | 43 ++ .../github.com/coreos/butane/translate/set.go | 31 ++ .../github.com/coreos/go-json/decode.go | 51 +- .../github.com/coreos/go-json/encode.go | 72 ++- .../vendor/github.com/coreos/go-json/fuzz.go | 1 + .../vendor/github.com/coreos/go-json/go.mod | 2 +- .../coreos/go-systemd/v22/dbus/dbus.go | 66 ++- .../coreos/go-systemd/v22/dbus/methods.go | 480 ++++++++++++++---- .../coreos/go-systemd/v22/journal/journal.go | 179 ------- .../go-systemd/v22/journal/journal_unix.go | 215 ++++++++ .../go-systemd/v22/journal/journal_windows.go | 35 ++ .../coreos/go-systemd/v22/unit/deserialize.go | 98 +++- .../coreos/go-systemd/v22/unit/escape.go | 21 +- .../coreos/go-systemd/v22/unit/section.go | 44 ++ .../coreos/go-systemd/v22/unit/serialize.go | 23 + .../github.com/godbus/dbus/v5/.travis.yml | 50 -- .../github.com/godbus/dbus/v5/README.markdown | 4 +- .../vendor/github.com/godbus/dbus/v5/auth.go | 2 +- .../vendor/github.com/godbus/dbus/v5/call.go | 9 + .../vendor/github.com/godbus/dbus/v5/conn.go | 159 ++++-- .../vendor/github.com/godbus/dbus/v5/dbus.go | 4 + .../godbus/dbus/v5/default_handler.go | 22 +- .../github.com/godbus/dbus/v5/export.go | 61 ++- .../vendor/github.com/godbus/dbus/v5/match.go | 27 + .../github.com/godbus/dbus/v5/object.go | 65 +-- .../github.com/godbus/dbus/v5/sequence.go | 24 + .../godbus/dbus/v5/sequential_handler.go | 125 +++++ .../vendor/github.com/godbus/dbus/v5/sig.go | 2 +- .../dbus/v5/transport_unixcred_freebsd.go | 1 + .../github.com/godbus/dbus/v5/variant.go | 6 + .../testify/assert/assertion_compare.go | 76 ++- .../assert/assertion_compare_can_convert.go | 16 + .../assert/assertion_compare_legacy.go | 16 + .../testify/assert/assertion_format.go | 22 + .../testify/assert/assertion_forward.go | 44 ++ .../testify/assert/assertion_order.go | 8 +- .../stretchr/testify/assert/assertions.go | 190 +++++-- mantle/vendor/gopkg.in/yaml.v3/decode.go | 78 ++- mantle/vendor/gopkg.in/yaml.v3/parserc.go | 11 +- mantle/vendor/modules.txt | 26 +- 73 files changed, 3183 insertions(+), 874 deletions(-) create mode 100644 mantle/vendor/github.com/coreos/butane/config/flatcar/v1_0/schema.go create mode 100644 mantle/vendor/github.com/coreos/butane/config/flatcar/v1_0/translate.go create mode 100644 mantle/vendor/github.com/coreos/butane/config/flatcar/v1_1_exp/schema.go create mode 100644 mantle/vendor/github.com/coreos/butane/config/flatcar/v1_1_exp/translate.go create mode 100644 mantle/vendor/github.com/coreos/butane/config/openshift/v4_11/result/schema.go create mode 100644 mantle/vendor/github.com/coreos/butane/config/openshift/v4_11/schema.go rename mantle/vendor/github.com/coreos/butane/config/openshift/{v4_11_exp => v4_11}/translate.go (89%) rename mantle/vendor/github.com/coreos/butane/config/openshift/{v4_11_exp => v4_11}/validate.go (98%) create mode 100644 mantle/vendor/github.com/coreos/butane/config/openshift/v4_12/result/schema.go create mode 100644 mantle/vendor/github.com/coreos/butane/config/openshift/v4_12/schema.go create mode 100644 mantle/vendor/github.com/coreos/butane/config/openshift/v4_12/translate.go create mode 100644 mantle/vendor/github.com/coreos/butane/config/openshift/v4_12/validate.go rename mantle/vendor/github.com/coreos/butane/config/openshift/{v4_11_exp => v4_13_exp}/result/schema.go (100%) rename mantle/vendor/github.com/coreos/butane/config/openshift/{v4_11_exp => v4_13_exp}/schema.go (98%) create mode 100644 mantle/vendor/github.com/coreos/butane/config/openshift/v4_13_exp/translate.go create mode 100644 mantle/vendor/github.com/coreos/butane/config/openshift/v4_13_exp/validate.go create mode 100644 mantle/vendor/github.com/coreos/go-systemd/v22/journal/journal_unix.go create mode 100644 mantle/vendor/github.com/coreos/go-systemd/v22/journal/journal_windows.go create mode 100644 mantle/vendor/github.com/coreos/go-systemd/v22/unit/section.go delete mode 100644 mantle/vendor/github.com/godbus/dbus/v5/.travis.yml create mode 100644 mantle/vendor/github.com/godbus/dbus/v5/sequence.go create mode 100644 mantle/vendor/github.com/godbus/dbus/v5/sequential_handler.go create mode 100644 mantle/vendor/github.com/stretchr/testify/assert/assertion_compare_can_convert.go create mode 100644 mantle/vendor/github.com/stretchr/testify/assert/assertion_compare_legacy.go diff --git a/mantle/go.mod b/mantle/go.mod index dc54d31419..08b42aed1d 100644 --- a/mantle/go.mod +++ b/mantle/go.mod @@ -12,15 +12,15 @@ require ( github.com/aliyun/aliyun-oss-go-sdk v2.0.3+incompatible github.com/aws/aws-sdk-go v1.34.28 github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f // indirect - github.com/coreos/butane v0.14.0 + github.com/coreos/butane v0.16.0 github.com/coreos/coreos-assembler-schema v0.0.0-00010101000000-000000000000 github.com/coreos/go-semver v0.3.0 github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e - github.com/coreos/go-systemd/v22 v22.0.0 + github.com/coreos/go-systemd/v22 v22.4.0 github.com/coreos/ignition/v2 v2.14.0 github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f github.com/coreos/stream-metadata-go v0.3.0 - github.com/coreos/vcontext v0.0.0-20211021162308-f1dbbca7bef4 + github.com/coreos/vcontext v0.0.0-20220810162454-88bd546c634c github.com/digitalocean/go-libvirt v0.0.0-20200810224808-b9c702499bf7 // indirect github.com/digitalocean/go-qemu v0.0.0-20200529005954-1b453d036a9c github.com/digitalocean/godo v1.33.0 diff --git a/mantle/go.sum b/mantle/go.sum index 78ad655a7a..a007133fb7 100644 --- a/mantle/go.sum +++ b/mantle/go.sum @@ -68,32 +68,34 @@ github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghf github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/clarketm/json v1.14.1 h1:43bkbTTKKdDx7crs3WHzkrnH6S1EvAF1VZrdFGMmmz4= -github.com/clarketm/json v1.14.1/go.mod h1:ynr2LRfb0fQU34l07csRNBTcivjySLLiY1YzQqKVfdo= +github.com/clarketm/json v1.17.1 h1:U1IxjqJkJ7bRK4L6dyphmoO840P6bdhPdbbLySourqI= +github.com/clarketm/json v1.17.1/go.mod h1:ynr2LRfb0fQU34l07csRNBTcivjySLLiY1YzQqKVfdo= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= -github.com/coreos/butane v0.14.0 h1:1xLt5y6RR8NTmeDf6yMzqP7Jqre8PvJ/1BTXQTxEMhk= -github.com/coreos/butane v0.14.0/go.mod h1:Q5DcBsHDckEZ7IgQSb1MvvkNc50dpoT1lOHdGWwCRjY= +github.com/coreos/butane v0.16.0 h1:qIH6H9O5lF+NfX7Msz6b4+MezZ68zYCNXBjTPbgnlyU= +github.com/coreos/butane v0.16.0/go.mod h1:7TBe8e7UqDtqsR9pMZl/mKeYT1QYTAFcAiGF5ivUaaQ= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-json v0.0.0-20211020211907-c63f628265de h1:qZvNu52Tv7Jfbgxdw3ONHf0BK9UpuSxi9FA9Y+qU5VU= github.com/coreos/go-json v0.0.0-20211020211907-c63f628265de/go.mod h1:lryFBkhadOfv8Jue2Vr/f/Yviw8h1DQPQojbXqEChY0= +github.com/coreos/go-json v0.0.0-20220810161552-7cce03887f34 h1:14qC8Go5ArRXeK4neVu4GwD/2KZcLsRotqGW7eBRqwk= +github.com/coreos/go-json v0.0.0-20220810161552-7cce03887f34/go.mod h1:jdmhE6D2v5tisGyVw92x7/r3USTNm2VAkdRZ4ZydKQk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd/v22 v22.0.0 h1:XJIw/+VlJ+87J+doOxznsAWIdmWuViOVhkQamW5YV28= github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= -github.com/coreos/ignition/v2 v2.13.0/go.mod h1:HO1HWYWcvAIbHu6xewoKxPGBTyZ32FLwGIuipw5d63o= +github.com/coreos/go-systemd/v22 v22.4.0 h1:y9YHcjnjynCd/DVbg5j9L/33jQM3MxJlbj/zWskzfGU= +github.com/coreos/go-systemd/v22 v22.4.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/ignition/v2 v2.14.0 h1:KfkCCnA6AK0kts/1zxzzNH5lDMCQN9sqqGcGs+RJVX4= github.com/coreos/ignition/v2 v2.14.0/go.mod h1:wxc4qdYEIHLygzWbVVEuoD7lQGTZmMgX0VjAPYBbeEQ= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f h1:lBNOc5arjvs8E5mO2tbpBpLoyyu8B6e44T7hJy6potg= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/stream-metadata-go v0.3.0 h1:Bmoh7jC5yn/2SNiKBzbM4vqCDITo/BqMN5xZ3nt+tns= github.com/coreos/stream-metadata-go v0.3.0/go.mod h1:RTjQyHgO/G37oJ3qnqYK6Z4TPZ5EsaabOtfMjVXmgko= -github.com/coreos/vcontext v0.0.0-20211021162308-f1dbbca7bef4 h1:pfSsrvbjUFGINaPGy0mm2QKQKTdq7IcbUa+nQwsz2UM= github.com/coreos/vcontext v0.0.0-20211021162308-f1dbbca7bef4/go.mod h1:HckqHnP/HI41vS0bfVjJ20u6jD0biI5+68QwZm5Xb9U= +github.com/coreos/vcontext v0.0.0-20220810162454-88bd546c634c h1:AjP8DGsqQOtNODjbPofQULNwS0CRq6grLckmB+EhpWE= +github.com/coreos/vcontext v0.0.0-20220810162454-88bd546c634c/go.mod h1:lTNa8nCDdioj9pWs3iUvaiyQEMDjOpok/oTgu5qVleE= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -154,8 +156,9 @@ github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWe github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ= github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0= github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= -github.com/godbus/dbus/v5 v5.0.3 h1:ZqHaoEF7TBzh4jzPmqVhE/5A1z9of6orkAe5uHoAeME= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.0.4 h1:9349emZab16e7zQvpmsbtjc18ykshndd8y2PG3sgJbA= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A= @@ -249,7 +252,6 @@ github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4= @@ -348,7 +350,6 @@ github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6Mwd github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v0.0.0-20190222223459-a17d461953aa/go.mod h1:2RVY1rIf+2J2o/IM9+vPq9RzmHDSseB7FoXiSNIUsoU= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= @@ -364,13 +365,16 @@ github.com/spf13/pflag v1.0.6-0.20210604193023-d5e0c0615ace/go.mod h1:McXfInJRrz github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= @@ -382,9 +386,7 @@ github.com/vishvananda/netns v0.0.0-20150710222425-604eaf189ee8 h1:MmJ82dMUwQ+0j github.com/vishvananda/netns v0.0.0-20150710222425-604eaf189ee8/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI= github.com/vmware/govmomi v0.15.0 h1:fVMjwFASkUIGenwURwP0ruAzTjka0l2AV9wtARwkJLI= github.com/vmware/govmomi v0.15.0/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= -github.com/vmware/vmw-guestinfo v0.0.0-20170707015358-25eff159a728/go.mod h1:x9oS4Wk2s2u4tS29nEaDLdzvuHdB19CvSGJjPgkZJNk= github.com/vmware/vmw-guestinfo v0.0.0-20220317130741-510905f0efa3/go.mod h1:CSBTxrhePCm0cmXNKDGeu+6bOQzpaEklfCqEpn89JWk= -github.com/vmware/vmw-ovflib v0.0.0-20170608004843-1f217b9dc714/go.mod h1:jiPk45kn7klhByRvUq5i2vo1RtHKBHj+iWGFpxbXuuI= github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= github.com/xdg/stringprep v0.0.0-20180714160509-73f8eece6fdc/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= @@ -736,8 +738,9 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/mantle/vendor/github.com/clarketm/json/decode.go b/mantle/vendor/github.com/clarketm/json/decode.go index b43484692e..a9917e72c7 100644 --- a/mantle/vendor/github.com/clarketm/json/decode.go +++ b/mantle/vendor/github.com/clarketm/json/decode.go @@ -200,22 +200,22 @@ func (n Number) Int64() (int64, error) { return strconv.ParseInt(string(n), 10, 64) } +// An errorContext provides context for type errors during decoding. +type errorContext struct { + Struct reflect.Type + FieldStack []string +} + // decodeState represents the state while decoding a JSON value. type decodeState struct { - data []byte - off int // next read offset in data - opcode int // last read result - scan scanner - errorContext struct { // provides context for type errors - Struct reflect.Type - FieldStack []string - } + data []byte + off int // next read offset in data + opcode int // last read result + scan scanner + errorContext *errorContext savedError error useNumber bool disallowUnknownFields bool - // safeUnquote is the number of current string literal bytes that don't - // need to be unquoted. When negative, no bytes need unquoting. - safeUnquote int } // readIndex returns the position of the last byte read. @@ -232,10 +232,11 @@ func (d *decodeState) init(data []byte) *decodeState { d.data = data d.off = 0 d.savedError = nil - d.errorContext.Struct = nil - - // Reuse the allocated space for the FieldStack slice. - d.errorContext.FieldStack = d.errorContext.FieldStack[:0] + if d.errorContext != nil { + d.errorContext.Struct = nil + // Reuse the allocated space for the FieldStack slice. + d.errorContext.FieldStack = d.errorContext.FieldStack[:0] + } return d } @@ -249,12 +250,11 @@ func (d *decodeState) saveError(err error) { // addErrorContext returns a new error enhanced with information from d.errorContext func (d *decodeState) addErrorContext(err error) error { - if d.errorContext.Struct != nil || len(d.errorContext.FieldStack) > 0 { + if d.errorContext != nil && (d.errorContext.Struct != nil || len(d.errorContext.FieldStack) > 0) { switch err := err.(type) { case *UnmarshalTypeError: err.Struct = d.errorContext.Struct.Name() err.Field = strings.Join(d.errorContext.FieldStack, ".") - return err } } return err @@ -317,27 +317,13 @@ func (d *decodeState) rescanLiteral() { Switch: switch data[i-1] { case '"': // string - // safeUnquote is initialized at -1, which means that all bytes - // checked so far can be unquoted at a later time with no work - // at all. When reaching the closing '"', if safeUnquote is - // still -1, all bytes can be unquoted with no work. Otherwise, - // only those bytes up until the first '\\' or non-ascii rune - // can be safely unquoted. - safeUnquote := -1 for ; i < len(data); i++ { - if c := data[i]; c == '\\' { - if safeUnquote < 0 { // first unsafe byte - safeUnquote = int(i - d.off) - } + switch data[i] { + case '\\': i++ // escaped char - } else if c == '"' { - d.safeUnquote = safeUnquote + case '"': i++ // tokenize the closing quote too break Switch - } else if c >= utf8.RuneSelf { - if safeUnquote < 0 { // first unsafe byte - safeUnquote = int(i - d.off) - } } } case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-': // number @@ -674,7 +660,10 @@ func (d *decodeState) object(v reflect.Value) error { } var mapElem reflect.Value - origErrorContext := d.errorContext + var origErrorContext errorContext + if d.errorContext != nil { + origErrorContext = *d.errorContext + } for { // Read opening " of string key or closing }. @@ -691,7 +680,7 @@ func (d *decodeState) object(v reflect.Value) error { start := d.readIndex() d.rescanLiteral() item := d.data[start:d.readIndex()] - key, ok := d.unquoteBytes(item) + key, ok := unquoteBytes(item) if !ok { panic(phasePanicMsg) } @@ -749,6 +738,9 @@ func (d *decodeState) object(v reflect.Value) error { } subv = subv.Field(i) } + if d.errorContext == nil { + d.errorContext = new(errorContext) + } d.errorContext.FieldStack = append(d.errorContext.FieldStack, f.name) d.errorContext.Struct = t } else if d.disallowUnknownFields { @@ -829,11 +821,13 @@ func (d *decodeState) object(v reflect.Value) error { if d.opcode == scanSkipSpace { d.scanWhile(scanSkipSpace) } - // Reset errorContext to its original state. - // Keep the same underlying array for FieldStack, to reuse the - // space and avoid unnecessary allocs. - d.errorContext.FieldStack = d.errorContext.FieldStack[:len(origErrorContext.FieldStack)] - d.errorContext.Struct = origErrorContext.Struct + if d.errorContext != nil { + // Reset errorContext to its original state. + // Keep the same underlying array for FieldStack, to reuse the + // space and avoid unnecessary allocs. + d.errorContext.FieldStack = d.errorContext.FieldStack[:len(origErrorContext.FieldStack)] + d.errorContext.Struct = origErrorContext.Struct + } if d.opcode == scanEndObject { break } @@ -892,7 +886,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool d.saveError(&UnmarshalTypeError{Value: val, Type: v.Type(), Offset: int64(d.readIndex())}) return nil } - s, ok := d.unquoteBytes(item) + s, ok := unquoteBytes(item) if !ok { if fromQuoted { return fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()) @@ -943,7 +937,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool } case '"': // string - s, ok := d.unquoteBytes(item) + s, ok := unquoteBytes(item) if !ok { if fromQuoted { return fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()) @@ -1103,7 +1097,7 @@ func (d *decodeState) objectInterface() map[string]interface{} { start := d.readIndex() d.rescanLiteral() item := d.data[start:d.readIndex()] - key, ok := d.unquote(item) + key, ok := unquote(item) if !ok { panic(phasePanicMsg) } @@ -1152,7 +1146,7 @@ func (d *decodeState) literalInterface() interface{} { return c == 't' case '"': // string - s, ok := d.unquote(item) + s, ok := unquote(item) if !ok { panic(phasePanicMsg) } @@ -1195,26 +1189,38 @@ func getu4(s []byte) rune { // unquote converts a quoted JSON string literal s into an actual string t. // The rules are different than for Go, so cannot use strconv.Unquote. -// The first byte in s must be '"'. -func (d *decodeState) unquote(s []byte) (t string, ok bool) { - s, ok = d.unquoteBytes(s) +func unquote(s []byte) (t string, ok bool) { + s, ok = unquoteBytes(s) t = string(s) return } -func (d *decodeState) unquoteBytes(s []byte) (t []byte, ok bool) { - // We already know that s[0] == '"'. However, we don't know that the - // closing quote exists in all cases, such as when the string is nested - // via the ",string" option. - if len(s) < 2 || s[len(s)-1] != '"' { +func unquoteBytes(s []byte) (t []byte, ok bool) { + if len(s) < 2 || s[0] != '"' || s[len(s)-1] != '"' { return } s = s[1 : len(s)-1] - // If there are no unusual characters, no unquoting is needed, so return - // a slice of the original bytes. - r := d.safeUnquote - if r == -1 { + // Check for unusual characters. If there are none, + // then no unquoting is needed, so return a slice of the + // original bytes. + r := 0 + for r < len(s) { + c := s[r] + if c == '\\' || c == '"' || c < ' ' { + break + } + if c < utf8.RuneSelf { + r++ + continue + } + rr, size := utf8.DecodeRune(s[r:]) + if rr == utf8.RuneError && size == 1 { + break + } + r += size + } + if r == len(s) { return s, true } diff --git a/mantle/vendor/github.com/clarketm/json/encode.go b/mantle/vendor/github.com/clarketm/json/encode.go index 1b45610abe..06b2f754c2 100644 --- a/mantle/vendor/github.com/clarketm/json/encode.go +++ b/mantle/vendor/github.com/clarketm/json/encode.go @@ -153,7 +153,7 @@ import ( // // JSON cannot represent cyclic data structures and Marshal does not // handle them. Passing cyclic structures to Marshal will result in -// an infinite recursion. +// an error. // func Marshal(v interface{}) ([]byte, error) { e := newEncodeState() @@ -236,6 +236,8 @@ func (e *UnsupportedTypeError) Error() string { return "json: unsupported type: " + e.Type.String() } +// An UnsupportedValueError is returned by Marshal when attempting +// to encode an unsupported value. type UnsupportedValueError struct { Value reflect.Value Str string @@ -285,17 +287,31 @@ var hex = "0123456789abcdef" type encodeState struct { bytes.Buffer // accumulated output scratch [64]byte + + // Keep track of what pointers we've seen in the current recursive call + // path, to avoid cycles that could lead to a stack overflow. Only do + // the relatively expensive map operations if ptrLevel is larger than + // startDetectingCyclesAfter, so that we skip the work if we're within a + // reasonable amount of nested pointers deep. + ptrLevel uint + ptrSeen map[interface{}]struct{} } +const startDetectingCyclesAfter = 1000 + var encodeStatePool sync.Pool func newEncodeState() *encodeState { if v := encodeStatePool.Get(); v != nil { e := v.(*encodeState) e.Reset() + if len(e.ptrSeen) > 0 { + panic("ptrEncoder.encode should have emptied ptrSeen via defers") + } + e.ptrLevel = 0 return e } - return new(encodeState) + return &encodeState{ptrSeen: make(map[interface{}]struct{})} } // jsonError is an error wrapper type for internal use only. @@ -632,11 +648,12 @@ func stringEncoder(e *encodeState, v reflect.Value, opts encOpts) { return } if opts.quoted { - b := make([]byte, 0, v.Len()+2) - b = append(b, '"') - b = append(b, []byte(v.String())...) - b = append(b, '"') - e.stringBytes(b, opts.escapeHTML) + e2 := newEncodeState() + // Since we encode the string twice, we only need to escape HTML + // the first time. + e2.string(v.String(), opts.escapeHTML) + e.stringBytes(e2.Bytes(), false) + encodeStatePool.Put(e2) } else { e.string(v.String(), opts.escapeHTML) } @@ -646,7 +663,7 @@ func stringEncoder(e *encodeState, v reflect.Value, opts encOpts) { func isValidNumber(s string) bool { // This function implements the JSON numbers grammar. // See https://tools.ietf.org/html/rfc7159#section-6 - // and https://json.org/number.gif + // and https://www.json.org/img/number.png if s == "" { return false @@ -775,28 +792,40 @@ func (me mapEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) { e.WriteString("null") return } + if e.ptrLevel++; e.ptrLevel > startDetectingCyclesAfter { + // We're a large number of nested ptrEncoder.encode calls deep; + // start checking if we've run into a pointer cycle. + ptr := v.Pointer() + if _, ok := e.ptrSeen[ptr]; ok { + e.error(&UnsupportedValueError{v, fmt.Sprintf("encountered a cycle via %s", v.Type())}) + } + e.ptrSeen[ptr] = struct{}{} + defer delete(e.ptrSeen, ptr) + } e.WriteByte('{') // Extract and sort the keys. - keys := v.MapKeys() - sv := make([]reflectWithString, len(keys)) - for i, v := range keys { - sv[i].v = v + sv := make([]reflectWithString, v.Len()) + mi := v.MapRange() + for i := 0; mi.Next(); i++ { + sv[i].k = mi.Key() + sv[i].v = mi.Value() if err := sv[i].resolve(); err != nil { e.error(fmt.Errorf("json: encoding error for type %q: %q", v.Type().String(), err.Error())) } } - sort.Slice(sv, func(i, j int) bool { return sv[i].s < sv[j].s }) + sort.Slice(sv, func(i, j int) bool { return sv[i].ks < sv[j].ks }) for i, kv := range sv { if i > 0 { e.WriteByte(',') } - e.string(kv.s, opts.escapeHTML) + e.string(kv.ks, opts.escapeHTML) e.WriteByte(':') - me.elemEnc(e, v.MapIndex(kv.v), opts) + me.elemEnc(e, kv.v, opts) } e.WriteByte('}') + e.ptrLevel-- } func newMapEncoder(t reflect.Type) encoderFunc { @@ -853,7 +882,23 @@ func (se sliceEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) { e.WriteString("null") return } + if e.ptrLevel++; e.ptrLevel > startDetectingCyclesAfter { + // We're a large number of nested ptrEncoder.encode calls deep; + // start checking if we've run into a pointer cycle. + // Here we use a struct to memorize the pointer to the first element of the slice + // and its length. + ptr := struct { + ptr uintptr + len int + }{v.Pointer(), v.Len()} + if _, ok := e.ptrSeen[ptr]; ok { + e.error(&UnsupportedValueError{v, fmt.Sprintf("encountered a cycle via %s", v.Type())}) + } + e.ptrSeen[ptr] = struct{}{} + defer delete(e.ptrSeen, ptr) + } se.arrayEnc(e, v, opts) + e.ptrLevel-- } func newSliceEncoder(t reflect.Type) encoderFunc { @@ -898,7 +943,18 @@ func (pe ptrEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) { e.WriteString("null") return } + if e.ptrLevel++; e.ptrLevel > startDetectingCyclesAfter { + // We're a large number of nested ptrEncoder.encode calls deep; + // start checking if we've run into a pointer cycle. + ptr := v.Interface() + if _, ok := e.ptrSeen[ptr]; ok { + e.error(&UnsupportedValueError{v, fmt.Sprintf("encountered a cycle via %s", v.Type())}) + } + e.ptrSeen[ptr] = struct{}{} + defer delete(e.ptrSeen, ptr) + } pe.elemEnc(e, v.Elem(), opts) + e.ptrLevel-- } func newPtrEncoder(t reflect.Type) encoderFunc { @@ -931,7 +987,7 @@ func isValidTag(s string) bool { } for _, c := range s { switch { - case strings.ContainsRune("!#$%&()*+-./:<=>?@[]^_{|}~ ", c): + case strings.ContainsRune("!#$%&()*+-./:;<=>?@[]^_{|}~ ", c): // Backslash and quote chars are reserved, but // otherwise any punctuation chars are allowed // in a tag name. @@ -953,29 +1009,30 @@ func typeByIndex(t reflect.Type, index []int) reflect.Type { } type reflectWithString struct { - v reflect.Value - s string + k reflect.Value + v reflect.Value + ks string } func (w *reflectWithString) resolve() error { - if w.v.Kind() == reflect.String { - w.s = w.v.String() + if w.k.Kind() == reflect.String { + w.ks = w.k.String() return nil } - if tm, ok := w.v.Interface().(encoding.TextMarshaler); ok { - if w.v.Kind() == reflect.Ptr && w.v.IsNil() { + if tm, ok := w.k.Interface().(encoding.TextMarshaler); ok { + if w.k.Kind() == reflect.Ptr && w.k.IsNil() { return nil } buf, err := tm.MarshalText() - w.s = string(buf) + w.ks = string(buf) return err } - switch w.v.Kind() { + switch w.k.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - w.s = strconv.FormatInt(w.v.Int(), 10) + w.ks = strconv.FormatInt(w.k.Int(), 10) return nil case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - w.s = strconv.FormatUint(w.v.Uint(), 10) + w.ks = strconv.FormatUint(w.k.Uint(), 10) return nil } panic("unexpected map key type") @@ -1195,19 +1252,18 @@ func typeFields(t reflect.Type) structFields { // Scan f.typ for fields to include. for i := 0; i < f.typ.NumField(); i++ { sf := f.typ.Field(i) - isUnexported := sf.PkgPath != "" if sf.Anonymous { t := sf.Type if t.Kind() == reflect.Ptr { t = t.Elem() } - if isUnexported && t.Kind() != reflect.Struct { + if !sf.IsExported() && t.Kind() != reflect.Struct { // Ignore embedded fields of unexported non-struct types. continue } // Do not ignore embedded fields of unexported struct types // since they may have exported fields. - } else if isUnexported { + } else if !sf.IsExported() { // Ignore unexported non-embedded fields. continue } diff --git a/mantle/vendor/github.com/clarketm/json/fuzz.go b/mantle/vendor/github.com/clarketm/json/fuzz.go index be03f0d7ff..d3fa2d1113 100644 --- a/mantle/vendor/github.com/clarketm/json/fuzz.go +++ b/mantle/vendor/github.com/clarketm/json/fuzz.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build gofuzz // +build gofuzz package json diff --git a/mantle/vendor/github.com/clarketm/json/scanner.go b/mantle/vendor/github.com/clarketm/json/scanner.go index 552bd70360..9dc1903e2d 100644 --- a/mantle/vendor/github.com/clarketm/json/scanner.go +++ b/mantle/vendor/github.com/clarketm/json/scanner.go @@ -139,6 +139,10 @@ const ( parseArrayValue // parsing array value ) +// This limits the max nesting depth to prevent stack overflow. +// This is permitted by https://tools.ietf.org/html/rfc7159#section-9 +const maxNestingDepth = 10000 + // reset prepares the scanner for use. // It must be called before calling s.step. func (s *scanner) reset() { @@ -168,8 +172,13 @@ func (s *scanner) eof() int { } // pushParseState pushes a new parse state p onto the parse stack. -func (s *scanner) pushParseState(p int) { - s.parseState = append(s.parseState, p) +// an error state is returned if maxNestingDepth was exceeded, otherwise successState is returned. +func (s *scanner) pushParseState(c byte, newParseState int, successState int) int { + s.parseState = append(s.parseState, newParseState) + if len(s.parseState) <= maxNestingDepth { + return successState + } + return s.error(c, "exceeded max depth") } // popParseState pops a parse state (already obtained) off the stack @@ -186,12 +195,12 @@ func (s *scanner) popParseState() { } func isSpace(c byte) bool { - return c == ' ' || c == '\t' || c == '\r' || c == '\n' + return c <= ' ' && (c == ' ' || c == '\t' || c == '\r' || c == '\n') } // stateBeginValueOrEmpty is the state after reading `[`. func stateBeginValueOrEmpty(s *scanner, c byte) int { - if c <= ' ' && isSpace(c) { + if isSpace(c) { return scanSkipSpace } if c == ']' { @@ -202,18 +211,16 @@ func stateBeginValueOrEmpty(s *scanner, c byte) int { // stateBeginValue is the state at the beginning of the input. func stateBeginValue(s *scanner, c byte) int { - if c <= ' ' && isSpace(c) { + if isSpace(c) { return scanSkipSpace } switch c { case '{': s.step = stateBeginStringOrEmpty - s.pushParseState(parseObjectKey) - return scanBeginObject + return s.pushParseState(c, parseObjectKey, scanBeginObject) case '[': s.step = stateBeginValueOrEmpty - s.pushParseState(parseArrayValue) - return scanBeginArray + return s.pushParseState(c, parseArrayValue, scanBeginArray) case '"': s.step = stateInString return scanBeginLiteral @@ -242,7 +249,7 @@ func stateBeginValue(s *scanner, c byte) int { // stateBeginStringOrEmpty is the state after reading `{`. func stateBeginStringOrEmpty(s *scanner, c byte) int { - if c <= ' ' && isSpace(c) { + if isSpace(c) { return scanSkipSpace } if c == '}' { @@ -255,7 +262,7 @@ func stateBeginStringOrEmpty(s *scanner, c byte) int { // stateBeginString is the state after reading `{"key": value,`. func stateBeginString(s *scanner, c byte) int { - if c <= ' ' && isSpace(c) { + if isSpace(c) { return scanSkipSpace } if c == '"' { @@ -275,7 +282,7 @@ func stateEndValue(s *scanner, c byte) int { s.endTop = true return stateEndTop(s, c) } - if c <= ' ' && isSpace(c) { + if isSpace(c) { s.step = stateEndValue return scanSkipSpace } diff --git a/mantle/vendor/github.com/coreos/butane/base/util/file.go b/mantle/vendor/github.com/coreos/butane/base/util/file.go index a6f9168088..73e24d4cc3 100644 --- a/mantle/vendor/github.com/coreos/butane/base/util/file.go +++ b/mantle/vendor/github.com/coreos/butane/base/util/file.go @@ -36,8 +36,8 @@ func EnsurePathWithinFilesDir(path, filesDir string) error { return nil } -/// CheckForDecimalMode fails if the specified mode appears to have been -/// incorrectly specified in decimal instead of octal. +// CheckForDecimalMode fails if the specified mode appears to have been +// incorrectly specified in decimal instead of octal. func CheckForDecimalMode(mode int, directory bool) error { correctedMode, ok := decimalModeToOctal(mode) if !ok { @@ -49,9 +49,9 @@ func CheckForDecimalMode(mode int, directory bool) error { return nil } -/// isTypicalMode returns true if the specified mode is unsurprising. -/// It returns false for some modes that are unusual but valid in limited -/// cases. +// isTypicalMode returns true if the specified mode is unsurprising. +// It returns false for some modes that are unusual but valid in limited +// cases. func isTypicalMode(mode int, directory bool) bool { // no permissions is always reasonable (root ignores mode bits) if mode == 0 { @@ -126,8 +126,8 @@ func isTypicalMode(mode int, directory bool) bool { return true } -/// decimalModeToOctal takes a mode written in decimal and converts it to -/// octal, returning (0, false) on failure. +// decimalModeToOctal takes a mode written in decimal and converts it to +// octal, returning (0, false) on failure. func decimalModeToOctal(mode int) (int, bool) { if mode < 0 || mode > 7777 { // out of range diff --git a/mantle/vendor/github.com/coreos/butane/base/util/url.go b/mantle/vendor/github.com/coreos/butane/base/util/url.go index 2cf3bef070..b7bc035924 100644 --- a/mantle/vendor/github.com/coreos/butane/base/util/url.go +++ b/mantle/vendor/github.com/coreos/butane/base/util/url.go @@ -24,9 +24,24 @@ import ( "github.com/vincent-petithory/dataurl" ) -func MakeDataURL(contents []byte, currentCompression *string, allowCompression bool) (uri string, gzipped bool, err error) { +func MakeDataURL(contents []byte, currentCompression *string, allowCompression bool) (uri string, compression *string, err error) { // try three different encodings, and select the smallest one + if util.NilOrEmpty(currentCompression) { + // The config does not specify compression. We need to + // explicitly set the compression field to avoid a child + // config inheriting a compression setting from the parent, + // which may not have used the same compression algorithm. + compression = util.StrToPtr("") + } else { + // The config specifies compression, meaning that the + // contents were compressed by the user, so we can pick a + // data URL encoding but we can't compress again. Return a + // nil compression value so the caller knows not to record a + // translation from input contents to output compression. + compression = nil + } + // URL-escaped, useful for ASCII text opaque := "," + dataurl.Escape(contents) @@ -53,10 +68,10 @@ func MakeDataURL(contents []byte, currentCompression *string, allowCompression b return } gz := ";base64," + base64.StdEncoding.EncodeToString(buf.Bytes()) - // Account for space needed by "compression": "gzip". - if len(gz)+25 < len(opaque) { + // Account for space needed by the compression value + if len(gz)+len("gzip") < len(opaque) { opaque = gz - gzipped = true + compression = util.StrToPtr("gzip") } } diff --git a/mantle/vendor/github.com/coreos/butane/base/v0_2/translate.go b/mantle/vendor/github.com/coreos/butane/base/v0_2/translate.go index 9199861e2c..3d05bd0e8f 100644 --- a/mantle/vendor/github.com/coreos/butane/base/v0_2/translate.go +++ b/mantle/vendor/github.com/coreos/butane/base/v0_2/translate.go @@ -15,8 +15,8 @@ package v0_2 import ( - "io/ioutil" "os" + slashpath "path" "path/filepath" "strings" "text/template" @@ -25,7 +25,7 @@ import ( "github.com/coreos/butane/config/common" "github.com/coreos/butane/translate" - "github.com/coreos/go-systemd/unit" + "github.com/coreos/go-systemd/v22/unit" "github.com/coreos/ignition/v2/config/util" "github.com/coreos/ignition/v2/config/v3_1/types" "github.com/coreos/vcontext/path" @@ -127,27 +127,27 @@ func translateResource(from Resource, options common.TranslateOptions) (to types // calculate file path within FilesDir and check for // path traversal - filePath := filepath.Join(options.FilesDir, *from.Local) + filePath := filepath.Join(options.FilesDir, filepath.FromSlash(*from.Local)) if err := baseutil.EnsurePathWithinFilesDir(filePath, options.FilesDir); err != nil { r.AddOnError(c, err) return } - contents, err := ioutil.ReadFile(filePath) + contents, err := os.ReadFile(filePath) if err != nil { r.AddOnError(c, err) return } - src, gzipped, err := baseutil.MakeDataURL(contents, to.Compression, !options.NoResourceAutoCompression) + src, compression, err := baseutil.MakeDataURL(contents, to.Compression, !options.NoResourceAutoCompression) if err != nil { r.AddOnError(c, err) return } to.Source = &src tm.AddTranslation(c, path.New("json", "source")) - if gzipped { - to.Compression = util.StrToPtr("gzip") + if compression != nil { + to.Compression = compression tm.AddTranslation(c, path.New("json", "compression")) } } @@ -155,15 +155,15 @@ func translateResource(from Resource, options common.TranslateOptions) (to types if from.Inline != nil { c := path.New("yaml", "inline") - src, gzipped, err := baseutil.MakeDataURL([]byte(*from.Inline), to.Compression, !options.NoResourceAutoCompression) + src, compression, err := baseutil.MakeDataURL([]byte(*from.Inline), to.Compression, !options.NoResourceAutoCompression) if err != nil { r.AddOnError(c, err) return } to.Source = &src tm.AddTranslation(c, path.New("json", "source")) - if gzipped { - to.Compression = util.StrToPtr("gzip") + if compression != nil { + to.Compression = compression tm.AddTranslation(c, path.New("json", "compression")) } } @@ -208,7 +208,7 @@ func (c Config) processTrees(ret *types.Config, options common.TranslateOptions) // calculate base path within FilesDir and check for // path traversal - srcBaseDir := filepath.Join(options.FilesDir, tree.Local) + srcBaseDir := filepath.Join(options.FilesDir, filepath.FromSlash(tree.Local)) if err := baseutil.EnsurePathWithinFilesDir(srcBaseDir, options.FilesDir); err != nil { r.AddOnError(yamlPath, err) continue @@ -246,7 +246,7 @@ func walkTree(yamlPath path.ContextPath, ts *translate.TranslationSet, r *report r.AddOnError(yamlPath, err) return nil } - destPath := filepath.Join(destBaseDir, relPath) + destPath := slashpath.Join(destBaseDir, filepath.ToSlash(relPath)) if info.Mode().IsDir() { return nil @@ -272,20 +272,20 @@ func walkTree(yamlPath path.ContextPath, ts *translate.TranslationSet, r *report ts.AddTranslation(yamlPath, path.New("json", "storage", "files")) } } - contents, err := ioutil.ReadFile(srcPath) + contents, err := os.ReadFile(srcPath) if err != nil { r.AddOnError(yamlPath, err) return nil } - url, gzipped, err := baseutil.MakeDataURL(contents, file.Contents.Compression, !options.NoResourceAutoCompression) + url, compression, err := baseutil.MakeDataURL(contents, file.Contents.Compression, !options.NoResourceAutoCompression) if err != nil { r.AddOnError(yamlPath, err) return nil } - file.Contents.Source = util.StrToPtr(url) + file.Contents.Source = &url ts.AddTranslation(yamlPath, path.New("json", "storage", "files", i, "contents", "source")) - if gzipped { - file.Contents.Compression = util.StrToPtr("gzip") + if compression != nil { + file.Contents.Compression = compression ts.AddTranslation(yamlPath, path.New("json", "storage", "files", i, "contents", "compression")) } ts.AddTranslation(yamlPath, path.New("json", "storage", "files", i, "contents")) @@ -319,11 +319,12 @@ func walkTree(yamlPath path.ContextPath, ts *translate.TranslationSet, r *report ts.AddTranslation(yamlPath, path.New("json", "storage", "links")) } } - link.Target, err = os.Readlink(srcPath) + target, err := os.Readlink(srcPath) if err != nil { r.AddOnError(yamlPath, err) return nil } + link.Target = filepath.ToSlash(target) ts.AddTranslation(yamlPath, path.New("json", "storage", "links", i, "target")) } else { r.AddOnError(yamlPath, common.ErrFileType) diff --git a/mantle/vendor/github.com/coreos/butane/base/v0_3/translate.go b/mantle/vendor/github.com/coreos/butane/base/v0_3/translate.go index cf8763423f..35dec7f74d 100644 --- a/mantle/vendor/github.com/coreos/butane/base/v0_3/translate.go +++ b/mantle/vendor/github.com/coreos/butane/base/v0_3/translate.go @@ -16,8 +16,8 @@ package v0_3 import ( "fmt" - "io/ioutil" "os" + slashpath "path" "path/filepath" "strings" "text/template" @@ -26,7 +26,7 @@ import ( "github.com/coreos/butane/config/common" "github.com/coreos/butane/translate" - "github.com/coreos/go-systemd/unit" + "github.com/coreos/go-systemd/v22/unit" "github.com/coreos/ignition/v2/config/util" "github.com/coreos/ignition/v2/config/v3_2/types" "github.com/coreos/vcontext/path" @@ -138,27 +138,27 @@ func translateResource(from Resource, options common.TranslateOptions) (to types // calculate file path within FilesDir and check for // path traversal - filePath := filepath.Join(options.FilesDir, *from.Local) + filePath := filepath.Join(options.FilesDir, filepath.FromSlash(*from.Local)) if err := baseutil.EnsurePathWithinFilesDir(filePath, options.FilesDir); err != nil { r.AddOnError(c, err) return } - contents, err := ioutil.ReadFile(filePath) + contents, err := os.ReadFile(filePath) if err != nil { r.AddOnError(c, err) return } - src, gzipped, err := baseutil.MakeDataURL(contents, to.Compression, !options.NoResourceAutoCompression) + src, compression, err := baseutil.MakeDataURL(contents, to.Compression, !options.NoResourceAutoCompression) if err != nil { r.AddOnError(c, err) return } to.Source = &src tm.AddTranslation(c, path.New("json", "source")) - if gzipped { - to.Compression = util.StrToPtr("gzip") + if compression != nil { + to.Compression = compression tm.AddTranslation(c, path.New("json", "compression")) } } @@ -166,15 +166,15 @@ func translateResource(from Resource, options common.TranslateOptions) (to types if from.Inline != nil { c := path.New("yaml", "inline") - src, gzipped, err := baseutil.MakeDataURL([]byte(*from.Inline), to.Compression, !options.NoResourceAutoCompression) + src, compression, err := baseutil.MakeDataURL([]byte(*from.Inline), to.Compression, !options.NoResourceAutoCompression) if err != nil { r.AddOnError(c, err) return } to.Source = &src tm.AddTranslation(c, path.New("json", "source")) - if gzipped { - to.Compression = util.StrToPtr("gzip") + if compression != nil { + to.Compression = compression tm.AddTranslation(c, path.New("json", "compression")) } } @@ -219,7 +219,7 @@ func (c Config) processTrees(ret *types.Config, options common.TranslateOptions) // calculate base path within FilesDir and check for // path traversal - srcBaseDir := filepath.Join(options.FilesDir, tree.Local) + srcBaseDir := filepath.Join(options.FilesDir, filepath.FromSlash(tree.Local)) if err := baseutil.EnsurePathWithinFilesDir(srcBaseDir, options.FilesDir); err != nil { r.AddOnError(yamlPath, err) continue @@ -257,7 +257,7 @@ func walkTree(yamlPath path.ContextPath, ts *translate.TranslationSet, r *report r.AddOnError(yamlPath, err) return nil } - destPath := filepath.Join(destBaseDir, relPath) + destPath := slashpath.Join(destBaseDir, filepath.ToSlash(relPath)) if info.Mode().IsDir() { return nil @@ -283,20 +283,20 @@ func walkTree(yamlPath path.ContextPath, ts *translate.TranslationSet, r *report ts.AddTranslation(yamlPath, path.New("json", "storage", "files")) } } - contents, err := ioutil.ReadFile(srcPath) + contents, err := os.ReadFile(srcPath) if err != nil { r.AddOnError(yamlPath, err) return nil } - url, gzipped, err := baseutil.MakeDataURL(contents, file.Contents.Compression, !options.NoResourceAutoCompression) + url, compression, err := baseutil.MakeDataURL(contents, file.Contents.Compression, !options.NoResourceAutoCompression) if err != nil { r.AddOnError(yamlPath, err) return nil } - file.Contents.Source = util.StrToPtr(url) + file.Contents.Source = &url ts.AddTranslation(yamlPath, path.New("json", "storage", "files", i, "contents", "source")) - if gzipped { - file.Contents.Compression = util.StrToPtr("gzip") + if compression != nil { + file.Contents.Compression = compression ts.AddTranslation(yamlPath, path.New("json", "storage", "files", i, "contents", "compression")) } ts.AddTranslation(yamlPath, path.New("json", "storage", "files", i, "contents")) @@ -330,11 +330,12 @@ func walkTree(yamlPath path.ContextPath, ts *translate.TranslationSet, r *report ts.AddTranslation(yamlPath, path.New("json", "storage", "links")) } } - link.Target, err = os.Readlink(srcPath) + target, err := os.Readlink(srcPath) if err != nil { r.AddOnError(yamlPath, err) return nil } + link.Target = filepath.ToSlash(target) ts.AddTranslation(yamlPath, path.New("json", "storage", "links", i, "target")) } else { r.AddOnError(yamlPath, common.ErrFileType) diff --git a/mantle/vendor/github.com/coreos/butane/base/v0_4/translate.go b/mantle/vendor/github.com/coreos/butane/base/v0_4/translate.go index b17492bd92..9e2caa857b 100644 --- a/mantle/vendor/github.com/coreos/butane/base/v0_4/translate.go +++ b/mantle/vendor/github.com/coreos/butane/base/v0_4/translate.go @@ -16,8 +16,8 @@ package v0_4 import ( "fmt" - "io/ioutil" "os" + slashpath "path" "path/filepath" "strings" "text/template" @@ -26,7 +26,7 @@ import ( "github.com/coreos/butane/config/common" "github.com/coreos/butane/translate" - "github.com/coreos/go-systemd/unit" + "github.com/coreos/go-systemd/v22/unit" "github.com/coreos/ignition/v2/config/util" "github.com/coreos/ignition/v2/config/v3_3/types" "github.com/coreos/vcontext/path" @@ -153,27 +153,27 @@ func translateResource(from Resource, options common.TranslateOptions) (to types // calculate file path within FilesDir and check for // path traversal - filePath := filepath.Join(options.FilesDir, *from.Local) + filePath := filepath.Join(options.FilesDir, filepath.FromSlash(*from.Local)) if err := baseutil.EnsurePathWithinFilesDir(filePath, options.FilesDir); err != nil { r.AddOnError(c, err) return } - contents, err := ioutil.ReadFile(filePath) + contents, err := os.ReadFile(filePath) if err != nil { r.AddOnError(c, err) return } - src, gzipped, err := baseutil.MakeDataURL(contents, to.Compression, !options.NoResourceAutoCompression) + src, compression, err := baseutil.MakeDataURL(contents, to.Compression, !options.NoResourceAutoCompression) if err != nil { r.AddOnError(c, err) return } to.Source = &src tm.AddTranslation(c, path.New("json", "source")) - if gzipped { - to.Compression = util.StrToPtr("gzip") + if compression != nil { + to.Compression = compression tm.AddTranslation(c, path.New("json", "compression")) } } @@ -181,15 +181,15 @@ func translateResource(from Resource, options common.TranslateOptions) (to types if from.Inline != nil { c := path.New("yaml", "inline") - src, gzipped, err := baseutil.MakeDataURL([]byte(*from.Inline), to.Compression, !options.NoResourceAutoCompression) + src, compression, err := baseutil.MakeDataURL([]byte(*from.Inline), to.Compression, !options.NoResourceAutoCompression) if err != nil { r.AddOnError(c, err) return } to.Source = &src tm.AddTranslation(c, path.New("json", "source")) - if gzipped { - to.Compression = util.StrToPtr("gzip") + if compression != nil { + to.Compression = compression tm.AddTranslation(c, path.New("json", "compression")) } } @@ -234,7 +234,7 @@ func (c Config) processTrees(ret *types.Config, options common.TranslateOptions) // calculate base path within FilesDir and check for // path traversal - srcBaseDir := filepath.Join(options.FilesDir, tree.Local) + srcBaseDir := filepath.Join(options.FilesDir, filepath.FromSlash(tree.Local)) if err := baseutil.EnsurePathWithinFilesDir(srcBaseDir, options.FilesDir); err != nil { r.AddOnError(yamlPath, err) continue @@ -272,7 +272,7 @@ func walkTree(yamlPath path.ContextPath, ts *translate.TranslationSet, r *report r.AddOnError(yamlPath, err) return nil } - destPath := filepath.Join(destBaseDir, relPath) + destPath := slashpath.Join(destBaseDir, filepath.ToSlash(relPath)) if info.Mode().IsDir() { return nil @@ -298,20 +298,20 @@ func walkTree(yamlPath path.ContextPath, ts *translate.TranslationSet, r *report ts.AddTranslation(yamlPath, path.New("json", "storage", "files")) } } - contents, err := ioutil.ReadFile(srcPath) + contents, err := os.ReadFile(srcPath) if err != nil { r.AddOnError(yamlPath, err) return nil } - url, gzipped, err := baseutil.MakeDataURL(contents, file.Contents.Compression, !options.NoResourceAutoCompression) + url, compression, err := baseutil.MakeDataURL(contents, file.Contents.Compression, !options.NoResourceAutoCompression) if err != nil { r.AddOnError(yamlPath, err) return nil } - file.Contents.Source = util.StrToPtr(url) + file.Contents.Source = &url ts.AddTranslation(yamlPath, path.New("json", "storage", "files", i, "contents", "source")) - if gzipped { - file.Contents.Compression = util.StrToPtr("gzip") + if compression != nil { + file.Contents.Compression = compression ts.AddTranslation(yamlPath, path.New("json", "storage", "files", i, "contents", "compression")) } ts.AddTranslation(yamlPath, path.New("json", "storage", "files", i, "contents")) @@ -350,7 +350,7 @@ func walkTree(yamlPath path.ContextPath, ts *translate.TranslationSet, r *report r.AddOnError(yamlPath, err) return nil } - link.Target = &target + link.Target = util.StrToPtr(filepath.ToSlash(target)) ts.AddTranslation(yamlPath, path.New("json", "storage", "links", i, "target")) } else { r.AddOnError(yamlPath, common.ErrFileType) diff --git a/mantle/vendor/github.com/coreos/butane/base/v0_5_exp/translate.go b/mantle/vendor/github.com/coreos/butane/base/v0_5_exp/translate.go index 960cd9e139..d53aa05d4a 100644 --- a/mantle/vendor/github.com/coreos/butane/base/v0_5_exp/translate.go +++ b/mantle/vendor/github.com/coreos/butane/base/v0_5_exp/translate.go @@ -16,8 +16,8 @@ package v0_5_exp import ( "fmt" - "io/ioutil" "os" + slashpath "path" "path/filepath" "strings" "text/template" @@ -26,7 +26,7 @@ import ( "github.com/coreos/butane/config/common" "github.com/coreos/butane/translate" - "github.com/coreos/go-systemd/unit" + "github.com/coreos/go-systemd/v22/unit" "github.com/coreos/ignition/v2/config/util" "github.com/coreos/ignition/v2/config/v3_4_experimental/types" "github.com/coreos/vcontext/path" @@ -153,27 +153,27 @@ func translateResource(from Resource, options common.TranslateOptions) (to types // calculate file path within FilesDir and check for // path traversal - filePath := filepath.Join(options.FilesDir, *from.Local) + filePath := filepath.Join(options.FilesDir, filepath.FromSlash(*from.Local)) if err := baseutil.EnsurePathWithinFilesDir(filePath, options.FilesDir); err != nil { r.AddOnError(c, err) return } - contents, err := ioutil.ReadFile(filePath) + contents, err := os.ReadFile(filePath) if err != nil { r.AddOnError(c, err) return } - src, gzipped, err := baseutil.MakeDataURL(contents, to.Compression, !options.NoResourceAutoCompression) + src, compression, err := baseutil.MakeDataURL(contents, to.Compression, !options.NoResourceAutoCompression) if err != nil { r.AddOnError(c, err) return } to.Source = &src tm.AddTranslation(c, path.New("json", "source")) - if gzipped { - to.Compression = util.StrToPtr("gzip") + if compression != nil { + to.Compression = compression tm.AddTranslation(c, path.New("json", "compression")) } } @@ -181,15 +181,15 @@ func translateResource(from Resource, options common.TranslateOptions) (to types if from.Inline != nil { c := path.New("yaml", "inline") - src, gzipped, err := baseutil.MakeDataURL([]byte(*from.Inline), to.Compression, !options.NoResourceAutoCompression) + src, compression, err := baseutil.MakeDataURL([]byte(*from.Inline), to.Compression, !options.NoResourceAutoCompression) if err != nil { r.AddOnError(c, err) return } to.Source = &src tm.AddTranslation(c, path.New("json", "source")) - if gzipped { - to.Compression = util.StrToPtr("gzip") + if compression != nil { + to.Compression = compression tm.AddTranslation(c, path.New("json", "compression")) } } @@ -234,7 +234,7 @@ func (c Config) processTrees(ret *types.Config, options common.TranslateOptions) // calculate base path within FilesDir and check for // path traversal - srcBaseDir := filepath.Join(options.FilesDir, tree.Local) + srcBaseDir := filepath.Join(options.FilesDir, filepath.FromSlash(tree.Local)) if err := baseutil.EnsurePathWithinFilesDir(srcBaseDir, options.FilesDir); err != nil { r.AddOnError(yamlPath, err) continue @@ -272,7 +272,7 @@ func walkTree(yamlPath path.ContextPath, ts *translate.TranslationSet, r *report r.AddOnError(yamlPath, err) return nil } - destPath := filepath.Join(destBaseDir, relPath) + destPath := slashpath.Join(destBaseDir, filepath.ToSlash(relPath)) if info.Mode().IsDir() { return nil @@ -298,20 +298,20 @@ func walkTree(yamlPath path.ContextPath, ts *translate.TranslationSet, r *report ts.AddTranslation(yamlPath, path.New("json", "storage", "files")) } } - contents, err := ioutil.ReadFile(srcPath) + contents, err := os.ReadFile(srcPath) if err != nil { r.AddOnError(yamlPath, err) return nil } - url, gzipped, err := baseutil.MakeDataURL(contents, file.Contents.Compression, !options.NoResourceAutoCompression) + url, compression, err := baseutil.MakeDataURL(contents, file.Contents.Compression, !options.NoResourceAutoCompression) if err != nil { r.AddOnError(yamlPath, err) return nil } - file.Contents.Source = util.StrToPtr(url) + file.Contents.Source = &url ts.AddTranslation(yamlPath, path.New("json", "storage", "files", i, "contents", "source")) - if gzipped { - file.Contents.Compression = util.StrToPtr("gzip") + if compression != nil { + file.Contents.Compression = compression ts.AddTranslation(yamlPath, path.New("json", "storage", "files", i, "contents", "compression")) } ts.AddTranslation(yamlPath, path.New("json", "storage", "files", i, "contents")) @@ -350,7 +350,7 @@ func walkTree(yamlPath path.ContextPath, ts *translate.TranslationSet, r *report r.AddOnError(yamlPath, err) return nil } - link.Target = &target + link.Target = util.StrToPtr(filepath.ToSlash(target)) ts.AddTranslation(yamlPath, path.New("json", "storage", "links", i, "target")) } else { r.AddOnError(yamlPath, common.ErrFileType) diff --git a/mantle/vendor/github.com/coreos/butane/config/common/errors.go b/mantle/vendor/github.com/coreos/butane/config/common/errors.go index 38313835b1..1961f00749 100644 --- a/mantle/vendor/github.com/coreos/butane/config/common/errors.go +++ b/mantle/vendor/github.com/coreos/butane/config/common/errors.go @@ -64,12 +64,20 @@ var ( ErrFileSchemeSupport = errors.New("file contents source must be data URL in this spec version") ErrFileAppendSupport = errors.New("appending to files is not supported in this spec version") ErrFileCompressionSupport = errors.New("file compression is not supported in this spec version") + ErrFileSpecialModeSupport = errors.New("special mode bits are not supported in this spec version") ErrLinkSupport = errors.New("links are not supported in this spec version") ErrGroupSupport = errors.New("groups are not supported in this spec version") ErrUserFieldSupport = errors.New("fields other than \"name\" and \"ssh_authorized_keys\" are not supported in this spec version") ErrUserNameSupport = errors.New("users other than \"core\" are not supported in this spec version") ErrKernelArgumentSupport = errors.New("this field cannot be used for kernel arguments in this spec version; use openshift.kernel_arguments instead") + // Storage + ErrClevisSupport = errors.New("clevis is not supported in this spec version") + // Extensions ErrExtensionNameRequired = errors.New("field \"name\" is required") + + // Grub + ErrGrubUserNameNotSpecified = errors.New("field \"name\" is required") + ErrGrubPasswordNotSpecified = errors.New("field \"password_hash\" is required") ) diff --git a/mantle/vendor/github.com/coreos/butane/config/config.go b/mantle/vendor/github.com/coreos/butane/config/config.go index b71bcf4ffe..61719477f3 100644 --- a/mantle/vendor/github.com/coreos/butane/config/config.go +++ b/mantle/vendor/github.com/coreos/butane/config/config.go @@ -24,8 +24,12 @@ import ( fcos1_3 "github.com/coreos/butane/config/fcos/v1_3" fcos1_4 "github.com/coreos/butane/config/fcos/v1_4" fcos1_5_exp "github.com/coreos/butane/config/fcos/v1_5_exp" + flatcar1_0 "github.com/coreos/butane/config/flatcar/v1_0" + flatcar1_1_exp "github.com/coreos/butane/config/flatcar/v1_1_exp" openshift4_10 "github.com/coreos/butane/config/openshift/v4_10" - openshift4_11_exp "github.com/coreos/butane/config/openshift/v4_11_exp" + openshift4_11 "github.com/coreos/butane/config/openshift/v4_11" + openshift4_12 "github.com/coreos/butane/config/openshift/v4_12" + openshift4_13_exp "github.com/coreos/butane/config/openshift/v4_13_exp" openshift4_8 "github.com/coreos/butane/config/openshift/v4_8" openshift4_9 "github.com/coreos/butane/config/openshift/v4_9" rhcos0_1 "github.com/coreos/butane/config/rhcos/v0_1" @@ -39,7 +43,7 @@ var ( registry = map[string]translator{} ) -/// Fields that must be included in the root struct of every spec version. +// Fields that must be included in the root struct of every spec version. type commonFields struct { Version string `yaml:"version"` Variant string `yaml:"variant"` @@ -52,16 +56,20 @@ func init() { RegisterTranslator("fcos", "1.3.0", fcos1_3.ToIgn3_2Bytes) RegisterTranslator("fcos", "1.4.0", fcos1_4.ToIgn3_3Bytes) RegisterTranslator("fcos", "1.5.0-experimental", fcos1_5_exp.ToIgn3_4Bytes) + RegisterTranslator("flatcar", "1.0.0", flatcar1_0.ToIgn3_3Bytes) + RegisterTranslator("flatcar", "1.1.0-experimental", flatcar1_1_exp.ToIgn3_4Bytes) RegisterTranslator("openshift", "4.8.0", openshift4_8.ToConfigBytes) RegisterTranslator("openshift", "4.9.0", openshift4_9.ToConfigBytes) RegisterTranslator("openshift", "4.10.0", openshift4_10.ToConfigBytes) - RegisterTranslator("openshift", "4.11.0-experimental", openshift4_11_exp.ToConfigBytes) + RegisterTranslator("openshift", "4.11.0", openshift4_11.ToConfigBytes) + RegisterTranslator("openshift", "4.12.0", openshift4_12.ToConfigBytes) + RegisterTranslator("openshift", "4.13.0-experimental", openshift4_13_exp.ToConfigBytes) RegisterTranslator("rhcos", "0.1.0", rhcos0_1.ToIgn3_2Bytes) } -/// RegisterTranslator registers a translator for the specified variant and -/// version to be available for use by TranslateBytes. This is only needed -/// by users implementing their own translators outside the Butane package. +// RegisterTranslator registers a translator for the specified variant and +// version to be available for use by TranslateBytes. This is only needed +// by users implementing their own translators outside the Butane package. func RegisterTranslator(variant, version string, trans translator) { key := fmt.Sprintf("%s+%s", variant, version) if _, ok := registry[key]; ok { diff --git a/mantle/vendor/github.com/coreos/butane/config/fcos/v1_5_exp/schema.go b/mantle/vendor/github.com/coreos/butane/config/fcos/v1_5_exp/schema.go index fc174dac9b..d985413d7f 100644 --- a/mantle/vendor/github.com/coreos/butane/config/fcos/v1_5_exp/schema.go +++ b/mantle/vendor/github.com/coreos/butane/config/fcos/v1_5_exp/schema.go @@ -22,6 +22,7 @@ type Config struct { base.Config `yaml:",inline"` BootDevice BootDevice `yaml:"boot_device"` Extensions []Extension `yaml:"extensions"` + Grub Grub `yaml:"grub"` } type BootDevice struct { @@ -43,3 +44,12 @@ type BootDeviceMirror struct { type Extension struct { Name string `yaml:"name"` } + +type Grub struct { + Users []GrubUser `yaml:"users"` +} + +type GrubUser struct { + Name string `yaml:"name"` + PasswordHash *string `yaml:"password_hash"` +} diff --git a/mantle/vendor/github.com/coreos/butane/config/fcos/v1_5_exp/translate.go b/mantle/vendor/github.com/coreos/butane/config/fcos/v1_5_exp/translate.go index c941af28c0..f2eec2fd0c 100644 --- a/mantle/vendor/github.com/coreos/butane/config/fcos/v1_5_exp/translate.go +++ b/mantle/vendor/github.com/coreos/butane/config/fcos/v1_5_exp/translate.go @@ -18,6 +18,7 @@ import ( "crypto/sha256" "encoding/hex" "fmt" + "strings" baseutil "github.com/coreos/butane/base/util" "github.com/coreos/butane/config/common" @@ -86,6 +87,11 @@ func (c Config) ToIgn3_4Unvalidated(options common.TranslateOptions) (types.Conf retConfig, ts := baseutil.MergeTranslatedConfigs(retp, tsp, ret, ts) ret = retConfig.(types.Config) r.Merge(rp) + + retp, tsp, rp = c.handleUserGrubCfg(options) + retConfig, ts = baseutil.MergeTranslatedConfigs(retp, tsp, ret, ts) + ret = retConfig.(types.Config) + r.Merge(rp) return ret, ts, r } @@ -323,7 +329,7 @@ func (c Config) processPackages(options common.TranslateOptions) (types.Config, return ret, ts, r } fullYamlContents := append([]byte("# Generated by Butane\n\n"), treeFileContents...) - src, gzipped, err := baseutil.MakeDataURL(fullYamlContents, nil, !options.NoResourceAutoCompression) + src, compression, err := baseutil.MakeDataURL(fullYamlContents, nil, !options.NoResourceAutoCompression) if err != nil { r.AddOnError(yamlPath, err) return ret, ts, r @@ -337,16 +343,74 @@ func (c Config) processPackages(options common.TranslateOptions) (types.Config, }, FileEmbedded1: types.FileEmbedded1{ Contents: types.Resource{ - Source: util.StrToPtr(src), + Source: &src, + Compression: compression, }, Mode: util.IntToPtr(0644), }, } - if gzipped { - file.Contents.Compression = util.StrToPtr("gzip") - } ret.Storage.Files = append(ret.Storage.Files, file) ts.AddFromCommonSource(yamlPath, path.New("json", "storage"), ret.Storage) return ret, ts, r } + +func (c Config) handleUserGrubCfg(options common.TranslateOptions) (types.Config, translate.TranslationSet, report.Report) { + rendered := types.Config{} + ts := translate.NewTranslationSet("yaml", "json") + var r report.Report + yamlPath := path.New("yaml", "grub", "users") + if len(c.Grub.Users) == 0 { + // No users + return rendered, ts, r + } + + // create boot filesystem + rendered.Storage.Filesystems = append(rendered.Storage.Filesystems, + types.Filesystem{ + Device: "/dev/disk/by-label/boot", + Format: util.StrToPtr("ext4"), + Path: util.StrToPtr("/boot"), + }) + + userCfgContent := []byte(buildGrubConfig(c.Grub)) + src, compression, err := baseutil.MakeDataURL(userCfgContent, nil, !options.NoResourceAutoCompression) + if err != nil { + r.AddOnError(yamlPath, err) + return rendered, ts, r + } + + // Create user.cfg file and add it to rendered config + rendered.Storage.Files = append(rendered.Storage.Files, + types.File{ + Node: types.Node{ + Path: "/boot/grub2/user.cfg", + }, + FileEmbedded1: types.FileEmbedded1{ + Append: []types.Resource{ + { + Source: util.StrToPtr(src), + Compression: compression, + }, + }, + }, + }) + + ts.AddFromCommonSource(yamlPath, path.New("json", "storage"), rendered.Storage) + return rendered, ts, r +} + +func buildGrubConfig(gb Grub) string { + // Process super users and corresponding passwords + allUsers := []string{} + cmds := []string{} + + for _, user := range gb.Users { + // We have already validated that user.Name and user.PasswordHash are non-empty + allUsers = append(allUsers, user.Name) + // Command for setting users password + cmds = append(cmds, fmt.Sprintf("password_pbkdf2 %s %s", user.Name, *user.PasswordHash)) + } + superUserCmd := fmt.Sprintf("set superusers=\"%s\"\n", strings.Join(allUsers, " ")) + return "# Generated by Butane\n\n" + superUserCmd + strings.Join(cmds, "\n") + "\n" +} diff --git a/mantle/vendor/github.com/coreos/butane/config/fcos/v1_5_exp/validate.go b/mantle/vendor/github.com/coreos/butane/config/fcos/v1_5_exp/validate.go index 97b2907aea..61cf290d4e 100644 --- a/mantle/vendor/github.com/coreos/butane/config/fcos/v1_5_exp/validate.go +++ b/mantle/vendor/github.com/coreos/butane/config/fcos/v1_5_exp/validate.go @@ -16,6 +16,7 @@ package v1_5_exp import ( "github.com/coreos/butane/config/common" + "github.com/coreos/ignition/v2/config/util" "github.com/coreos/vcontext/path" "github.com/coreos/vcontext/report" @@ -46,3 +47,14 @@ func (e Extension) Validate(c path.ContextPath) (r report.Report) { } return } + +func (user GrubUser) Validate(c path.ContextPath) (r report.Report) { + if user.Name == "" { + r.AddOnError(c.Append("name"), common.ErrGrubUserNameNotSpecified) + } + + if !util.NotEmpty(user.PasswordHash) { + r.AddOnError(c.Append("password_hash"), common.ErrGrubPasswordNotSpecified) + } + return +} diff --git a/mantle/vendor/github.com/coreos/butane/config/flatcar/v1_0/schema.go b/mantle/vendor/github.com/coreos/butane/config/flatcar/v1_0/schema.go new file mode 100644 index 0000000000..6a1d7366a9 --- /dev/null +++ b/mantle/vendor/github.com/coreos/butane/config/flatcar/v1_0/schema.go @@ -0,0 +1,23 @@ +// Copyright 2020 Red Hat, 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 v1_0 + +import ( + base "github.com/coreos/butane/base/v0_4" +) + +type Config struct { + base.Config `yaml:",inline"` +} diff --git a/mantle/vendor/github.com/coreos/butane/config/flatcar/v1_0/translate.go b/mantle/vendor/github.com/coreos/butane/config/flatcar/v1_0/translate.go new file mode 100644 index 0000000000..498c329f5c --- /dev/null +++ b/mantle/vendor/github.com/coreos/butane/config/flatcar/v1_0/translate.go @@ -0,0 +1,60 @@ +// Copyright 2020 Red Hat, 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 v1_0 + +import ( + "github.com/coreos/butane/config/common" + cutil "github.com/coreos/butane/config/util" + "github.com/coreos/butane/translate" + + "github.com/coreos/ignition/v2/config/v3_3/types" + "github.com/coreos/vcontext/path" + "github.com/coreos/vcontext/report" +) + +// ToIgn3_3Unvalidated translates the config to an Ignition config. It also +// returns the set of translations it did so paths in the resultant config +// can be tracked back to their source in the source config. No config +// validation is performed on input or output. +func (c Config) ToIgn3_3Unvalidated(options common.TranslateOptions) (types.Config, translate.TranslationSet, report.Report) { + ret, ts, r := c.Config.ToIgn3_3Unvalidated(options) + if r.IsFatal() { + return types.Config{}, translate.TranslationSet{}, r + } + + for i, luks := range ret.Storage.Luks { + if luks.Clevis.IsPresent() { + r.AddOnError(path.New("json", "storage", "luks", i, "clevis"), common.ErrClevisSupport) + } + } + + return ret, ts, r +} + +// ToIgn3_3 translates the config to an Ignition config. It returns a +// report of any errors or warnings in the source and resultant config. If +// the report has fatal errors or it encounters other problems translating, +// an error is returned. +func (c Config) ToIgn3_3(options common.TranslateOptions) (types.Config, report.Report, error) { + cfg, r, err := cutil.Translate(c, "ToIgn3_3Unvalidated", options) + return cfg.(types.Config), r, err +} + +// ToIgn3_3Bytes translates from a v1.4 Butane config to a v3.3.0 Ignition config. It returns a report of any errors or +// warnings in the source and resultant config. If the report has fatal errors or it encounters other problems +// translating, an error is returned. +func ToIgn3_3Bytes(input []byte, options common.TranslateBytesOptions) ([]byte, report.Report, error) { + return cutil.TranslateBytes(input, &Config{}, "ToIgn3_3", options) +} diff --git a/mantle/vendor/github.com/coreos/butane/config/flatcar/v1_1_exp/schema.go b/mantle/vendor/github.com/coreos/butane/config/flatcar/v1_1_exp/schema.go new file mode 100644 index 0000000000..72f1984fa9 --- /dev/null +++ b/mantle/vendor/github.com/coreos/butane/config/flatcar/v1_1_exp/schema.go @@ -0,0 +1,23 @@ +// Copyright 2020 Red Hat, 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 v1_1_exp + +import ( + base "github.com/coreos/butane/base/v0_5_exp" +) + +type Config struct { + base.Config `yaml:",inline"` +} diff --git a/mantle/vendor/github.com/coreos/butane/config/flatcar/v1_1_exp/translate.go b/mantle/vendor/github.com/coreos/butane/config/flatcar/v1_1_exp/translate.go new file mode 100644 index 0000000000..f1c48e9a6d --- /dev/null +++ b/mantle/vendor/github.com/coreos/butane/config/flatcar/v1_1_exp/translate.go @@ -0,0 +1,60 @@ +// Copyright 2020 Red Hat, 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 v1_1_exp + +import ( + "github.com/coreos/butane/config/common" + cutil "github.com/coreos/butane/config/util" + "github.com/coreos/butane/translate" + + "github.com/coreos/ignition/v2/config/v3_4_experimental/types" + "github.com/coreos/vcontext/path" + "github.com/coreos/vcontext/report" +) + +// ToIgn3_4Unvalidated translates the config to an Ignition config. It also +// returns the set of translations it did so paths in the resultant config +// can be tracked back to their source in the source config. No config +// validation is performed on input or output. +func (c Config) ToIgn3_4Unvalidated(options common.TranslateOptions) (types.Config, translate.TranslationSet, report.Report) { + ret, ts, r := c.Config.ToIgn3_4Unvalidated(options) + if r.IsFatal() { + return types.Config{}, translate.TranslationSet{}, r + } + + for i, luks := range ret.Storage.Luks { + if luks.Clevis.IsPresent() { + r.AddOnError(path.New("json", "storage", "luks", i, "clevis"), common.ErrClevisSupport) + } + } + + return ret, ts, r +} + +// ToIgn3_4 translates the config to an Ignition config. It returns a +// report of any errors or warnings in the source and resultant config. If +// the report has fatal errors or it encounters other problems translating, +// an error is returned. +func (c Config) ToIgn3_4(options common.TranslateOptions) (types.Config, report.Report, error) { + cfg, r, err := cutil.Translate(c, "ToIgn3_4Unvalidated", options) + return cfg.(types.Config), r, err +} + +// ToIgn3_4Bytes translates from a v1.4 Butane config to a v3.3.0 Ignition config. It returns a report of any errors or +// warnings in the source and resultant config. If the report has fatal errors or it encounters other problems +// translating, an error is returned. +func ToIgn3_4Bytes(input []byte, options common.TranslateBytesOptions) ([]byte, report.Report, error) { + return cutil.TranslateBytes(input, &Config{}, "ToIgn3_4", options) +} diff --git a/mantle/vendor/github.com/coreos/butane/config/openshift/v4_10/translate.go b/mantle/vendor/github.com/coreos/butane/config/openshift/v4_10/translate.go index dc55421255..722162cbae 100644 --- a/mantle/vendor/github.com/coreos/butane/config/openshift/v4_10/translate.go +++ b/mantle/vendor/github.com/coreos/butane/config/openshift/v4_10/translate.go @@ -200,6 +200,9 @@ func validateRHCOSSupport(mc result.MachineConfig, ts translate.TranslationSet) func validateMCOSupport(mc result.MachineConfig, ts translate.TranslationSet) report.Report { // Error classes for the purposes of this function: // + // UNPARSABLE - Cannot be rendered into a config by the MCC. If + // present in MC, MCC will mark the pool degraded. We reject these. + // // FORBIDDEN - Not supported by the MCD. If present in MC, MCD will // mark the node degraded. We reject these. // @@ -232,6 +235,10 @@ func validateMCOSupport(mc result.MachineConfig, ts translate.TranslationSet) re r.AddOnError(path.New("json", "spec", "config", "storage", "files", i, "contents", "source"), common.ErrFileSchemeSupport) } } + if file.Mode != nil && *file.Mode & ^0777 != 0 { + // UNPARSABLE + r.AddOnError(path.New("json", "spec", "config", "storage", "files", i, "mode"), common.ErrFileSpecialModeSupport) + } } for i := range mc.Spec.Config.Storage.Links { // IMMUTABLE diff --git a/mantle/vendor/github.com/coreos/butane/config/openshift/v4_11/result/schema.go b/mantle/vendor/github.com/coreos/butane/config/openshift/v4_11/result/schema.go new file mode 100644 index 0000000000..37e49f3028 --- /dev/null +++ b/mantle/vendor/github.com/coreos/butane/config/openshift/v4_11/result/schema.go @@ -0,0 +1,48 @@ +// Copyright 2021 Red Hat, 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 result + +import ( + "github.com/coreos/ignition/v2/config/v3_2/types" +) + +const ( + MC_API_VERSION = "machineconfiguration.openshift.io/v1" + MC_KIND = "MachineConfig" +) + +// We round-trip through JSON because Ignition uses `json` struct tags, +// so all struct tags need to be `json` even though we're ultimately +// writing YAML. + +type MachineConfig struct { + ApiVersion string `json:"apiVersion"` + Kind string `json:"kind"` + Metadata Metadata `json:"metadata"` + Spec Spec `json:"spec"` +} + +type Metadata struct { + Name string `json:"name"` + Labels map[string]string `json:"labels,omitempty"` +} + +type Spec struct { + Config types.Config `json:"config"` + KernelArguments []string `json:"kernelArguments,omitempty"` + Extensions []string `json:"extensions,omitempty"` + FIPS *bool `json:"fips,omitempty"` + KernelType *string `json:"kernelType,omitempty"` +} diff --git a/mantle/vendor/github.com/coreos/butane/config/openshift/v4_11/schema.go b/mantle/vendor/github.com/coreos/butane/config/openshift/v4_11/schema.go new file mode 100644 index 0000000000..eac0a311c4 --- /dev/null +++ b/mantle/vendor/github.com/coreos/butane/config/openshift/v4_11/schema.go @@ -0,0 +1,39 @@ +// Copyright 2020 Red Hat, 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 v4_11 + +import ( + fcos "github.com/coreos/butane/config/fcos/v1_3" +) + +const ROLE_LABEL_KEY = "machineconfiguration.openshift.io/role" + +type Config struct { + fcos.Config `yaml:",inline"` + Metadata Metadata `yaml:"metadata"` + OpenShift OpenShift `yaml:"openshift"` +} + +type Metadata struct { + Name string `yaml:"name"` + Labels map[string]string `yaml:"labels,omitempty"` +} + +type OpenShift struct { + KernelArguments []string `yaml:"kernel_arguments"` + Extensions []string `yaml:"extensions"` + FIPS *bool `yaml:"fips"` + KernelType *string `yaml:"kernel_type"` +} diff --git a/mantle/vendor/github.com/coreos/butane/config/openshift/v4_11_exp/translate.go b/mantle/vendor/github.com/coreos/butane/config/openshift/v4_11/translate.go similarity index 89% rename from mantle/vendor/github.com/coreos/butane/config/openshift/v4_11_exp/translate.go rename to mantle/vendor/github.com/coreos/butane/config/openshift/v4_11/translate.go index 261f11f212..b19ad93370 100644 --- a/mantle/vendor/github.com/coreos/butane/config/openshift/v4_11_exp/translate.go +++ b/mantle/vendor/github.com/coreos/butane/config/openshift/v4_11/translate.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License.) -package v4_11_exp +package v4_11 import ( "net/url" @@ -20,12 +20,12 @@ import ( "strings" "github.com/coreos/butane/config/common" - "github.com/coreos/butane/config/openshift/v4_11_exp/result" + "github.com/coreos/butane/config/openshift/v4_11/result" cutil "github.com/coreos/butane/config/util" "github.com/coreos/butane/translate" "github.com/coreos/ignition/v2/config/util" - "github.com/coreos/ignition/v2/config/v3_4_experimental/types" + "github.com/coreos/ignition/v2/config/v3_2/types" "github.com/coreos/vcontext/path" "github.com/coreos/vcontext/report" ) @@ -42,7 +42,7 @@ const ( // can be tracked back to their source in the source config. No config // validation is performed on input or output. func (c Config) ToMachineConfig4_11Unvalidated(options common.TranslateOptions) (result.MachineConfig, translate.TranslationSet, report.Report) { - cfg, ts, r := c.Config.ToIgn3_4Unvalidated(options) + cfg, ts, r := c.Config.ToIgn3_2Unvalidated(options) if r.IsFatal() { return result.MachineConfig{}, ts, r } @@ -102,11 +102,11 @@ func (c Config) ToMachineConfig4_11(options common.TranslateOptions) (result.Mac return cfg.(result.MachineConfig), r, err } -// ToIgn3_4Unvalidated translates the config to an Ignition config. It also +// ToIgn3_2Unvalidated translates the config to an Ignition config. It also // returns the set of translations it did so paths in the resultant config // can be tracked back to their source in the source config. No config // validation is performed on input or output. -func (c Config) ToIgn3_4Unvalidated(options common.TranslateOptions) (types.Config, translate.TranslationSet, report.Report) { +func (c Config) ToIgn3_2Unvalidated(options common.TranslateOptions) (types.Config, translate.TranslationSet, report.Report) { mc, ts, r := c.ToMachineConfig4_11Unvalidated(options) cfg := mc.Spec.Config @@ -121,12 +121,12 @@ func (c Config) ToIgn3_4Unvalidated(options common.TranslateOptions) (types.Conf return cfg, ts, r } -// ToIgn3_4 translates the config to an Ignition config. It returns a +// ToIgn3_2 translates the config to an Ignition config. It returns a // report of any errors or warnings in the source and resultant config. If // the report has fatal errors or it encounters other problems translating, // an error is returned. -func (c Config) ToIgn3_4(options common.TranslateOptions) (types.Config, report.Report, error) { - cfg, r, err := cutil.Translate(c, "ToIgn3_4Unvalidated", options) +func (c Config) ToIgn3_2(options common.TranslateOptions) (types.Config, report.Report, error) { + cfg, r, err := cutil.Translate(c, "ToIgn3_2Unvalidated", options) return cfg.(types.Config), r, err } @@ -135,7 +135,7 @@ func (c Config) ToIgn3_4(options common.TranslateOptions) (types.Config, report. // translating, an error is returned. func ToConfigBytes(input []byte, options common.TranslateBytesOptions) ([]byte, report.Report, error) { if options.Raw { - return cutil.TranslateBytes(input, &Config{}, "ToIgn3_4", options) + return cutil.TranslateBytes(input, &Config{}, "ToIgn3_2", options) } else { return cutil.TranslateBytesYAML(input, &Config{}, "ToMachineConfig4_11", options) } @@ -206,10 +206,6 @@ func validateMCOSupport(mc result.MachineConfig, ts translate.TranslationSet) re // FORBIDDEN - Not supported by the MCD. If present in MC, MCD will // mark the node degraded. We reject these. // - // REDUNDANT - Feature is also provided by a MachineConfig-specific - // field with different semantics. To reduce confusion, disable - // this implementation. - // // IMMUTABLE - Permitted in MC, passed through to Ignition, but not // supported by the MCD. MCD will mark the node degraded if the // field changes after the node is provisioned. We reject these @@ -222,12 +218,6 @@ func validateMCOSupport(mc result.MachineConfig, ts translate.TranslationSet) re // supported fields. We reject these. var r report.Report - for i, fs := range mc.Spec.Config.Storage.Filesystems { - if fs.Format != nil && *fs.Format == "none" { - // UNPARSABLE - r.AddOnError(path.New("json", "spec", "config", "storage", "filesystems", i, "format"), common.ErrFilesystemNoneSupport) - } - } for i := range mc.Spec.Config.Storage.Directories { // IMMUTABLE r.AddOnError(path.New("json", "spec", "config", "storage", "directories", i), common.ErrDirectorySupport) @@ -245,6 +235,10 @@ func validateMCOSupport(mc result.MachineConfig, ts translate.TranslationSet) re r.AddOnError(path.New("json", "spec", "config", "storage", "files", i, "contents", "source"), common.ErrFileSchemeSupport) } } + if file.Mode != nil && *file.Mode & ^0777 != 0 { + // UNPARSABLE + r.AddOnError(path.New("json", "spec", "config", "storage", "files", i, "mode"), common.ErrFileSpecialModeSupport) + } } for i := range mc.Spec.Config.Storage.Links { // IMMUTABLE @@ -281,13 +275,5 @@ func validateMCOSupport(mc result.MachineConfig, ts translate.TranslationSet) re r.AddOnError(path.New("json", "spec", "config", "passwd", "users", i), common.ErrUserNameSupport) } } - for i := range mc.Spec.Config.KernelArguments.ShouldExist { - // UNPARSABLE, REDUNDANT - r.AddOnError(path.New("json", "spec", "config", "kernelArguments", "shouldExist", i), common.ErrKernelArgumentSupport) - } - for i := range mc.Spec.Config.KernelArguments.ShouldNotExist { - // UNPARSABLE, REDUNDANT - r.AddOnError(path.New("json", "spec", "config", "kernelArguments", "shouldNotExist", i), common.ErrKernelArgumentSupport) - } return cutil.TranslateReportPaths(r, ts) } diff --git a/mantle/vendor/github.com/coreos/butane/config/openshift/v4_11_exp/validate.go b/mantle/vendor/github.com/coreos/butane/config/openshift/v4_11/validate.go similarity index 98% rename from mantle/vendor/github.com/coreos/butane/config/openshift/v4_11_exp/validate.go rename to mantle/vendor/github.com/coreos/butane/config/openshift/v4_11/validate.go index 1f551c9e48..dd827c2cda 100644 --- a/mantle/vendor/github.com/coreos/butane/config/openshift/v4_11_exp/validate.go +++ b/mantle/vendor/github.com/coreos/butane/config/openshift/v4_11/validate.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License.) -package v4_11_exp +package v4_11 import ( "github.com/coreos/butane/config/common" diff --git a/mantle/vendor/github.com/coreos/butane/config/openshift/v4_12/result/schema.go b/mantle/vendor/github.com/coreos/butane/config/openshift/v4_12/result/schema.go new file mode 100644 index 0000000000..37e49f3028 --- /dev/null +++ b/mantle/vendor/github.com/coreos/butane/config/openshift/v4_12/result/schema.go @@ -0,0 +1,48 @@ +// Copyright 2021 Red Hat, 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 result + +import ( + "github.com/coreos/ignition/v2/config/v3_2/types" +) + +const ( + MC_API_VERSION = "machineconfiguration.openshift.io/v1" + MC_KIND = "MachineConfig" +) + +// We round-trip through JSON because Ignition uses `json` struct tags, +// so all struct tags need to be `json` even though we're ultimately +// writing YAML. + +type MachineConfig struct { + ApiVersion string `json:"apiVersion"` + Kind string `json:"kind"` + Metadata Metadata `json:"metadata"` + Spec Spec `json:"spec"` +} + +type Metadata struct { + Name string `json:"name"` + Labels map[string]string `json:"labels,omitempty"` +} + +type Spec struct { + Config types.Config `json:"config"` + KernelArguments []string `json:"kernelArguments,omitempty"` + Extensions []string `json:"extensions,omitempty"` + FIPS *bool `json:"fips,omitempty"` + KernelType *string `json:"kernelType,omitempty"` +} diff --git a/mantle/vendor/github.com/coreos/butane/config/openshift/v4_12/schema.go b/mantle/vendor/github.com/coreos/butane/config/openshift/v4_12/schema.go new file mode 100644 index 0000000000..e143b54709 --- /dev/null +++ b/mantle/vendor/github.com/coreos/butane/config/openshift/v4_12/schema.go @@ -0,0 +1,39 @@ +// Copyright 2020 Red Hat, 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 v4_12 + +import ( + fcos "github.com/coreos/butane/config/fcos/v1_3" +) + +const ROLE_LABEL_KEY = "machineconfiguration.openshift.io/role" + +type Config struct { + fcos.Config `yaml:",inline"` + Metadata Metadata `yaml:"metadata"` + OpenShift OpenShift `yaml:"openshift"` +} + +type Metadata struct { + Name string `yaml:"name"` + Labels map[string]string `yaml:"labels,omitempty"` +} + +type OpenShift struct { + KernelArguments []string `yaml:"kernel_arguments"` + Extensions []string `yaml:"extensions"` + FIPS *bool `yaml:"fips"` + KernelType *string `yaml:"kernel_type"` +} diff --git a/mantle/vendor/github.com/coreos/butane/config/openshift/v4_12/translate.go b/mantle/vendor/github.com/coreos/butane/config/openshift/v4_12/translate.go new file mode 100644 index 0000000000..4cb433fa77 --- /dev/null +++ b/mantle/vendor/github.com/coreos/butane/config/openshift/v4_12/translate.go @@ -0,0 +1,279 @@ +// Copyright 2020 Red Hat, 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 v4_12 + +import ( + "net/url" + "reflect" + "strings" + + "github.com/coreos/butane/config/common" + "github.com/coreos/butane/config/openshift/v4_12/result" + cutil "github.com/coreos/butane/config/util" + "github.com/coreos/butane/translate" + + "github.com/coreos/ignition/v2/config/util" + "github.com/coreos/ignition/v2/config/v3_2/types" + "github.com/coreos/vcontext/path" + "github.com/coreos/vcontext/report" +) + +const ( + // FIPS 140-2 doesn't allow the default XTS mode + fipsCipherOption = types.LuksOption("--cipher") + fipsCipherShortOption = types.LuksOption("-c") + fipsCipherArgument = types.LuksOption("aes-cbc-essiv:sha256") +) + +// ToMachineConfig4_12Unvalidated translates the config to a MachineConfig. It also +// returns the set of translations it did so paths in the resultant config +// can be tracked back to their source in the source config. No config +// validation is performed on input or output. +func (c Config) ToMachineConfig4_12Unvalidated(options common.TranslateOptions) (result.MachineConfig, translate.TranslationSet, report.Report) { + cfg, ts, r := c.Config.ToIgn3_2Unvalidated(options) + if r.IsFatal() { + return result.MachineConfig{}, ts, r + } + + // wrap + ts = ts.PrefixPaths(path.New("yaml"), path.New("json", "spec", "config")) + mc := result.MachineConfig{ + ApiVersion: result.MC_API_VERSION, + Kind: result.MC_KIND, + Metadata: result.Metadata{ + Name: c.Metadata.Name, + Labels: make(map[string]string), + }, + Spec: result.Spec{ + Config: cfg, + }, + } + ts.AddTranslation(path.New("yaml", "version"), path.New("json", "apiVersion")) + ts.AddTranslation(path.New("yaml", "version"), path.New("json", "kind")) + ts.AddTranslation(path.New("yaml", "metadata"), path.New("json", "metadata")) + ts.AddTranslation(path.New("yaml", "metadata", "name"), path.New("json", "metadata", "name")) + ts.AddTranslation(path.New("yaml", "metadata", "labels"), path.New("json", "metadata", "labels")) + ts.AddTranslation(path.New("yaml", "version"), path.New("json", "spec")) + ts.AddTranslation(path.New("yaml"), path.New("json", "spec", "config")) + for k, v := range c.Metadata.Labels { + mc.Metadata.Labels[k] = v + ts.AddTranslation(path.New("yaml", "metadata", "labels", k), path.New("json", "metadata", "labels", k)) + } + + // translate OpenShift fields + tr := translate.NewTranslator("yaml", "json", options) + from := &c.OpenShift + to := &mc.Spec + ts2, r2 := translate.Prefixed(tr, "extensions", &from.Extensions, &to.Extensions) + translate.MergeP(tr, ts2, &r2, "fips", &from.FIPS, &to.FIPS) + translate.MergeP2(tr, ts2, &r2, "kernel_arguments", &from.KernelArguments, "kernelArguments", &to.KernelArguments) + translate.MergeP2(tr, ts2, &r2, "kernel_type", &from.KernelType, "kernelType", &to.KernelType) + ts.MergeP2("openshift", "spec", ts2) + r.Merge(r2) + + // apply FIPS options to LUKS volumes + ts.Merge(addLuksFipsOptions(&mc)) + + // finally, check the fully desugared config for RHCOS and MCO support + r.Merge(validateRHCOSSupport(mc, ts)) + r.Merge(validateMCOSupport(mc, ts)) + + return mc, ts, r +} + +// ToMachineConfig4_12 translates the config to a MachineConfig. It returns a +// report of any errors or warnings in the source and resultant config. If +// the report has fatal errors or it encounters other problems translating, +// an error is returned. +func (c Config) ToMachineConfig4_12(options common.TranslateOptions) (result.MachineConfig, report.Report, error) { + cfg, r, err := cutil.Translate(c, "ToMachineConfig4_12Unvalidated", options) + return cfg.(result.MachineConfig), r, err +} + +// ToIgn3_2Unvalidated translates the config to an Ignition config. It also +// returns the set of translations it did so paths in the resultant config +// can be tracked back to their source in the source config. No config +// validation is performed on input or output. +func (c Config) ToIgn3_2Unvalidated(options common.TranslateOptions) (types.Config, translate.TranslationSet, report.Report) { + mc, ts, r := c.ToMachineConfig4_12Unvalidated(options) + cfg := mc.Spec.Config + + // report warnings if there are any non-empty fields in Spec (other + // than the Ignition config itself) that we're ignoring + mc.Spec.Config = types.Config{} + warnings := translate.PrefixReport(cutil.CheckForElidedFields(mc.Spec), "spec") + // translate from json space into yaml space + r.Merge(cutil.TranslateReportPaths(warnings, ts)) + + ts = ts.Descend(path.New("json", "spec", "config")) + return cfg, ts, r +} + +// ToIgn3_2 translates the config to an Ignition config. It returns a +// report of any errors or warnings in the source and resultant config. If +// the report has fatal errors or it encounters other problems translating, +// an error is returned. +func (c Config) ToIgn3_2(options common.TranslateOptions) (types.Config, report.Report, error) { + cfg, r, err := cutil.Translate(c, "ToIgn3_2Unvalidated", options) + return cfg.(types.Config), r, err +} + +// ToConfigBytes translates from a v4.12 Butane config to a v4.12 MachineConfig or a v3.2.0 Ignition config. It returns a report of any errors or +// warnings in the source and resultant config. If the report has fatal errors or it encounters other problems +// translating, an error is returned. +func ToConfigBytes(input []byte, options common.TranslateBytesOptions) ([]byte, report.Report, error) { + if options.Raw { + return cutil.TranslateBytes(input, &Config{}, "ToIgn3_2", options) + } else { + return cutil.TranslateBytesYAML(input, &Config{}, "ToMachineConfig4_12", options) + } +} + +func addLuksFipsOptions(mc *result.MachineConfig) translate.TranslationSet { + ts := translate.NewTranslationSet("yaml", "json") + if !util.IsTrue(mc.Spec.FIPS) { + return ts + } + +OUTER: + for i := range mc.Spec.Config.Storage.Luks { + luks := &mc.Spec.Config.Storage.Luks[i] + // Only add options if the user hasn't already specified + // a cipher option. Do this in-place, since config merging + // doesn't support conditional logic. + for _, option := range luks.Options { + if option == fipsCipherOption || + strings.HasPrefix(string(option), string(fipsCipherOption)+"=") || + option == fipsCipherShortOption { + continue OUTER + } + } + for j := 0; j < 2; j++ { + ts.AddTranslation(path.New("yaml", "openshift", "fips"), path.New("json", "spec", "config", "storage", "luks", i, "options", len(luks.Options)+j)) + } + if len(luks.Options) == 0 { + ts.AddTranslation(path.New("yaml", "openshift", "fips"), path.New("json", "spec", "config", "storage", "luks", i, "options")) + } + luks.Options = append(luks.Options, fipsCipherOption, fipsCipherArgument) + } + return ts +} + +// Error on fields that are rejected by RHCOS. +// +// Some of these fields may have been generated by sugar (e.g. +// boot_device.luks), so we work in JSON (output) space and then translate +// paths back to YAML (input) space. That's also the reason we do these +// checks after translation, rather than during validation. +func validateRHCOSSupport(mc result.MachineConfig, ts translate.TranslationSet) report.Report { + var r report.Report + for i, fs := range mc.Spec.Config.Storage.Filesystems { + if fs.Format != nil && *fs.Format == "btrfs" { + // we don't ship mkfs.btrfs + r.AddOnError(path.New("json", "spec", "config", "storage", "filesystems", i, "format"), common.ErrBtrfsSupport) + } + } + return cutil.TranslateReportPaths(r, ts) +} + +// Error on fields that are rejected outright by the MCO, or that are +// unsupported by the MCO and we want to discourage. +// +// https://github.com/openshift/machine-config-operator/blob/d6dabadeca05/MachineConfigDaemon.md#supported-vs-unsupported-ignition-config-changes +// +// Some of these fields may have been generated by sugar (e.g. storage.trees), +// so we work in JSON (output) space and then translate paths back to YAML +// (input) space. That's also the reason we do these checks after +// translation, rather than during validation. +func validateMCOSupport(mc result.MachineConfig, ts translate.TranslationSet) report.Report { + // Error classes for the purposes of this function: + // + // UNPARSABLE - Cannot be rendered into a config by the MCC. If + // present in MC, MCC will mark the pool degraded. We reject these. + // + // FORBIDDEN - Not supported by the MCD. If present in MC, MCD will + // mark the node degraded. We reject these. + // + // IMMUTABLE - Permitted in MC, passed through to Ignition, but not + // supported by the MCD. MCD will mark the node degraded if the + // field changes after the node is provisioned. We reject these + // outright to discourage their use. + // + // TRIPWIRE - A subset of fields in the containing struct are + // supported by the MCD. If the struct contents change after the node + // is provisioned, and the struct contains unsupported fields, MCD + // will mark the node degraded, even if the change only affects + // supported fields. We reject these. + + var r report.Report + for i := range mc.Spec.Config.Storage.Directories { + // IMMUTABLE + r.AddOnError(path.New("json", "spec", "config", "storage", "directories", i), common.ErrDirectorySupport) + } + for i, file := range mc.Spec.Config.Storage.Files { + if len(file.Append) > 0 { + // FORBIDDEN + r.AddOnError(path.New("json", "spec", "config", "storage", "files", i, "append"), common.ErrFileAppendSupport) + } + if file.Contents.Source != nil { + fileSource, err := url.Parse(*file.Contents.Source) + // parse errors will be caught by normal config validation + if err == nil && fileSource.Scheme != "data" { + // FORBIDDEN + r.AddOnError(path.New("json", "spec", "config", "storage", "files", i, "contents", "source"), common.ErrFileSchemeSupport) + } + } + if file.Mode != nil && *file.Mode & ^0777 != 0 { + // UNPARSABLE + r.AddOnError(path.New("json", "spec", "config", "storage", "files", i, "mode"), common.ErrFileSpecialModeSupport) + } + } + for i := range mc.Spec.Config.Storage.Links { + // IMMUTABLE + // If you change this to be less restrictive without adding + // link support in the MCO, consider what should happen if + // the user specifies a storage.tree that includes symlinks. + r.AddOnError(path.New("json", "spec", "config", "storage", "links", i), common.ErrLinkSupport) + } + for i := range mc.Spec.Config.Passwd.Groups { + // IMMUTABLE + r.AddOnError(path.New("json", "spec", "config", "passwd", "groups", i), common.ErrGroupSupport) + } + for i, user := range mc.Spec.Config.Passwd.Users { + if user.Name == "core" { + // SSHAuthorizedKeys is managed; other fields are not + v := reflect.ValueOf(user) + t := v.Type() + for j := 0; j < v.NumField(); j++ { + fv := v.Field(j) + ft := t.Field(j) + switch ft.Name { + case "Name", "SSHAuthorizedKeys": + continue + default: + if fv.IsValid() && !fv.IsZero() { + tag := strings.Split(ft.Tag.Get("json"), ",")[0] + // TRIPWIRE + r.AddOnError(path.New("json", "spec", "config", "passwd", "users", i, tag), common.ErrUserFieldSupport) + } + } + } + } else { + // TRIPWIRE + r.AddOnError(path.New("json", "spec", "config", "passwd", "users", i), common.ErrUserNameSupport) + } + } + return cutil.TranslateReportPaths(r, ts) +} diff --git a/mantle/vendor/github.com/coreos/butane/config/openshift/v4_12/validate.go b/mantle/vendor/github.com/coreos/butane/config/openshift/v4_12/validate.go new file mode 100644 index 0000000000..ff1403cb4a --- /dev/null +++ b/mantle/vendor/github.com/coreos/butane/config/openshift/v4_12/validate.go @@ -0,0 +1,43 @@ +// Copyright 2021 Red Hat, 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 v4_12 + +import ( + "github.com/coreos/butane/config/common" + + "github.com/coreos/vcontext/path" + "github.com/coreos/vcontext/report" +) + +func (m Metadata) Validate(c path.ContextPath) (r report.Report) { + if m.Name == "" { + r.AddOnError(c.Append("name"), common.ErrNameRequired) + } + if m.Labels[ROLE_LABEL_KEY] == "" { + r.AddOnError(c.Append("labels", ROLE_LABEL_KEY), common.ErrRoleRequired) + } + return +} + +func (os OpenShift) Validate(c path.ContextPath) (r report.Report) { + if os.KernelType != nil { + switch *os.KernelType { + case "", "default", "realtime": + default: + r.AddOnError(c.Append("kernel_type"), common.ErrInvalidKernelType) + } + } + return +} diff --git a/mantle/vendor/github.com/coreos/butane/config/openshift/v4_11_exp/result/schema.go b/mantle/vendor/github.com/coreos/butane/config/openshift/v4_13_exp/result/schema.go similarity index 100% rename from mantle/vendor/github.com/coreos/butane/config/openshift/v4_11_exp/result/schema.go rename to mantle/vendor/github.com/coreos/butane/config/openshift/v4_13_exp/result/schema.go diff --git a/mantle/vendor/github.com/coreos/butane/config/openshift/v4_11_exp/schema.go b/mantle/vendor/github.com/coreos/butane/config/openshift/v4_13_exp/schema.go similarity index 98% rename from mantle/vendor/github.com/coreos/butane/config/openshift/v4_11_exp/schema.go rename to mantle/vendor/github.com/coreos/butane/config/openshift/v4_13_exp/schema.go index 60a551fa6e..ab204d39dd 100644 --- a/mantle/vendor/github.com/coreos/butane/config/openshift/v4_11_exp/schema.go +++ b/mantle/vendor/github.com/coreos/butane/config/openshift/v4_13_exp/schema.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License.) -package v4_11_exp +package v4_13_exp import ( fcos "github.com/coreos/butane/config/fcos/v1_5_exp" diff --git a/mantle/vendor/github.com/coreos/butane/config/openshift/v4_13_exp/translate.go b/mantle/vendor/github.com/coreos/butane/config/openshift/v4_13_exp/translate.go new file mode 100644 index 0000000000..d4840fc1ee --- /dev/null +++ b/mantle/vendor/github.com/coreos/butane/config/openshift/v4_13_exp/translate.go @@ -0,0 +1,321 @@ +// Copyright 2020 Red Hat, 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 v4_13_exp + +import ( + "net/url" + "reflect" + "strings" + + "github.com/coreos/butane/config/common" + "github.com/coreos/butane/config/openshift/v4_13_exp/result" + cutil "github.com/coreos/butane/config/util" + "github.com/coreos/butane/translate" + + "github.com/coreos/ignition/v2/config/util" + "github.com/coreos/ignition/v2/config/v3_4_experimental/types" + "github.com/coreos/vcontext/path" + "github.com/coreos/vcontext/report" +) + +const ( + // FIPS 140-2 doesn't allow the default XTS mode + fipsCipherOption = types.LuksOption("--cipher") + fipsCipherShortOption = types.LuksOption("-c") + fipsCipherArgument = types.LuksOption("aes-cbc-essiv:sha256") +) + +// ToMachineConfig4_13Unvalidated translates the config to a MachineConfig. It also +// returns the set of translations it did so paths in the resultant config +// can be tracked back to their source in the source config. No config +// validation is performed on input or output. +func (c Config) ToMachineConfig4_13Unvalidated(options common.TranslateOptions) (result.MachineConfig, translate.TranslationSet, report.Report) { + cfg, ts, r := c.Config.ToIgn3_4Unvalidated(options) + if r.IsFatal() { + return result.MachineConfig{}, ts, r + } + ts = translateUserGrubCfg(&cfg, &ts) + + // wrap + ts = ts.PrefixPaths(path.New("yaml"), path.New("json", "spec", "config")) + mc := result.MachineConfig{ + ApiVersion: result.MC_API_VERSION, + Kind: result.MC_KIND, + Metadata: result.Metadata{ + Name: c.Metadata.Name, + Labels: make(map[string]string), + }, + Spec: result.Spec{ + Config: cfg, + }, + } + ts.AddTranslation(path.New("yaml", "version"), path.New("json", "apiVersion")) + ts.AddTranslation(path.New("yaml", "version"), path.New("json", "kind")) + ts.AddTranslation(path.New("yaml", "metadata"), path.New("json", "metadata")) + ts.AddTranslation(path.New("yaml", "metadata", "name"), path.New("json", "metadata", "name")) + ts.AddTranslation(path.New("yaml", "metadata", "labels"), path.New("json", "metadata", "labels")) + ts.AddTranslation(path.New("yaml", "version"), path.New("json", "spec")) + ts.AddTranslation(path.New("yaml"), path.New("json", "spec", "config")) + for k, v := range c.Metadata.Labels { + mc.Metadata.Labels[k] = v + ts.AddTranslation(path.New("yaml", "metadata", "labels", k), path.New("json", "metadata", "labels", k)) + } + + // translate OpenShift fields + tr := translate.NewTranslator("yaml", "json", options) + from := &c.OpenShift + to := &mc.Spec + ts2, r2 := translate.Prefixed(tr, "extensions", &from.Extensions, &to.Extensions) + translate.MergeP(tr, ts2, &r2, "fips", &from.FIPS, &to.FIPS) + translate.MergeP2(tr, ts2, &r2, "kernel_arguments", &from.KernelArguments, "kernelArguments", &to.KernelArguments) + translate.MergeP2(tr, ts2, &r2, "kernel_type", &from.KernelType, "kernelType", &to.KernelType) + ts.MergeP2("openshift", "spec", ts2) + r.Merge(r2) + + // apply FIPS options to LUKS volumes + ts.Merge(addLuksFipsOptions(&mc)) + + // finally, check the fully desugared config for RHCOS and MCO support + r.Merge(validateRHCOSSupport(mc, ts)) + r.Merge(validateMCOSupport(mc, ts)) + + return mc, ts, r +} + +// ToMachineConfig4_13 translates the config to a MachineConfig. It returns a +// report of any errors or warnings in the source and resultant config. If +// the report has fatal errors or it encounters other problems translating, +// an error is returned. +func (c Config) ToMachineConfig4_13(options common.TranslateOptions) (result.MachineConfig, report.Report, error) { + cfg, r, err := cutil.Translate(c, "ToMachineConfig4_13Unvalidated", options) + return cfg.(result.MachineConfig), r, err +} + +// ToIgn3_4Unvalidated translates the config to an Ignition config. It also +// returns the set of translations it did so paths in the resultant config +// can be tracked back to their source in the source config. No config +// validation is performed on input or output. +func (c Config) ToIgn3_4Unvalidated(options common.TranslateOptions) (types.Config, translate.TranslationSet, report.Report) { + mc, ts, r := c.ToMachineConfig4_13Unvalidated(options) + cfg := mc.Spec.Config + + // report warnings if there are any non-empty fields in Spec (other + // than the Ignition config itself) that we're ignoring + mc.Spec.Config = types.Config{} + warnings := translate.PrefixReport(cutil.CheckForElidedFields(mc.Spec), "spec") + // translate from json space into yaml space + r.Merge(cutil.TranslateReportPaths(warnings, ts)) + + ts = ts.Descend(path.New("json", "spec", "config")) + return cfg, ts, r +} + +// ToIgn3_4 translates the config to an Ignition config. It returns a +// report of any errors or warnings in the source and resultant config. If +// the report has fatal errors or it encounters other problems translating, +// an error is returned. +func (c Config) ToIgn3_4(options common.TranslateOptions) (types.Config, report.Report, error) { + cfg, r, err := cutil.Translate(c, "ToIgn3_4Unvalidated", options) + return cfg.(types.Config), r, err +} + +// ToConfigBytes translates from a v4.13 Butane config to a v4.13 MachineConfig or a v3.4.0 Ignition config. It returns a report of any errors or +// warnings in the source and resultant config. If the report has fatal errors or it encounters other problems +// translating, an error is returned. +func ToConfigBytes(input []byte, options common.TranslateBytesOptions) ([]byte, report.Report, error) { + if options.Raw { + return cutil.TranslateBytes(input, &Config{}, "ToIgn3_4", options) + } else { + return cutil.TranslateBytesYAML(input, &Config{}, "ToMachineConfig4_13", options) + } +} + +func addLuksFipsOptions(mc *result.MachineConfig) translate.TranslationSet { + ts := translate.NewTranslationSet("yaml", "json") + if !util.IsTrue(mc.Spec.FIPS) { + return ts + } + +OUTER: + for i := range mc.Spec.Config.Storage.Luks { + luks := &mc.Spec.Config.Storage.Luks[i] + // Only add options if the user hasn't already specified + // a cipher option. Do this in-place, since config merging + // doesn't support conditional logic. + for _, option := range luks.Options { + if option == fipsCipherOption || + strings.HasPrefix(string(option), string(fipsCipherOption)+"=") || + option == fipsCipherShortOption { + continue OUTER + } + } + for j := 0; j < 2; j++ { + ts.AddTranslation(path.New("yaml", "openshift", "fips"), path.New("json", "spec", "config", "storage", "luks", i, "options", len(luks.Options)+j)) + } + if len(luks.Options) == 0 { + ts.AddTranslation(path.New("yaml", "openshift", "fips"), path.New("json", "spec", "config", "storage", "luks", i, "options")) + } + luks.Options = append(luks.Options, fipsCipherOption, fipsCipherArgument) + } + return ts +} + +// Error on fields that are rejected by RHCOS. +// +// Some of these fields may have been generated by sugar (e.g. +// boot_device.luks), so we work in JSON (output) space and then translate +// paths back to YAML (input) space. That's also the reason we do these +// checks after translation, rather than during validation. +func validateRHCOSSupport(mc result.MachineConfig, ts translate.TranslationSet) report.Report { + var r report.Report + for i, fs := range mc.Spec.Config.Storage.Filesystems { + if fs.Format != nil && *fs.Format == "btrfs" { + // we don't ship mkfs.btrfs + r.AddOnError(path.New("json", "spec", "config", "storage", "filesystems", i, "format"), common.ErrBtrfsSupport) + } + } + return cutil.TranslateReportPaths(r, ts) +} + +// Error on fields that are rejected outright by the MCO, or that are +// unsupported by the MCO and we want to discourage. +// +// https://github.com/openshift/machine-config-operator/blob/d6dabadeca05/MachineConfigDaemon.md#supported-vs-unsupported-ignition-config-changes +// +// Some of these fields may have been generated by sugar (e.g. storage.trees), +// so we work in JSON (output) space and then translate paths back to YAML +// (input) space. That's also the reason we do these checks after +// translation, rather than during validation. +func validateMCOSupport(mc result.MachineConfig, ts translate.TranslationSet) report.Report { + // Error classes for the purposes of this function: + // + // UNPARSABLE - Cannot be rendered into a config by the MCC. If + // present in MC, MCC will mark the pool degraded. We reject these. + // + // FORBIDDEN - Not supported by the MCD. If present in MC, MCD will + // mark the node degraded. We reject these. + // + // REDUNDANT - Feature is also provided by a MachineConfig-specific + // field with different semantics. To reduce confusion, disable + // this implementation. + // + // IMMUTABLE - Permitted in MC, passed through to Ignition, but not + // supported by the MCD. MCD will mark the node degraded if the + // field changes after the node is provisioned. We reject these + // outright to discourage their use. + // + // TRIPWIRE - A subset of fields in the containing struct are + // supported by the MCD. If the struct contents change after the node + // is provisioned, and the struct contains unsupported fields, MCD + // will mark the node degraded, even if the change only affects + // supported fields. We reject these. + + var r report.Report + for i, fs := range mc.Spec.Config.Storage.Filesystems { + if fs.Format != nil && *fs.Format == "none" { + // UNPARSABLE + r.AddOnError(path.New("json", "spec", "config", "storage", "filesystems", i, "format"), common.ErrFilesystemNoneSupport) + } + } + for i := range mc.Spec.Config.Storage.Directories { + // IMMUTABLE + r.AddOnError(path.New("json", "spec", "config", "storage", "directories", i), common.ErrDirectorySupport) + } + for i, file := range mc.Spec.Config.Storage.Files { + if len(file.Append) > 0 { + // FORBIDDEN + r.AddOnError(path.New("json", "spec", "config", "storage", "files", i, "append"), common.ErrFileAppendSupport) + } + if file.Contents.Source != nil { + fileSource, err := url.Parse(*file.Contents.Source) + // parse errors will be caught by normal config validation + if err == nil && fileSource.Scheme != "data" { + // FORBIDDEN + r.AddOnError(path.New("json", "spec", "config", "storage", "files", i, "contents", "source"), common.ErrFileSchemeSupport) + } + } + if file.Mode != nil && *file.Mode & ^0777 != 0 { + // UNPARSABLE + r.AddOnError(path.New("json", "spec", "config", "storage", "files", i, "mode"), common.ErrFileSpecialModeSupport) + } + } + for i := range mc.Spec.Config.Storage.Links { + // IMMUTABLE + // If you change this to be less restrictive without adding + // link support in the MCO, consider what should happen if + // the user specifies a storage.tree that includes symlinks. + r.AddOnError(path.New("json", "spec", "config", "storage", "links", i), common.ErrLinkSupport) + } + for i := range mc.Spec.Config.Passwd.Groups { + // IMMUTABLE + r.AddOnError(path.New("json", "spec", "config", "passwd", "groups", i), common.ErrGroupSupport) + } + for i, user := range mc.Spec.Config.Passwd.Users { + if user.Name == "core" { + // SSHAuthorizedKeys is managed; other fields are not + v := reflect.ValueOf(user) + t := v.Type() + for j := 0; j < v.NumField(); j++ { + fv := v.Field(j) + ft := t.Field(j) + switch ft.Name { + case "Name", "SSHAuthorizedKeys": + continue + default: + if fv.IsValid() && !fv.IsZero() { + tag := strings.Split(ft.Tag.Get("json"), ",")[0] + // TRIPWIRE + r.AddOnError(path.New("json", "spec", "config", "passwd", "users", i, tag), common.ErrUserFieldSupport) + } + } + } + } else { + // TRIPWIRE + r.AddOnError(path.New("json", "spec", "config", "passwd", "users", i), common.ErrUserNameSupport) + } + } + for i := range mc.Spec.Config.KernelArguments.ShouldExist { + // UNPARSABLE, REDUNDANT + r.AddOnError(path.New("json", "spec", "config", "kernelArguments", "shouldExist", i), common.ErrKernelArgumentSupport) + } + for i := range mc.Spec.Config.KernelArguments.ShouldNotExist { + // UNPARSABLE, REDUNDANT + r.AddOnError(path.New("json", "spec", "config", "kernelArguments", "shouldNotExist", i), common.ErrKernelArgumentSupport) + } + return cutil.TranslateReportPaths(r, ts) +} + +// fcos config generates a user.cfg file using append; however, OpenShift config +// does not support append (since MCO does not support it). Let change the file to use contents +func translateUserGrubCfg(config *types.Config, ts *translate.TranslationSet) translate.TranslationSet { + newMappings := translate.NewTranslationSet("json", "json") + for i, file := range config.Storage.Files { + if file.Path == "/boot/grub2/user.cfg" { + if len(file.Append) != 1 { + // The number of append objects was different from expected, this file + // was created by the user and not via butane GRUB sugar + return *ts + } + fromPath := path.New("json", "storage", "files", i, "append", 0) + translatedPath := path.New("json", "storage", "files", i, "contents") + config.Storage.Files[i].FileEmbedded1.Contents = file.Append[0] + config.Storage.Files[i].FileEmbedded1.Append = nil + newMappings.AddFromCommonObject(fromPath, translatedPath, config.Storage.Files[i].FileEmbedded1.Contents) + + return ts.Map(newMappings) + } + } + return *ts +} diff --git a/mantle/vendor/github.com/coreos/butane/config/openshift/v4_13_exp/validate.go b/mantle/vendor/github.com/coreos/butane/config/openshift/v4_13_exp/validate.go new file mode 100644 index 0000000000..74f0955d15 --- /dev/null +++ b/mantle/vendor/github.com/coreos/butane/config/openshift/v4_13_exp/validate.go @@ -0,0 +1,43 @@ +// Copyright 2021 Red Hat, 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 v4_13_exp + +import ( + "github.com/coreos/butane/config/common" + + "github.com/coreos/vcontext/path" + "github.com/coreos/vcontext/report" +) + +func (m Metadata) Validate(c path.ContextPath) (r report.Report) { + if m.Name == "" { + r.AddOnError(c.Append("name"), common.ErrNameRequired) + } + if m.Labels[ROLE_LABEL_KEY] == "" { + r.AddOnError(c.Append("labels", ROLE_LABEL_KEY), common.ErrRoleRequired) + } + return +} + +func (os OpenShift) Validate(c path.ContextPath) (r report.Report) { + if os.KernelType != nil { + switch *os.KernelType { + case "", "default", "realtime": + default: + r.AddOnError(c.Append("kernel_type"), common.ErrInvalidKernelType) + } + } + return +} diff --git a/mantle/vendor/github.com/coreos/butane/translate/set.go b/mantle/vendor/github.com/coreos/butane/translate/set.go index e6c582e4c9..60df644ea9 100644 --- a/mantle/vendor/github.com/coreos/butane/translate/set.go +++ b/mantle/vendor/github.com/coreos/butane/translate/set.go @@ -105,6 +105,19 @@ func (ts TranslationSet) AddFromCommonSource(common path.ContextPath, toPrefix p ts.AddTranslation(common, toPrefix) } +// AddFromCommonObject adds translations for all of the paths in to. The paths being translated +// are prefixed by fromPrefix and the translated paths are prefixed by toPrefix. +// This is useful when we want to copy all the fields of an object to another with the same field names. +func (ts TranslationSet) AddFromCommonObject(fromPrefix path.ContextPath, toPrefix path.ContextPath, to interface{}) { + vTo := reflect.ValueOf(to) + vPaths := getAllPaths(vTo, ts.ToTag, true) + + for _, path := range vPaths { + ts.AddTranslation(fromPrefix.Append(path.Path...), toPrefix.Append(path.Path...)) + } + ts.AddTranslation(fromPrefix, toPrefix) +} + // Merge adds all the entries to the set. It mutates the Set in place. func (ts TranslationSet) Merge(from TranslationSet) { for _, t := range from.Set { @@ -160,6 +173,24 @@ OUTER: return ret } +// Map returns a new TranslationSet with To translation paths further +// translated through mappings. Translations not listed in mappings are +// copied unmodified. +func (ts TranslationSet) Map(mappings TranslationSet) TranslationSet { + if mappings.FromTag != ts.ToTag || mappings.ToTag != ts.ToTag { + panic(fmt.Sprintf("mappings have incorrect tag; %q != %q || %q != %q", mappings.FromTag, ts.ToTag, mappings.ToTag, ts.ToTag)) + } + ret := NewTranslationSet(ts.FromTag, ts.ToTag) + ret.Merge(ts) + for _, mapping := range mappings.Set { + if t, ok := ret.Set[mapping.From.String()]; ok { + delete(ret.Set, mapping.From.String()) + ret.AddTranslation(t.From, mapping.To) + } + } + return ret +} + // DebugVerifyCoverage recursively checks whether every non-zero field in v // has a translation. If translations are missing, it returns a multi-line // error listing them. diff --git a/mantle/vendor/github.com/coreos/go-json/decode.go b/mantle/vendor/github.com/coreos/go-json/decode.go index 1966dcdf42..b6f0df0878 100644 --- a/mantle/vendor/github.com/coreos/go-json/decode.go +++ b/mantle/vendor/github.com/coreos/go-json/decode.go @@ -229,16 +229,19 @@ func (n Number) Int64() (int64, error) { return strconv.ParseInt(string(n), 10, 64) } +// An errorContext provides context for type errors during decoding. +type errorContext struct { + Struct reflect.Type + FieldStack []string +} + // decodeState represents the state while decoding a JSON value. type decodeState struct { - data []byte - off int // next read offset in data - opcode int // last read result - scan scanner - errorContext struct { // provides context for type errors - Struct reflect.Type - FieldStack []string - } + data []byte + off int // next read offset in data + opcode int // last read result + scan scanner + errorContext *errorContext savedError error useNumber bool disallowUnknownFields bool @@ -258,10 +261,11 @@ func (d *decodeState) init(data []byte) *decodeState { d.data = data d.off = 0 d.savedError = nil - d.errorContext.Struct = nil - - // Reuse the allocated space for the FieldStack slice. - d.errorContext.FieldStack = d.errorContext.FieldStack[:0] + if d.errorContext != nil { + d.errorContext.Struct = nil + // Reuse the allocated space for the FieldStack slice. + d.errorContext.FieldStack = d.errorContext.FieldStack[:0] + } return d } @@ -275,12 +279,11 @@ func (d *decodeState) saveError(err error) { // addErrorContext returns a new error enhanced with information from d.errorContext func (d *decodeState) addErrorContext(err error) error { - if d.errorContext.Struct != nil || len(d.errorContext.FieldStack) > 0 { + if d.errorContext != nil && (d.errorContext.Struct != nil || len(d.errorContext.FieldStack) > 0) { switch err := err.(type) { case *UnmarshalTypeError: err.Struct = d.errorContext.Struct.Name() err.Field = strings.Join(d.errorContext.FieldStack, ".") - return err } } return err @@ -695,7 +698,10 @@ func (d *decodeState) object(v reflect.Value) error { } var mapElem reflect.Value - origErrorContext := d.errorContext + var origErrorContext errorContext + if d.errorContext != nil { + origErrorContext = *d.errorContext + } for { // Read opening " of string key or closing }. @@ -770,6 +776,9 @@ func (d *decodeState) object(v reflect.Value) error { } subv = subv.Field(i) } + if d.errorContext == nil { + d.errorContext = new(errorContext) + } d.errorContext.FieldStack = append(d.errorContext.FieldStack, f.name) d.errorContext.Struct = t } else if d.disallowUnknownFields { @@ -850,11 +859,13 @@ func (d *decodeState) object(v reflect.Value) error { if d.opcode == scanSkipSpace { d.scanWhile(scanSkipSpace) } - // Reset errorContext to its original state. - // Keep the same underlying array for FieldStack, to reuse the - // space and avoid unnecessary allocs. - d.errorContext.FieldStack = d.errorContext.FieldStack[:len(origErrorContext.FieldStack)] - d.errorContext.Struct = origErrorContext.Struct + if d.errorContext != nil { + // Reset errorContext to its original state. + // Keep the same underlying array for FieldStack, to reuse the + // space and avoid unnecessary allocs. + d.errorContext.FieldStack = d.errorContext.FieldStack[:len(origErrorContext.FieldStack)] + d.errorContext.Struct = origErrorContext.Struct + } if d.opcode == scanEndObject { break } diff --git a/mantle/vendor/github.com/coreos/go-json/encode.go b/mantle/vendor/github.com/coreos/go-json/encode.go index 578d551102..e473e615a9 100644 --- a/mantle/vendor/github.com/coreos/go-json/encode.go +++ b/mantle/vendor/github.com/coreos/go-json/encode.go @@ -236,6 +236,8 @@ func (e *UnsupportedTypeError) Error() string { return "json: unsupported type: " + e.Type.String() } +// An UnsupportedValueError is returned by Marshal when attempting +// to encode an unsupported value. type UnsupportedValueError struct { Value reflect.Value Str string @@ -779,28 +781,40 @@ func (me mapEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) { e.WriteString("null") return } + if e.ptrLevel++; e.ptrLevel > startDetectingCyclesAfter { + // We're a large number of nested ptrEncoder.encode calls deep; + // start checking if we've run into a pointer cycle. + ptr := v.Pointer() + if _, ok := e.ptrSeen[ptr]; ok { + e.error(&UnsupportedValueError{v, fmt.Sprintf("encountered a cycle via %s", v.Type())}) + } + e.ptrSeen[ptr] = struct{}{} + defer delete(e.ptrSeen, ptr) + } e.WriteByte('{') // Extract and sort the keys. - keys := v.MapKeys() - sv := make([]reflectWithString, len(keys)) - for i, v := range keys { - sv[i].v = v + sv := make([]reflectWithString, v.Len()) + mi := v.MapRange() + for i := 0; mi.Next(); i++ { + sv[i].k = mi.Key() + sv[i].v = mi.Value() if err := sv[i].resolve(); err != nil { e.error(fmt.Errorf("json: encoding error for type %q: %q", v.Type().String(), err.Error())) } } - sort.Slice(sv, func(i, j int) bool { return sv[i].s < sv[j].s }) + sort.Slice(sv, func(i, j int) bool { return sv[i].ks < sv[j].ks }) for i, kv := range sv { if i > 0 { e.WriteByte(',') } - e.string(kv.s, opts.escapeHTML) + e.string(kv.ks, opts.escapeHTML) e.WriteByte(':') - me.elemEnc(e, v.MapIndex(kv.v), opts) + me.elemEnc(e, kv.v, opts) } e.WriteByte('}') + e.ptrLevel-- } func newMapEncoder(t reflect.Type) encoderFunc { @@ -857,7 +871,23 @@ func (se sliceEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) { e.WriteString("null") return } + if e.ptrLevel++; e.ptrLevel > startDetectingCyclesAfter { + // We're a large number of nested ptrEncoder.encode calls deep; + // start checking if we've run into a pointer cycle. + // Here we use a struct to memorize the pointer to the first element of the slice + // and its length. + ptr := struct { + ptr uintptr + len int + }{v.Pointer(), v.Len()} + if _, ok := e.ptrSeen[ptr]; ok { + e.error(&UnsupportedValueError{v, fmt.Sprintf("encountered a cycle via %s", v.Type())}) + } + e.ptrSeen[ptr] = struct{}{} + defer delete(e.ptrSeen, ptr) + } se.arrayEnc(e, v, opts) + e.ptrLevel-- } func newSliceEncoder(t reflect.Type) encoderFunc { @@ -946,7 +976,7 @@ func isValidTag(s string) bool { } for _, c := range s { switch { - case strings.ContainsRune("!#$%&()*+-./:<=>?@[]^_{|}~ ", c): + case strings.ContainsRune("!#$%&()*+-./:;<=>?@[]^_{|}~ ", c): // Backslash and quote chars are reserved, but // otherwise any punctuation chars are allowed // in a tag name. @@ -968,29 +998,30 @@ func typeByIndex(t reflect.Type, index []int) reflect.Type { } type reflectWithString struct { - v reflect.Value - s string + k reflect.Value + v reflect.Value + ks string } func (w *reflectWithString) resolve() error { - if w.v.Kind() == reflect.String { - w.s = w.v.String() + if w.k.Kind() == reflect.String { + w.ks = w.k.String() return nil } - if tm, ok := w.v.Interface().(encoding.TextMarshaler); ok { - if w.v.Kind() == reflect.Ptr && w.v.IsNil() { + if tm, ok := w.k.Interface().(encoding.TextMarshaler); ok { + if w.k.Kind() == reflect.Ptr && w.k.IsNil() { return nil } buf, err := tm.MarshalText() - w.s = string(buf) + w.ks = string(buf) return err } - switch w.v.Kind() { + switch w.k.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - w.s = strconv.FormatInt(w.v.Int(), 10) + w.ks = strconv.FormatInt(w.k.Int(), 10) return nil case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - w.s = strconv.FormatUint(w.v.Uint(), 10) + w.ks = strconv.FormatUint(w.k.Uint(), 10) return nil } panic("unexpected map key type") @@ -1210,19 +1241,18 @@ func typeFields(t reflect.Type) structFields { // Scan f.typ for fields to include. for i := 0; i < f.typ.NumField(); i++ { sf := f.typ.Field(i) - isUnexported := sf.PkgPath != "" if sf.Anonymous { t := sf.Type if t.Kind() == reflect.Ptr { t = t.Elem() } - if isUnexported && t.Kind() != reflect.Struct { + if !sf.IsExported() && t.Kind() != reflect.Struct { // Ignore embedded fields of unexported non-struct types. continue } // Do not ignore embedded fields of unexported struct types // since they may have exported fields. - } else if isUnexported { + } else if !sf.IsExported() { // Ignore unexported non-embedded fields. continue } diff --git a/mantle/vendor/github.com/coreos/go-json/fuzz.go b/mantle/vendor/github.com/coreos/go-json/fuzz.go index be03f0d7ff..d3fa2d1113 100644 --- a/mantle/vendor/github.com/coreos/go-json/fuzz.go +++ b/mantle/vendor/github.com/coreos/go-json/fuzz.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build gofuzz // +build gofuzz package json diff --git a/mantle/vendor/github.com/coreos/go-json/go.mod b/mantle/vendor/github.com/coreos/go-json/go.mod index 8f9f23f408..5065e134d4 100644 --- a/mantle/vendor/github.com/coreos/go-json/go.mod +++ b/mantle/vendor/github.com/coreos/go-json/go.mod @@ -1,3 +1,3 @@ module github.com/coreos/go-json -go 1.15 +go 1.17 diff --git a/mantle/vendor/github.com/coreos/go-systemd/v22/dbus/dbus.go b/mantle/vendor/github.com/coreos/go-systemd/v22/dbus/dbus.go index 91584a1668..147f756fe2 100644 --- a/mantle/vendor/github.com/coreos/go-systemd/v22/dbus/dbus.go +++ b/mantle/vendor/github.com/coreos/go-systemd/v22/dbus/dbus.go @@ -16,6 +16,7 @@ package dbus import ( + "context" "encoding/hex" "fmt" "os" @@ -110,51 +111,76 @@ type Conn struct { } } -// New establishes a connection to any available bus and authenticates. -// Callers should call Close() when done with the connection. +// Deprecated: use NewWithContext instead. func New() (*Conn, error) { - conn, err := NewSystemConnection() + 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 NewSystemdConnection() + return NewSystemdConnectionContext(ctx) } return conn, err } -// NewSystemConnection establishes a connection to the system bus and authenticates. -// Callers should call Close() when done with the connection +// 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(dbus.SystemBusPrivate) + return dbusAuthHelloConnection(ctx, dbus.SystemBusPrivate) }) } -// NewUserConnection establishes a connection to the session bus and +// 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 NewUserConnection() (*Conn, error) { +func NewUserConnectionContext(ctx context.Context) (*Conn, error) { return NewConnection(func() (*dbus.Conn, error) { - return dbusAuthHelloConnection(dbus.SessionBusPrivate) + return dbusAuthHelloConnection(ctx, dbus.SessionBusPrivate) }) } -// NewSystemdConnection establishes a private, direct connection to systemd. +// 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 NewSystemdConnection() (*Conn, error) { +func NewSystemdConnectionContext(ctx context.Context) (*Conn, error) { return NewConnection(func() (*dbus.Conn, error) { // We skip Hello when talking directly to systemd. - return dbusAuthConnection(func(opts ...dbus.ConnOption) (*dbus.Conn, error) { - return dbus.Dial("unix:path=/run/systemd/private") + return dbusAuthConnection(ctx, func(opts ...dbus.ConnOption) (*dbus.Conn, error) { + return dbus.Dial("unix:path=/run/systemd/private", opts...) }) }) } -// Close closes an established connection +// 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. @@ -192,7 +218,7 @@ func NewConnection(dialBus func() (*dbus.Conn, error)) (*Conn, error) { // 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 +// 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 { @@ -201,8 +227,8 @@ func (c *Conn) GetManagerProperty(prop string) (string, error) { return variant.String(), nil } -func dbusAuthConnection(createBus func(opts ...dbus.ConnOption) (*dbus.Conn, error)) (*dbus.Conn, error) { - conn, err := createBus() +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 } @@ -221,8 +247,8 @@ func dbusAuthConnection(createBus func(opts ...dbus.ConnOption) (*dbus.Conn, err return conn, nil } -func dbusAuthHelloConnection(createBus func(opts ...dbus.ConnOption) (*dbus.Conn, error)) (*dbus.Conn, error) { - conn, err := dbusAuthConnection(createBus) +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 } diff --git a/mantle/vendor/github.com/coreos/go-systemd/v22/dbus/methods.go b/mantle/vendor/github.com/coreos/go-systemd/v22/dbus/methods.go index e38659d7be..074148cb4d 100644 --- a/mantle/vendor/github.com/coreos/go-systemd/v22/dbus/methods.go +++ b/mantle/vendor/github.com/coreos/go-systemd/v22/dbus/methods.go @@ -15,6 +15,7 @@ package dbus import ( + "context" "errors" "fmt" "path" @@ -23,6 +24,18 @@ import ( "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 @@ -38,14 +51,14 @@ func (c *Conn) jobComplete(signal *dbus.Signal) { c.jobListener.Unlock() } -func (c *Conn) startJob(ch chan<- string, job string, args ...interface{}) (int, error) { +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.Call(job, 0, args...).Store(&p) + err := c.sysobj.CallWithContext(ctx, job, 0, args...).Store(&p) if err != nil { return 0, err } @@ -60,7 +73,12 @@ func (c *Conn) startJob(ch chan<- string, job string, args ...interface{}) (int, return jobID, nil } -// StartUnit enqueues a start job and depending jobs, if any (unless otherwise +// 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 @@ -90,72 +108,130 @@ func (c *Conn) startJob(ch chan<- string, job string, args ...interface{}) (int, // 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) StartUnit(name string, mode string, ch chan<- string) (int, error) { - return c.startJob(ch, "org.freedesktop.systemd1.Manager.StartUnit", name, mode) +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) } -// StopUnit is similar to StartUnit but stops the specified unit rather -// than starting it. +// Deprecated: use StopUnitContext instead. func (c *Conn) StopUnit(name string, mode string, ch chan<- string) (int, error) { - return c.startJob(ch, "org.freedesktop.systemd1.Manager.StopUnit", name, mode) + 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) } -// ReloadUnit reloads a unit. Reloading is done only if the unit is already running and fails otherwise. +// Deprecated: use ReloadUnitContext instead. func (c *Conn) ReloadUnit(name string, mode string, ch chan<- string) (int, error) { - return c.startJob(ch, "org.freedesktop.systemd1.Manager.ReloadUnit", name, mode) + return c.ReloadUnitContext(context.Background(), name, mode, ch) } -// RestartUnit restarts a service. If a service is restarted that isn't -// running it will be started. +// 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.startJob(ch, "org.freedesktop.systemd1.Manager.RestartUnit", name, mode) + return c.RestartUnitContext(context.Background(), name, mode, ch) } -// TryRestartUnit is like RestartUnit, except that a service that isn't running -// is not affected by the restart. +// 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.startJob(ch, "org.freedesktop.systemd1.Manager.TryRestartUnit", name, mode) + 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) } -// ReloadOrRestartUnit attempts a reload if the unit supports it and use a restart -// otherwise. +// Deprecated: use ReloadOrRestartUnitContext instead. func (c *Conn) ReloadOrRestartUnit(name string, mode string, ch chan<- string) (int, error) { - return c.startJob(ch, "org.freedesktop.systemd1.Manager.ReloadOrRestartUnit", name, mode) + return c.ReloadOrRestartUnitContext(context.Background(), name, mode, ch) } -// ReloadOrTryRestartUnit attempts a reload if the unit supports it and use a "Try" -// flavored restart otherwise. +// 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.startJob(ch, "org.freedesktop.systemd1.Manager.ReloadOrTryRestartUnit", name, mode) + 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) } -// StartTransientUnit() may be used to create and start a transient unit, which +// 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 StartUnit(), properties contains properties +// unique. mode is the same as in StartUnitContext, properties contains properties // of the unit. -func (c *Conn) StartTransientUnit(name string, mode string, properties []Property, ch chan<- string) (int, error) { - return c.startJob(ch, "org.freedesktop.systemd1.Manager.StartTransientUnit", name, mode, properties, make([]PropertyCollection, 0)) +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)) } -// KillUnit takes the unit name and a UNIX signal number to send. All of the unit's -// processes are killed. +// Deprecated: use KillUnitContext instead. func (c *Conn) KillUnit(name string, signal int32) { - c.sysobj.Call("org.freedesktop.systemd1.Manager.KillUnit", 0, name, "all", signal).Store() + 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) } -// ResetFailedUnit resets the "failed" state of a specific unit. +// 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.sysobj.Call("org.freedesktop.systemd1.Manager.ResetFailedUnit", 0, name).Store() + 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() } -// SystemState returns the systemd state. Equivalent to `systemctl is-system-running`. +// 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.Call("org.freedesktop.DBus.Properties.Get", 0, "org.freedesktop.systemd1.Manager", "SystemState").Store(&prop) + err = obj.CallWithContext(ctx, "org.freedesktop.DBus.Properties.Get", 0, "org.freedesktop.systemd1.Manager", "SystemState").Store(&prop) if err != nil { return nil, err } @@ -163,8 +239,8 @@ func (c *Conn) SystemState() (*Property, error) { 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(path dbus.ObjectPath, dbusInterface string) (map[string]interface{}, error) { +// 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 @@ -173,7 +249,7 @@ func (c *Conn) getProperties(path dbus.ObjectPath, dbusInterface string) (map[st } obj := c.sysconn.Object("org.freedesktop.systemd1", path) - err = obj.Call("org.freedesktop.DBus.Properties.GetAll", 0, dbusInterface).Store(&props) + err = obj.CallWithContext(ctx, "org.freedesktop.DBus.Properties.GetAll", 0, dbusInterface).Store(&props) if err != nil { return nil, err } @@ -186,24 +262,42 @@ func (c *Conn) getProperties(path dbus.ObjectPath, dbusInterface string) (map[st return out, nil } -// GetUnitProperties takes the (unescaped) unit name and returns all of its dbus object properties. +// 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(path, "org.freedesktop.systemd1.Unit") + return c.getProperties(ctx, path, "org.freedesktop.systemd1.Unit") } -// GetUnitPathProperties takes the (escaped) unit path and returns all of its dbus object properties. +// Deprecated: use GetUnitPathPropertiesContext instead. func (c *Conn) GetUnitPathProperties(path dbus.ObjectPath) (map[string]interface{}, error) { - return c.getProperties(path, "org.freedesktop.systemd1.Unit") + return c.GetUnitPathPropertiesContext(context.Background(), path) } -// GetAllProperties takes the (unescaped) unit name and returns all of its dbus object properties. +// 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(path, "") + return c.getProperties(ctx, path, "") } -func (c *Conn) getProperty(unit string, dbusInterface string, propertyName string) (*Property, error) { +func (c *Conn) getProperty(ctx context.Context, unit string, dbusInterface string, propertyName string) (*Property, error) { var err error var prop dbus.Variant @@ -213,7 +307,7 @@ func (c *Conn) getProperty(unit string, dbusInterface string, propertyName strin } obj := c.sysconn.Object("org.freedesktop.systemd1", path) - err = obj.Call("org.freedesktop.DBus.Properties.Get", 0, dbusInterface, propertyName).Store(&prop) + err = obj.CallWithContext(ctx, "org.freedesktop.DBus.Properties.Get", 0, dbusInterface, propertyName).Store(&prop) if err != nil { return nil, err } @@ -221,36 +315,65 @@ func (c *Conn) getProperty(unit string, dbusInterface string, propertyName strin return &Property{Name: propertyName, Value: prop}, nil } +// Deprecated: use GetUnitPropertyContext instead. func (c *Conn) GetUnitProperty(unit string, propertyName string) (*Property, error) { - return c.getProperty(unit, "org.freedesktop.systemd1.Unit", propertyName) + return c.GetUnitPropertyContext(context.Background(), unit, propertyName) } -// GetServiceProperty returns property for given service name and property name +// 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.getProperty(service, "org.freedesktop.systemd1.Service", propertyName) + 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) } -// GetUnitTypeProperties 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 -// return "dbus.Error: Unknown interface" if the unitType is not the correct type of the unit +// 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(path, "org.freedesktop.systemd1."+unitType) + 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...) } -// SetUnitProperties() may be used to modify certain unit properties at runtime. +// 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) SetUnitProperties(name string, runtime bool, properties ...Property) error { - return c.sysobj.Call("org.freedesktop.systemd1.Manager.SetUnitProperties", 0, name, runtime, properties).Store() +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.getProperty(unit, "org.freedesktop.systemd1."+unitType, propertyName) + 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 { @@ -294,36 +417,80 @@ func (c *Conn) listUnitsInternal(f storeFunc) ([]UnitStatus, error) { return status, nil } -// ListUnits returns an array with all currently loaded units. Note that +// 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) ListUnits() ([]UnitStatus, error) { - return c.listUnitsInternal(c.sysobj.Call("org.freedesktop.systemd1.Manager.ListUnits", 0).Store) +func (c *Conn) ListUnitsContext(ctx context.Context) ([]UnitStatus, error) { + return c.listUnitsInternal(c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.ListUnits", 0).Store) } -// ListUnitsFiltered returns an array with units filtered by state. -// It takes a list of units' statuses to filter. +// Deprecated: use ListUnitsFilteredContext instead. func (c *Conn) ListUnitsFiltered(states []string) ([]UnitStatus, error) { - return c.listUnitsInternal(c.sysobj.Call("org.freedesktop.systemd1.Manager.ListUnitsFiltered", 0, states).Store) + 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) } -// ListUnitsByPatterns returns an array with units. +// 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) ListUnitsByPatterns(states []string, patterns []string) ([]UnitStatus, error) { - return c.listUnitsInternal(c.sysobj.Call("org.freedesktop.systemd1.Manager.ListUnitsByPatterns", 0, states, patterns).Store) +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) } -// ListUnitsByNames returns an array with units. It takes a list of units' -// names and returns an UnitStatus array. Comparing to ListUnitsByPatterns +// 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. -// Note: Requires systemd v230 or higher -func (c *Conn) ListUnitsByNames(units []string) ([]UnitStatus, error) { - return c.listUnitsInternal(c.sysobj.Call("org.freedesktop.systemd1.Manager.ListUnitsByNames", 0, units).Store) +// +// 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 { @@ -357,25 +524,43 @@ func (c *Conn) listUnitFilesInternal(f storeFunc) ([]UnitFile, error) { return files, nil } -// ListUnitFiles returns an array of all available units on disk. +// Deprecated: use ListUnitFilesContext instead. func (c *Conn) ListUnitFiles() ([]UnitFile, error) { - return c.listUnitFilesInternal(c.sysobj.Call("org.freedesktop.systemd1.Manager.ListUnitFiles", 0).Store) + return c.ListUnitFilesContext(context.Background()) } -// ListUnitFilesByPatterns returns an array of all available units on disk matched the patterns. +// 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.listUnitFilesInternal(c.sysobj.Call("org.freedesktop.systemd1.Manager.ListUnitFilesByPatterns", 0, states, patterns).Store) + 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 -// LinkUnitFiles() links unit files (that are located outside of the +// 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 +// 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. // @@ -383,9 +568,9 @@ type LinkUnitFileChange EnableUnitFileChange // 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) LinkUnitFiles(files []string, runtime bool, force bool) ([]LinkUnitFileChange, error) { +func (c *Conn) LinkUnitFilesContext(ctx context.Context, files []string, runtime bool, force bool) ([]LinkUnitFileChange, error) { result := make([][]interface{}, 0) - err := c.sysobj.Call("org.freedesktop.systemd1.Manager.LinkUnitFiles", 0, files, runtime, force).Store(&result) + err := c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.LinkUnitFiles", 0, files, runtime, force).Store(&result) if err != nil { return nil, err } @@ -409,8 +594,13 @@ func (c *Conn) LinkUnitFiles(files []string, runtime bool, force bool) ([]LinkUn return changes, nil } -// EnableUnitFiles() may be used to enable one or more units in the system (by -// creating symlinks to them in /etc or /run). +// 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 @@ -425,11 +615,11 @@ func (c *Conn) LinkUnitFiles(files []string, runtime bool, force bool) ([]LinkUn // 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) EnableUnitFiles(files []string, runtime bool, force bool) (bool, []EnableUnitFileChange, error) { +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.Call("org.freedesktop.systemd1.Manager.EnableUnitFiles", 0, files, runtime, force).Store(&carries_install_info, &result) + 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 } @@ -459,8 +649,13 @@ type EnableUnitFileChange struct { Destination string // Destination of the symlink } -// DisableUnitFiles() may be used to disable one or more units in the system (by -// removing symlinks to them from /etc or /run). +// 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 @@ -471,9 +666,9 @@ type EnableUnitFileChange struct { // 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) DisableUnitFiles(files []string, runtime bool) ([]DisableUnitFileChange, error) { +func (c *Conn) DisableUnitFilesContext(ctx context.Context, files []string, runtime bool) ([]DisableUnitFileChange, error) { result := make([][]interface{}, 0) - err := c.sysobj.Call("org.freedesktop.systemd1.Manager.DisableUnitFiles", 0, files, runtime).Store(&result) + err := c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.DisableUnitFiles", 0, files, runtime).Store(&result) if err != nil { return nil, err } @@ -503,18 +698,23 @@ type DisableUnitFileChange struct { Destination string // Destination of the symlink } -// MaskUnitFiles masks one or more units in the system -// -// It takes three arguments: -// * 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) -// * runtime to specify whether the unit was enabled for runtime -// only (true, /run/systemd/..), or persistently (false, /etc/systemd/..) -// * force flag +// 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.Call("org.freedesktop.systemd1.Manager.MaskUnitFiles", 0, files, runtime, force).Store(&result) + err := c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.MaskUnitFiles", 0, files, runtime, force).Store(&result) if err != nil { return nil, err } @@ -544,17 +744,21 @@ type MaskUnitFileChange struct { Destination string // Destination of the symlink } -// UnmaskUnitFiles unmasks one or more units in the system -// -// It takes two arguments: -// * 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) -// * runtime to specify whether the unit was enabled for runtime -// only (true, /run/systemd/..), or persistently (false, /etc/systemd/..) +// 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.Call("org.freedesktop.systemd1.Manager.UnmaskUnitFiles", 0, files, runtime).Store(&result) + err := c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.UnmaskUnitFiles", 0, files, runtime).Store(&result) if err != nil { return nil, err } @@ -584,17 +788,77 @@ type UnmaskUnitFileChange struct { Destination string // Destination of the symlink } -// Reload instructs systemd to scan for and reload unit files. This is -// equivalent to a 'systemctl daemon-reload'. +// Deprecated: use ReloadContext instead. func (c *Conn) Reload() error { - return c.sysobj.Call("org.freedesktop.systemd1.Manager.Reload", 0).Store() + 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 +// 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/mantle/vendor/github.com/coreos/go-systemd/v22/journal/journal.go b/mantle/vendor/github.com/coreos/go-systemd/v22/journal/journal.go index a0f4837a02..ac24c7767d 100644 --- a/mantle/vendor/github.com/coreos/go-systemd/v22/journal/journal.go +++ b/mantle/vendor/github.com/coreos/go-systemd/v22/journal/journal.go @@ -23,20 +23,7 @@ package journal import ( - "bytes" - "encoding/binary" - "errors" "fmt" - "io" - "io/ioutil" - "net" - "os" - "strconv" - "strings" - "sync" - "sync/atomic" - "syscall" - "unsafe" ) // Priority of a journal message @@ -53,173 +40,7 @@ const ( PriDebug ) -var ( - // This can be overridden at build-time: - // https://github.com/golang/go/wiki/GcToolchainTricks#including-build-information-in-the-executable - journalSocket = "/run/systemd/journal/socket" - - // unixConnPtr atomically holds the local unconnected Unix-domain socket. - // Concrete safe pointer type: *net.UnixConn - unixConnPtr unsafe.Pointer - // onceConn ensures that unixConnPtr is initialized exactly once. - onceConn sync.Once -) - -func init() { - onceConn.Do(initConn) -} - -// Enabled checks whether the local systemd journal is available for logging. -func Enabled() bool { - onceConn.Do(initConn) - - if (*net.UnixConn)(atomic.LoadPointer(&unixConnPtr)) == nil { - return false - } - - if _, err := net.Dial("unixgram", journalSocket); err != nil { - return false - } - - return true -} - -// Send a message to the local systemd journal. vars is a map of journald -// fields to values. Fields must be composed of uppercase letters, numbers, -// and underscores, but must not start with an underscore. Within these -// restrictions, any arbitrary field name may be used. Some names have special -// significance: see the journalctl documentation -// (http://www.freedesktop.org/software/systemd/man/systemd.journal-fields.html) -// for more details. vars may be nil. -func Send(message string, priority Priority, vars map[string]string) error { - conn := (*net.UnixConn)(atomic.LoadPointer(&unixConnPtr)) - if conn == nil { - return errors.New("could not initialize socket to journald") - } - - socketAddr := &net.UnixAddr{ - Name: journalSocket, - Net: "unixgram", - } - - data := new(bytes.Buffer) - appendVariable(data, "PRIORITY", strconv.Itoa(int(priority))) - appendVariable(data, "MESSAGE", message) - for k, v := range vars { - appendVariable(data, k, v) - } - - _, _, err := conn.WriteMsgUnix(data.Bytes(), nil, socketAddr) - if err == nil { - return nil - } - if !isSocketSpaceError(err) { - return err - } - - // Large log entry, send it via tempfile and ancillary-fd. - file, err := tempFd() - if err != nil { - return err - } - defer file.Close() - _, err = io.Copy(file, data) - if err != nil { - return err - } - rights := syscall.UnixRights(int(file.Fd())) - _, _, err = conn.WriteMsgUnix([]byte{}, rights, socketAddr) - if err != nil { - return err - } - - return nil -} - // Print prints a message to the local systemd journal using Send(). func Print(priority Priority, format string, a ...interface{}) error { return Send(fmt.Sprintf(format, a...), priority, nil) } - -func appendVariable(w io.Writer, name, value string) { - if err := validVarName(name); err != nil { - fmt.Fprintf(os.Stderr, "variable name %s contains invalid character, ignoring\n", name) - } - if strings.ContainsRune(value, '\n') { - /* When the value contains a newline, we write: - * - the variable name, followed by a newline - * - the size (in 64bit little endian format) - * - the data, followed by a newline - */ - fmt.Fprintln(w, name) - binary.Write(w, binary.LittleEndian, uint64(len(value))) - fmt.Fprintln(w, value) - } else { - /* just write the variable and value all on one line */ - fmt.Fprintf(w, "%s=%s\n", name, value) - } -} - -// validVarName validates a variable name to make sure journald will accept it. -// The variable name must be in uppercase and consist only of characters, -// numbers and underscores, and may not begin with an underscore: -// https://www.freedesktop.org/software/systemd/man/sd_journal_print.html -func validVarName(name string) error { - if name == "" { - return errors.New("Empty variable name") - } else if name[0] == '_' { - return errors.New("Variable name begins with an underscore") - } - - for _, c := range name { - if !(('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_') { - return errors.New("Variable name contains invalid characters") - } - } - return nil -} - -// isSocketSpaceError checks whether the error is signaling -// an "overlarge message" condition. -func isSocketSpaceError(err error) bool { - opErr, ok := err.(*net.OpError) - if !ok || opErr == nil { - return false - } - - sysErr, ok := opErr.Err.(*os.SyscallError) - if !ok || sysErr == nil { - return false - } - - return sysErr.Err == syscall.EMSGSIZE || sysErr.Err == syscall.ENOBUFS -} - -// tempFd creates a temporary, unlinked file under `/dev/shm`. -func tempFd() (*os.File, error) { - file, err := ioutil.TempFile("/dev/shm/", "journal.XXXXX") - if err != nil { - return nil, err - } - err = syscall.Unlink(file.Name()) - if err != nil { - return nil, err - } - return file, nil -} - -// initConn initializes the global `unixConnPtr` socket. -// It is meant to be called exactly once, at program startup. -func initConn() { - autobind, err := net.ResolveUnixAddr("unixgram", "") - if err != nil { - return - } - - sock, err := net.ListenUnixgram("unixgram", autobind) - if err != nil { - return - } - - atomic.StorePointer(&unixConnPtr, unsafe.Pointer(sock)) -} diff --git a/mantle/vendor/github.com/coreos/go-systemd/v22/journal/journal_unix.go b/mantle/vendor/github.com/coreos/go-systemd/v22/journal/journal_unix.go new file mode 100644 index 0000000000..439ad28746 --- /dev/null +++ b/mantle/vendor/github.com/coreos/go-systemd/v22/journal/journal_unix.go @@ -0,0 +1,215 @@ +// 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. + +//go:build !windows +// +build !windows + +// Package journal provides write bindings to the local systemd journal. +// It is implemented in pure Go and connects to the journal directly over its +// unix socket. +// +// To read from the journal, see the "sdjournal" package, which wraps the +// sd-journal a C API. +// +// http://www.freedesktop.org/software/systemd/man/systemd-journald.service.html +package journal + +import ( + "bytes" + "encoding/binary" + "errors" + "fmt" + "io" + "io/ioutil" + "net" + "os" + "strconv" + "strings" + "sync" + "sync/atomic" + "syscall" + "unsafe" +) + +var ( + // This can be overridden at build-time: + // https://github.com/golang/go/wiki/GcToolchainTricks#including-build-information-in-the-executable + journalSocket = "/run/systemd/journal/socket" + + // unixConnPtr atomically holds the local unconnected Unix-domain socket. + // Concrete safe pointer type: *net.UnixConn + unixConnPtr unsafe.Pointer + // onceConn ensures that unixConnPtr is initialized exactly once. + onceConn sync.Once +) + +// Enabled checks whether the local systemd journal is available for logging. +func Enabled() bool { + if c := getOrInitConn(); c == nil { + return false + } + + conn, err := net.Dial("unixgram", journalSocket) + if err != nil { + return false + } + defer conn.Close() + + return true +} + +// Send a message to the local systemd journal. vars is a map of journald +// fields to values. Fields must be composed of uppercase letters, numbers, +// and underscores, but must not start with an underscore. Within these +// restrictions, any arbitrary field name may be used. Some names have special +// significance: see the journalctl documentation +// (http://www.freedesktop.org/software/systemd/man/systemd.journal-fields.html) +// for more details. vars may be nil. +func Send(message string, priority Priority, vars map[string]string) error { + conn := getOrInitConn() + if conn == nil { + return errors.New("could not initialize socket to journald") + } + + socketAddr := &net.UnixAddr{ + Name: journalSocket, + Net: "unixgram", + } + + data := new(bytes.Buffer) + appendVariable(data, "PRIORITY", strconv.Itoa(int(priority))) + appendVariable(data, "MESSAGE", message) + for k, v := range vars { + appendVariable(data, k, v) + } + + _, _, err := conn.WriteMsgUnix(data.Bytes(), nil, socketAddr) + if err == nil { + return nil + } + if !isSocketSpaceError(err) { + return err + } + + // Large log entry, send it via tempfile and ancillary-fd. + file, err := tempFd() + if err != nil { + return err + } + defer file.Close() + _, err = io.Copy(file, data) + if err != nil { + return err + } + rights := syscall.UnixRights(int(file.Fd())) + _, _, err = conn.WriteMsgUnix([]byte{}, rights, socketAddr) + if err != nil { + return err + } + + return nil +} + +// getOrInitConn attempts to get the global `unixConnPtr` socket, initializing if necessary +func getOrInitConn() *net.UnixConn { + conn := (*net.UnixConn)(atomic.LoadPointer(&unixConnPtr)) + if conn != nil { + return conn + } + onceConn.Do(initConn) + return (*net.UnixConn)(atomic.LoadPointer(&unixConnPtr)) +} + +func appendVariable(w io.Writer, name, value string) { + if err := validVarName(name); err != nil { + fmt.Fprintf(os.Stderr, "variable name %s contains invalid character, ignoring\n", name) + } + if strings.ContainsRune(value, '\n') { + /* When the value contains a newline, we write: + * - the variable name, followed by a newline + * - the size (in 64bit little endian format) + * - the data, followed by a newline + */ + fmt.Fprintln(w, name) + binary.Write(w, binary.LittleEndian, uint64(len(value))) + fmt.Fprintln(w, value) + } else { + /* just write the variable and value all on one line */ + fmt.Fprintf(w, "%s=%s\n", name, value) + } +} + +// validVarName validates a variable name to make sure journald will accept it. +// The variable name must be in uppercase and consist only of characters, +// numbers and underscores, and may not begin with an underscore: +// https://www.freedesktop.org/software/systemd/man/sd_journal_print.html +func validVarName(name string) error { + if name == "" { + return errors.New("Empty variable name") + } else if name[0] == '_' { + return errors.New("Variable name begins with an underscore") + } + + for _, c := range name { + if !(('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_') { + return errors.New("Variable name contains invalid characters") + } + } + return nil +} + +// isSocketSpaceError checks whether the error is signaling +// an "overlarge message" condition. +func isSocketSpaceError(err error) bool { + opErr, ok := err.(*net.OpError) + if !ok || opErr == nil { + return false + } + + sysErr, ok := opErr.Err.(*os.SyscallError) + if !ok || sysErr == nil { + return false + } + + return sysErr.Err == syscall.EMSGSIZE || sysErr.Err == syscall.ENOBUFS +} + +// tempFd creates a temporary, unlinked file under `/dev/shm`. +func tempFd() (*os.File, error) { + file, err := ioutil.TempFile("/dev/shm/", "journal.XXXXX") + if err != nil { + return nil, err + } + err = syscall.Unlink(file.Name()) + if err != nil { + return nil, err + } + return file, nil +} + +// initConn initializes the global `unixConnPtr` socket. +// It is automatically called when needed. +func initConn() { + autobind, err := net.ResolveUnixAddr("unixgram", "") + if err != nil { + return + } + + sock, err := net.ListenUnixgram("unixgram", autobind) + if err != nil { + return + } + + atomic.StorePointer(&unixConnPtr, unsafe.Pointer(sock)) +} diff --git a/mantle/vendor/github.com/coreos/go-systemd/v22/journal/journal_windows.go b/mantle/vendor/github.com/coreos/go-systemd/v22/journal/journal_windows.go new file mode 100644 index 0000000000..677aca68ed --- /dev/null +++ b/mantle/vendor/github.com/coreos/go-systemd/v22/journal/journal_windows.go @@ -0,0 +1,35 @@ +// 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 journal provides write bindings to the local systemd journal. +// It is implemented in pure Go and connects to the journal directly over its +// unix socket. +// +// To read from the journal, see the "sdjournal" package, which wraps the +// sd-journal a C API. +// +// http://www.freedesktop.org/software/systemd/man/systemd-journald.service.html +package journal + +import ( + "errors" +) + +func Enabled() bool { + return false +} + +func Send(message string, priority Priority, vars map[string]string) error { + return errors.New("could not initialize socket to journald") +} diff --git a/mantle/vendor/github.com/coreos/go-systemd/v22/unit/deserialize.go b/mantle/vendor/github.com/coreos/go-systemd/v22/unit/deserialize.go index c0c06bdfc2..283c150771 100644 --- a/mantle/vendor/github.com/coreos/go-systemd/v22/unit/deserialize.go +++ b/mantle/vendor/github.com/coreos/go-systemd/v22/unit/deserialize.go @@ -43,37 +43,99 @@ var ( ErrLineTooLong = fmt.Errorf("line too long (max %d bytes)", SYSTEMD_LINE_MAX) ) -// Deserialize parses a systemd unit file into a list of UnitOption objects. +// DeserializeOptions parses a systemd unit file into a list of UnitOptions +func DeserializeOptions(f io.Reader) (opts []*UnitOption, err error) { + _, options, err := deserializeAll(f) + return options, err +} + +// DeserializeSections deserializes into a list of UnitSections. +func DeserializeSections(f io.Reader) ([]*UnitSection, error) { + sections, _, err := deserializeAll(f) + return sections, err +} + +// Deserialize parses a systemd unit file into a list of UnitOptions. +// Note: this function is deprecated in favor of DeserializeOptions +// and will be removed at a future date. func Deserialize(f io.Reader) (opts []*UnitOption, err error) { - lexer, optchan, errchan := newLexer(f) + return DeserializeOptions(f) +} + +type lexDataType int + +const ( + sectionKind lexDataType = iota + optionKind +) + +// lexChanData - support either datatype in the lex channel. +// Poor man's union data type. +type lexData struct { + Type lexDataType + Option *UnitOption + Section *UnitSection +} + +// deserializeAll deserializes into UnitSections and UnitOptions. +func deserializeAll(f io.Reader) ([]*UnitSection, []*UnitOption, error) { + + lexer, lexchan, errchan := newLexer(f) + go lexer.lex() - for opt := range optchan { - opts = append(opts, &(*opt)) + sections := []*UnitSection{} + options := []*UnitOption{} + + for ld := range lexchan { + switch ld.Type { + case optionKind: + if ld.Option != nil { + // add to options + opt := ld.Option + options = append(options, &(*opt)) + + // sanity check. "should not happen" as sectionKind is first in code flow. + if len(sections) == 0 { + return nil, nil, fmt.Errorf( + "Unit file misparse: option before section") + } + + // add to newest section entries. + s := len(sections) - 1 + sections[s].Entries = append(sections[s].Entries, + &UnitEntry{Name: opt.Name, Value: opt.Value}) + } + case sectionKind: + if ld.Section != nil { + sections = append(sections, ld.Section) + } + } } - err = <-errchan - return opts, err + err := <-errchan + + return sections, options, err } -func newLexer(f io.Reader) (*lexer, <-chan *UnitOption, <-chan error) { - optchan := make(chan *UnitOption) +func newLexer(f io.Reader) (*lexer, <-chan *lexData, <-chan error) { + lexchan := make(chan *lexData) errchan := make(chan error, 1) buf := bufio.NewReader(f) - return &lexer{buf, optchan, errchan, ""}, optchan, errchan + return &lexer{buf, lexchan, errchan, ""}, lexchan, errchan } type lexer struct { buf *bufio.Reader - optchan chan *UnitOption + lexchan chan *lexData errchan chan error section string } func (l *lexer) lex() { defer func() { - close(l.optchan) + close(l.lexchan) close(l.errchan) }() next := l.lexNextSection @@ -123,7 +185,13 @@ func (l *lexer) lexSectionSuffixFunc(section string) lexStep { garbage = bytes.TrimSpace(garbage) if len(garbage) > 0 { - return nil, fmt.Errorf("found garbage after section name %s: %v", l.section, garbage) + return nil, fmt.Errorf("found garbage after section name %s: %q", l.section, garbage) + } + + l.lexchan <- &lexData{ + Type: sectionKind, + Section: &UnitSection{Section: section, Entries: []*UnitEntry{}}, + Option: nil, } return l.lexNextSectionOrOptionFunc(section), nil @@ -252,7 +320,11 @@ func (l *lexer) lexOptionValueFunc(section, name string, partial bytes.Buffer) l } else { val = strings.TrimSpace(val) } - l.optchan <- &UnitOption{Section: section, Name: name, Value: val} + l.lexchan <- &lexData{ + Type: optionKind, + Section: nil, + Option: &UnitOption{Section: section, Name: name, Value: val}, + } return l.lexNextSectionOrOptionFunc(section), nil } diff --git a/mantle/vendor/github.com/coreos/go-systemd/v22/unit/escape.go b/mantle/vendor/github.com/coreos/go-systemd/v22/unit/escape.go index 63b11726db..98e2044a71 100644 --- a/mantle/vendor/github.com/coreos/go-systemd/v22/unit/escape.go +++ b/mantle/vendor/github.com/coreos/go-systemd/v22/unit/escape.go @@ -27,14 +27,15 @@ const ( ) // If isPath is true: -// We remove redundant '/'s, the leading '/', and trailing '/'. -// If the result is empty, a '/' is inserted. +// +// We remove redundant '/'s, the leading '/', and trailing '/'. +// If the result is empty, a '/' is inserted. // // We always: -// Replace the following characters with `\x%x`: -// Leading `.` -// `-`, `\`, and anything not in this set: `:-_.\[0-9a-zA-Z]` -// Replace '/' with '-'. +// +// Replace the following characters with `\x%x`: Leading `.`, +// `-`, `\`, and anything not in this set: `:-_.\[0-9a-zA-Z]` +// Replace '/' with '-'. func escape(unescaped string, isPath bool) string { e := []byte{} inSlashes := false @@ -69,11 +70,13 @@ func escape(unescaped string, isPath bool) string { } // If isPath is true: -// We always return a string beginning with '/'. +// +// We always return a string beginning with '/'. // // We always: -// Replace '-' with '/'. -// Replace `\x%x` with the value represented in hex. +// +// Replace '-' with '/'. +// Replace `\x%x` with the value represented in hex. func unescape(escaped string, isPath bool) string { u := []byte{} for i := 0; i < len(escaped); i++ { diff --git a/mantle/vendor/github.com/coreos/go-systemd/v22/unit/section.go b/mantle/vendor/github.com/coreos/go-systemd/v22/unit/section.go new file mode 100644 index 0000000000..217a183cbd --- /dev/null +++ b/mantle/vendor/github.com/coreos/go-systemd/v22/unit/section.go @@ -0,0 +1,44 @@ +// Copyright 2020 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 unit + +// UnitEntry is a single line entry in a Unit file. +type UnitEntry struct { + Name string + Value string +} + +// UnitSection is a section in a Unit file. The section name +// and a list of entries in that section. +type UnitSection struct { + Section string + Entries []*UnitEntry +} + +// String implements the stringify interface for UnitEntry +func (u *UnitEntry) String() string { + return "{Name: " + u.Name + ", " + "Value: " + u.Value + "}" +} + +// String implements the stringify interface for UnitSection +func (s *UnitSection) String() string { + result := "{Section: " + s.Section + for _, e := range s.Entries { + result += e.String() + } + + result += "}" + return result +} diff --git a/mantle/vendor/github.com/coreos/go-systemd/v22/unit/serialize.go b/mantle/vendor/github.com/coreos/go-systemd/v22/unit/serialize.go index e07799cad6..c1b79c02dc 100644 --- a/mantle/vendor/github.com/coreos/go-systemd/v22/unit/serialize.go +++ b/mantle/vendor/github.com/coreos/go-systemd/v22/unit/serialize.go @@ -58,6 +58,29 @@ func Serialize(opts []*UnitOption) io.Reader { return &buf } +// SerializeSections will serializes the unit file from the given +// UnitSections. +func SerializeSections(sections []*UnitSection) io.Reader { + + var buf bytes.Buffer + + for i, s := range sections { + writeSectionHeader(&buf, s.Section) + writeNewline(&buf) + + for _, e := range s.Entries { + writeOption(&buf, &UnitOption{s.Section, e.Name, e.Value}) + writeNewline(&buf) + } + + if i < len(sections)-1 { + writeNewline(&buf) + } + } + + return &buf +} + func writeNewline(buf *bytes.Buffer) { buf.WriteRune('\n') } diff --git a/mantle/vendor/github.com/godbus/dbus/v5/.travis.yml b/mantle/vendor/github.com/godbus/dbus/v5/.travis.yml deleted file mode 100644 index dd67672048..0000000000 --- a/mantle/vendor/github.com/godbus/dbus/v5/.travis.yml +++ /dev/null @@ -1,50 +0,0 @@ -dist: bionic -language: go -go_import_path: github.com/godbus/dbus - -go: - - 1.11.x - - 1.12.x - - 1.13.x - - tip - -matrix: - fast_finish: true - allow_failures: - - go: tip - -addons: - apt: - packages: - - dbus - - dbus-x11 - -before_install: - - export GO111MODULE=on - -script: - - go test -v -race -mod=readonly ./... # Run all the tests with the race detector enabled - - go vet ./... # go vet is the official Go static analyzer - -jobs: - include: - # The build matrix doesn't cover build stages, so manually expand - # the jobs with anchors - - &multiarch - stage: "Multiarch Test" - go: 1.11.x - env: TARGETS="386 arm arm64 ppc64le" - before_install: - - docker run --rm --privileged multiarch/qemu-user-static --reset -p yes - script: - - | - set -e - for target in $TARGETS; do - printf "\e[1mRunning test suite under ${target}.\e[0m\n" - GOARCH="$target" go test -v ./... - printf "\n\n" - done - - <<: *multiarch - go: 1.12.x - - <<: *multiarch - go: 1.13.x diff --git a/mantle/vendor/github.com/godbus/dbus/v5/README.markdown b/mantle/vendor/github.com/godbus/dbus/v5/README.markdown index fd29648752..1fb2eacaa1 100644 --- a/mantle/vendor/github.com/godbus/dbus/v5/README.markdown +++ b/mantle/vendor/github.com/godbus/dbus/v5/README.markdown @@ -1,4 +1,4 @@ -[![Build Status](https://travis-ci.org/godbus/dbus.svg?branch=master)](https://travis-ci.org/godbus/dbus) +![Build Status](https://github.com/godbus/dbus/workflows/Go/badge.svg) dbus ---- @@ -32,6 +32,8 @@ gives a short overview over the basic usage. #### Projects using godbus - [notify](https://github.com/esiqveland/notify) provides desktop notifications over dbus into a library. - [go-bluetooth](https://github.com/muka/go-bluetooth) provides a bluetooth client over bluez dbus API. +- [playerbm](https://github.com/altdesktop/playerbm) a bookmark utility for media players. +- [iwd](https://github.com/shibumi/iwd) go bindings for the internet wireless daemon "iwd". Please note that the API is considered unstable for now and may change without further notice. diff --git a/mantle/vendor/github.com/godbus/dbus/v5/auth.go b/mantle/vendor/github.com/godbus/dbus/v5/auth.go index 31abac629d..283487a0e3 100644 --- a/mantle/vendor/github.com/godbus/dbus/v5/auth.go +++ b/mantle/vendor/github.com/godbus/dbus/v5/auth.go @@ -37,7 +37,7 @@ const ( // Auth defines the behaviour of an authentication mechanism. type Auth interface { - // Return the name of the mechnism, the argument to the first AUTH command + // Return the name of the mechanism, the argument to the first AUTH command // and the next status. FirstData() (name, resp []byte, status AuthStatus) diff --git a/mantle/vendor/github.com/godbus/dbus/v5/call.go b/mantle/vendor/github.com/godbus/dbus/v5/call.go index 2cb189012e..b06b063580 100644 --- a/mantle/vendor/github.com/godbus/dbus/v5/call.go +++ b/mantle/vendor/github.com/godbus/dbus/v5/call.go @@ -24,6 +24,15 @@ type Call struct { // Holds the response once the call is done. Body []interface{} + // ResponseSequence stores the sequence number of the DBus message containing + // the call response (or error). This can be compared to the sequence number + // of other call responses and signals on this connection to determine their + // relative ordering on the underlying DBus connection. + // For errors, ResponseSequence is populated only if the error came from a + // DBusMessage that was received or if there was an error receiving. In case of + // failure to make the call, ResponseSequence will be NoSequence. + ResponseSequence Sequence + // tracks context and canceler ctx context.Context ctxCanceler context.CancelFunc diff --git a/mantle/vendor/github.com/godbus/dbus/v5/conn.go b/mantle/vendor/github.com/godbus/dbus/v5/conn.go index b55bc99c85..29fe018ad8 100644 --- a/mantle/vendor/github.com/godbus/dbus/v5/conn.go +++ b/mantle/vendor/github.com/godbus/dbus/v5/conn.go @@ -45,6 +45,7 @@ type Conn struct { serialGen SerialGenerator inInt Interceptor outInt Interceptor + auth []Auth names *nameTracker calls *callTracker @@ -59,7 +60,8 @@ type Conn struct { func SessionBus() (conn *Conn, err error) { sessionBusLck.Lock() defer sessionBusLck.Unlock() - if sessionBus != nil { + if sessionBus != nil && + sessionBus.Connected() { return sessionBus, nil } defer func() { @@ -67,19 +69,7 @@ func SessionBus() (conn *Conn, err error) { sessionBus = conn } }() - conn, err = SessionBusPrivate() - if err != nil { - return - } - if err = conn.Auth(nil); err != nil { - conn.Close() - conn = nil - return - } - if err = conn.Hello(); err != nil { - conn.Close() - conn = nil - } + conn, err = ConnectSessionBus() return } @@ -116,7 +106,8 @@ func SessionBusPrivateHandler(handler Handler, signalHandler SignalHandler) (*Co func SystemBus() (conn *Conn, err error) { systemBusLck.Lock() defer systemBusLck.Unlock() - if systemBus != nil { + if systemBus != nil && + systemBus.Connected() { return systemBus, nil } defer func() { @@ -124,20 +115,42 @@ func SystemBus() (conn *Conn, err error) { systemBus = conn } }() - conn, err = SystemBusPrivate() + conn, err = ConnectSystemBus() + return +} + +// ConnectSessionBus connects to the session bus. +func ConnectSessionBus(opts ...ConnOption) (*Conn, error) { + address, err := getSessionBusAddress() if err != nil { - return + return nil, err } - if err = conn.Auth(nil); err != nil { - conn.Close() - conn = nil - return + return Connect(address, opts...) +} + +// ConnectSystemBus connects to the system bus. +func ConnectSystemBus(opts ...ConnOption) (*Conn, error) { + return Connect(getSystemBusPlatformAddress(), opts...) +} + +// Connect connects to the given address. +// +// Returned connection is ready to use and doesn't require calling +// Auth and Hello methods to make it usable. +func Connect(address string, opts ...ConnOption) (*Conn, error) { + conn, err := Dial(address, opts...) + if err != nil { + return nil, err + } + if err = conn.Auth(conn.auth); err != nil { + _ = conn.Close() + return nil, err } if err = conn.Hello(); err != nil { - conn.Close() - conn = nil + _ = conn.Close() + return nil, err } - return + return conn, nil } // SystemBusPrivate returns a new private connection to the system bus. @@ -197,6 +210,14 @@ func WithSerialGenerator(gen SerialGenerator) ConnOption { } } +// WithAuth sets authentication methods for the auth conversation. +func WithAuth(methods ...Auth) ConnOption { + return func(conn *Conn) error { + conn.auth = methods + return nil + } +} + // Interceptor intercepts incoming and outgoing messages. type Interceptor func(msg *Message) @@ -309,6 +330,11 @@ func (conn *Conn) Context() context.Context { return conn.ctx } +// Connected returns whether conn is connected +func (conn *Conn) Connected() bool { + return conn.ctx.Err() == nil +} + // Eavesdrop causes conn to send all incoming messages to the given channel // without further processing. Method replies, errors and signals will not be // sent to the appropriate channels and method calls will not be handled. If nil @@ -342,8 +368,9 @@ func (conn *Conn) Hello() error { } // inWorker runs in an own goroutine, reading incoming messages from the -// transport and dispatching them appropiately. +// transport and dispatching them appropriately. func (conn *Conn) inWorker() { + sequenceGen := newSequenceGenerator() for { msg, err := conn.ReadMessage() if err != nil { @@ -352,7 +379,7 @@ func (conn *Conn) inWorker() { // anything but to shut down all stuff and returns errors to all // pending replies. conn.Close() - conn.calls.finalizeAllWithError(err) + conn.calls.finalizeAllWithError(sequenceGen, err) return } // invalid messages are ignored @@ -381,13 +408,14 @@ func (conn *Conn) inWorker() { if conn.inInt != nil { conn.inInt(msg) } + sequence := sequenceGen.next() switch msg.Type { case TypeError: - conn.serialGen.RetireSerial(conn.calls.handleDBusError(msg)) + conn.serialGen.RetireSerial(conn.calls.handleDBusError(sequence, msg)) case TypeMethodReply: - conn.serialGen.RetireSerial(conn.calls.handleReply(msg)) + conn.serialGen.RetireSerial(conn.calls.handleReply(sequence, msg)) case TypeSignal: - conn.handleSignal(msg) + conn.handleSignal(sequence, msg) case TypeMethodCall: go conn.handleCall(msg) } @@ -395,7 +423,7 @@ func (conn *Conn) inWorker() { } } -func (conn *Conn) handleSignal(msg *Message) { +func (conn *Conn) handleSignal(sequence Sequence, msg *Message) { iface := msg.Headers[FieldInterface].value.(string) member := msg.Headers[FieldMember].value.(string) // as per http://dbus.freedesktop.org/doc/dbus-specification.html , @@ -421,10 +449,11 @@ func (conn *Conn) handleSignal(msg *Message) { } } signal := &Signal{ - Sender: sender, - Path: msg.Headers[FieldPath].value.(ObjectPath), - Name: iface + "." + member, - Body: msg.Body, + Sender: sender, + Path: msg.Headers[FieldPath].value.(ObjectPath), + Name: iface + "." + member, + Body: msg.Body, + Sequence: sequence, } conn.signalHandler.DeliverSignal(iface, member, signal) } @@ -442,6 +471,9 @@ func (conn *Conn) Object(dest string, path ObjectPath) BusObject { } func (conn *Conn) sendMessageAndIfClosed(msg *Message, ifClosed func()) { + if msg.serial == 0 { + msg.serial = conn.getSerial() + } if conn.outInt != nil { conn.outInt(msg) } @@ -473,16 +505,16 @@ func (conn *Conn) send(ctx context.Context, msg *Message, ch chan *Call) *Call { if ctx == nil { panic("nil context") } + if ch == nil { + ch = make(chan *Call, 1) + } else if cap(ch) == 0 { + panic("dbus: unbuffered channel passed to (*Conn).Send") + } var call *Call ctx, canceler := context.WithCancel(ctx) msg.serial = conn.getSerial() if msg.Type == TypeMethodCall && msg.Flags&FlagNoReplyExpected == 0 { - if ch == nil { - ch = make(chan *Call, 5) - } else if cap(ch) == 0 { - panic("dbus: unbuffered channel passed to (*Conn).Send") - } call = new(Call) call.Destination, _ = msg.Headers[FieldDestination].value.(string) call.Path, _ = msg.Headers[FieldPath].value.(ObjectPath) @@ -504,7 +536,8 @@ func (conn *Conn) send(ctx context.Context, msg *Message, ch chan *Call) *Call { }) } else { canceler() - call = &Call{Err: nil} + call = &Call{Err: nil, Done: ch} + ch <- call conn.sendMessageAndIfClosed(msg, func() { call = &Call{Err: ErrClosed} }) @@ -529,7 +562,6 @@ func (conn *Conn) sendError(err error, dest string, serial uint32) { } msg := new(Message) msg.Type = TypeError - msg.serial = conn.getSerial() msg.Headers = make(map[HeaderField]Variant) if dest != "" { msg.Headers[FieldDestination] = MakeVariant(dest) @@ -548,7 +580,6 @@ func (conn *Conn) sendError(err error, dest string, serial uint32) { func (conn *Conn) sendReply(dest string, serial uint32, values ...interface{}) { msg := new(Message) msg.Type = TypeMethodReply - msg.serial = conn.getSerial() msg.Headers = make(map[HeaderField]Variant) if dest != "" { msg.Headers[FieldDestination] = MakeVariant(dest) @@ -564,8 +595,14 @@ func (conn *Conn) sendReply(dest string, serial uint32, values ...interface{}) { // AddMatchSignal registers the given match rule to receive broadcast // signals based on their contents. func (conn *Conn) AddMatchSignal(options ...MatchOption) error { + return conn.AddMatchSignalContext(context.Background(), options...) +} + +// AddMatchSignalContext acts like AddMatchSignal but takes a context. +func (conn *Conn) AddMatchSignalContext(ctx context.Context, options ...MatchOption) error { options = append([]MatchOption{withMatchType("signal")}, options...) - return conn.busObj.Call( + return conn.busObj.CallWithContext( + ctx, "org.freedesktop.DBus.AddMatch", 0, formatMatchOptions(options), ).Store() @@ -573,8 +610,14 @@ func (conn *Conn) AddMatchSignal(options ...MatchOption) error { // RemoveMatchSignal removes the first rule that matches previously registered with AddMatchSignal. func (conn *Conn) RemoveMatchSignal(options ...MatchOption) error { + return conn.RemoveMatchSignalContext(context.Background(), options...) +} + +// RemoveMatchSignalContext acts like RemoveMatchSignal but takes a context. +func (conn *Conn) RemoveMatchSignalContext(ctx context.Context, options ...MatchOption) error { options = append([]MatchOption{withMatchType("signal")}, options...) - return conn.busObj.Call( + return conn.busObj.CallWithContext( + ctx, "org.freedesktop.DBus.RemoveMatch", 0, formatMatchOptions(options), ).Store() @@ -639,10 +682,11 @@ func (e Error) Error() string { // Signal represents a D-Bus message of type Signal. The name member is given in // "interface.member" notation, e.g. org.freedesktop.D-Bus.NameLost. type Signal struct { - Sender string - Path ObjectPath - Name string - Body []interface{} + Sender string + Path ObjectPath + Name string + Body []interface{} + Sequence Sequence } // transport is a D-Bus transport. @@ -825,25 +869,25 @@ func (tracker *callTracker) track(sn uint32, call *Call) { tracker.lck.Unlock() } -func (tracker *callTracker) handleReply(msg *Message) uint32 { +func (tracker *callTracker) handleReply(sequence Sequence, msg *Message) uint32 { serial := msg.Headers[FieldReplySerial].value.(uint32) tracker.lck.RLock() _, ok := tracker.calls[serial] tracker.lck.RUnlock() if ok { - tracker.finalizeWithBody(serial, msg.Body) + tracker.finalizeWithBody(serial, sequence, msg.Body) } return serial } -func (tracker *callTracker) handleDBusError(msg *Message) uint32 { +func (tracker *callTracker) handleDBusError(sequence Sequence, msg *Message) uint32 { serial := msg.Headers[FieldReplySerial].value.(uint32) tracker.lck.RLock() _, ok := tracker.calls[serial] tracker.lck.RUnlock() if ok { name, _ := msg.Headers[FieldErrorName].value.(string) - tracker.finalizeWithError(serial, Error{name, msg.Body}) + tracker.finalizeWithError(serial, sequence, Error{name, msg.Body}) } return serial } @@ -856,7 +900,7 @@ func (tracker *callTracker) handleSendError(msg *Message, err error) { _, ok := tracker.calls[msg.serial] tracker.lck.RUnlock() if ok { - tracker.finalizeWithError(msg.serial, err) + tracker.finalizeWithError(msg.serial, NoSequence, err) } } @@ -871,7 +915,7 @@ func (tracker *callTracker) finalize(sn uint32) { } } -func (tracker *callTracker) finalizeWithBody(sn uint32, body []interface{}) { +func (tracker *callTracker) finalizeWithBody(sn uint32, sequence Sequence, body []interface{}) { tracker.lck.Lock() c, ok := tracker.calls[sn] if ok { @@ -880,11 +924,12 @@ func (tracker *callTracker) finalizeWithBody(sn uint32, body []interface{}) { tracker.lck.Unlock() if ok { c.Body = body + c.ResponseSequence = sequence c.done() } } -func (tracker *callTracker) finalizeWithError(sn uint32, err error) { +func (tracker *callTracker) finalizeWithError(sn uint32, sequence Sequence, err error) { tracker.lck.Lock() c, ok := tracker.calls[sn] if ok { @@ -893,11 +938,12 @@ func (tracker *callTracker) finalizeWithError(sn uint32, err error) { tracker.lck.Unlock() if ok { c.Err = err + c.ResponseSequence = sequence c.done() } } -func (tracker *callTracker) finalizeAllWithError(err error) { +func (tracker *callTracker) finalizeAllWithError(sequenceGen *sequenceGenerator, err error) { tracker.lck.Lock() closedCalls := make([]*Call, 0, len(tracker.calls)) for sn := range tracker.calls { @@ -907,6 +953,7 @@ func (tracker *callTracker) finalizeAllWithError(err error) { tracker.lck.Unlock() for _, call := range closedCalls { call.Err = err + call.ResponseSequence = sequenceGen.next() call.done() } } diff --git a/mantle/vendor/github.com/godbus/dbus/v5/dbus.go b/mantle/vendor/github.com/godbus/dbus/v5/dbus.go index 428923d266..ddf3b7afde 100644 --- a/mantle/vendor/github.com/godbus/dbus/v5/dbus.go +++ b/mantle/vendor/github.com/godbus/dbus/v5/dbus.go @@ -28,6 +28,7 @@ var ( interfaceType = reflect.TypeOf((*interface{})(nil)).Elem() unixFDType = reflect.TypeOf(UnixFD(0)) unixFDIndexType = reflect.TypeOf(UnixFDIndex(0)) + errType = reflect.TypeOf((*error)(nil)).Elem() ) // An InvalidTypeError signals that a value which cannot be represented in the @@ -63,6 +64,9 @@ func storeInterfaces(src, dest interface{}) error { func store(dest, src reflect.Value) error { if dest.Kind() == reflect.Ptr { + if dest.IsNil() { + dest.Set(reflect.New(dest.Type().Elem())) + } return store(dest.Elem(), src) } switch src.Kind() { diff --git a/mantle/vendor/github.com/godbus/dbus/v5/default_handler.go b/mantle/vendor/github.com/godbus/dbus/v5/default_handler.go index 6d8bf32f9f..13132c6b47 100644 --- a/mantle/vendor/github.com/godbus/dbus/v5/default_handler.go +++ b/mantle/vendor/github.com/godbus/dbus/v5/default_handler.go @@ -126,14 +126,28 @@ func (m exportedMethod) Call(args ...interface{}) ([]interface{}, error) { } ret := m.Value.Call(params) - - err := ret[t.NumOut()-1].Interface().(*Error) - ret = ret[:t.NumOut()-1] + var err error + nilErr := false // The reflection will find almost-nils, let's only pass back clean ones! + if t.NumOut() > 0 { + if e, ok := ret[t.NumOut()-1].Interface().(*Error); ok { // godbus *Error + nilErr = ret[t.NumOut()-1].IsNil() + ret = ret[:t.NumOut()-1] + err = e + } else if ret[t.NumOut()-1].Type().Implements(errType) { // Go error + i := ret[t.NumOut()-1].Interface() + if i == nil { + nilErr = ret[t.NumOut()-1].IsNil() + } else { + err = i.(error) + } + ret = ret[:t.NumOut()-1] + } + } out := make([]interface{}, len(ret)) for i, val := range ret { out[i] = val.Interface() } - if err == nil { + if nilErr || err == nil { //concrete type to interface nil is a special case return out, nil } diff --git a/mantle/vendor/github.com/godbus/dbus/v5/export.go b/mantle/vendor/github.com/godbus/dbus/v5/export.go index c277ab1426..2447b51d46 100644 --- a/mantle/vendor/github.com/godbus/dbus/v5/export.go +++ b/mantle/vendor/github.com/godbus/dbus/v5/export.go @@ -69,6 +69,22 @@ func getMethods(in interface{}, mapping map[string]string) map[string]reflect.Va return methods } +func getAllMethods(in interface{}, mapping map[string]string) map[string]reflect.Value { + if in == nil { + return nil + } + methods := make(map[string]reflect.Value) + val := reflect.ValueOf(in) + typ := val.Type() + for i := 0; i < typ.NumMethod(); i++ { + methtype := typ.Method(i) + method := val.Method(i) + // map names while building table + methods[computeMethodName(methtype.Name, mapping)] = method + } + return methods +} + func standardMethodArgumentDecode(m Method, sender string, msg *Message, body []interface{}) ([]interface{}, error) { pointers := make([]interface{}, m.NumArguments()) decode := make([]interface{}, 0, len(body)) @@ -159,7 +175,6 @@ func (conn *Conn) handleCall(msg *Message) { if msg.Flags&FlagNoReplyExpected == 0 { reply := new(Message) reply.Type = TypeMethodReply - reply.serial = conn.getSerial() reply.Headers = make(map[HeaderField]Variant) if hasSender { reply.Headers[FieldDestination] = msg.Headers[FieldSender] @@ -195,7 +210,6 @@ func (conn *Conn) Emit(path ObjectPath, name string, values ...interface{}) erro } msg := new(Message) msg.Type = TypeSignal - msg.serial = conn.getSerial() msg.Headers = make(map[HeaderField]Variant) msg.Headers[FieldInterface] = MakeVariant(iface) msg.Headers[FieldMember] = MakeVariant(member) @@ -247,6 +261,18 @@ func (conn *Conn) Export(v interface{}, path ObjectPath, iface string) error { return conn.ExportWithMap(v, nil, path, iface) } +// ExportAll registers all exported methods defined by the given object on +// the message bus. +// +// Unlike Export there is no requirement to have the last parameter as type +// *Error. If you want to be able to return error then you can append an error +// type parameter to your method signature. If the error returned is not nil, +// it is sent back to the caller as an error. Otherwise, a method reply is +// sent with the other return values as its body. +func (conn *Conn) ExportAll(v interface{}, path ObjectPath, iface string) error { + return conn.export(getAllMethods(v, nil), path, iface, false) +} + // ExportWithMap works exactly like Export but provides the ability to remap // method names (e.g. export a lower-case method). // @@ -299,19 +325,22 @@ func (conn *Conn) ExportSubtreeMethodTable(methods map[string]interface{}, path } func (conn *Conn) exportMethodTable(methods map[string]interface{}, path ObjectPath, iface string, includeSubtree bool) error { - out := make(map[string]reflect.Value) - for name, method := range methods { - rval := reflect.ValueOf(method) - if rval.Kind() != reflect.Func { - continue - } - t := rval.Type() - // only track valid methods must return *Error as last arg - if t.NumOut() == 0 || - t.Out(t.NumOut()-1) != reflect.TypeOf(&ErrMsgInvalidArg) { - continue + var out map[string]reflect.Value + if methods != nil { + out = make(map[string]reflect.Value) + for name, method := range methods { + rval := reflect.ValueOf(method) + if rval.Kind() != reflect.Func { + continue + } + t := rval.Type() + // only track valid methods must return *Error as last arg + if t.NumOut() == 0 || + t.Out(t.NumOut()-1) != reflect.TypeOf(&ErrMsgInvalidArg) { + continue + } + out[name] = rval } - out[name] = rval } return conn.export(out, path, iface, includeSubtree) } @@ -327,12 +356,12 @@ func (conn *Conn) unexport(h *defaultHandler, path ObjectPath, iface string) err return nil } -// exportWithMap is the worker function for all exports/registrations. +// export is the worker function for all exports/registrations. func (conn *Conn) export(methods map[string]reflect.Value, path ObjectPath, iface string, includeSubtree bool) error { h, ok := conn.handler.(*defaultHandler) if !ok { return fmt.Errorf( - `dbus: export only allowed on the default hander handler have %T"`, + `dbus: export only allowed on the default handler. Received: %T"`, conn.handler) } diff --git a/mantle/vendor/github.com/godbus/dbus/v5/match.go b/mantle/vendor/github.com/godbus/dbus/v5/match.go index 086ee336a9..5a607e53e4 100644 --- a/mantle/vendor/github.com/godbus/dbus/v5/match.go +++ b/mantle/vendor/github.com/godbus/dbus/v5/match.go @@ -1,6 +1,7 @@ package dbus import ( + "strconv" "strings" ) @@ -60,3 +61,29 @@ func WithMatchPathNamespace(namespace ObjectPath) MatchOption { func WithMatchDestination(destination string) MatchOption { return WithMatchOption("destination", destination) } + +// WithMatchArg sets argN match option, range of N is 0 to 63. +func WithMatchArg(argIdx int, value string) MatchOption { + if argIdx < 0 || argIdx > 63 { + panic("range of argument index is 0 to 63") + } + return WithMatchOption("arg"+strconv.Itoa(argIdx), value) +} + +// WithMatchArgPath sets argN path match option, range of N is 0 to 63. +func WithMatchArgPath(argIdx int, path string) MatchOption { + if argIdx < 0 || argIdx > 63 { + panic("range of argument index is 0 to 63") + } + return WithMatchOption("arg"+strconv.Itoa(argIdx)+"path", path) +} + +// WithMatchArg0Namespace sets arg0namespace match option. +func WithMatchArg0Namespace(arg0Namespace string) MatchOption { + return WithMatchOption("arg0namespace", arg0Namespace) +} + +// WithMatchEavesdrop sets eavesdrop match option. +func WithMatchEavesdrop(eavesdrop bool) MatchOption { + return WithMatchOption("eavesdrop", strconv.FormatBool(eavesdrop)) +} diff --git a/mantle/vendor/github.com/godbus/dbus/v5/object.go b/mantle/vendor/github.com/godbus/dbus/v5/object.go index 8acd7fc8b1..664abb7fba 100644 --- a/mantle/vendor/github.com/godbus/dbus/v5/object.go +++ b/mantle/vendor/github.com/godbus/dbus/v5/object.go @@ -16,6 +16,7 @@ type BusObject interface { AddMatchSignal(iface, member string, options ...MatchOption) *Call RemoveMatchSignal(iface, member string, options ...MatchOption) *Call GetProperty(p string) (Variant, error) + StoreProperty(p string, value interface{}) error SetProperty(p string, v interface{}) error Destination() string Path() ObjectPath @@ -109,7 +110,6 @@ func (o *Object) createCall(ctx context.Context, method string, flags Flags, ch method = method[i+1:] msg := new(Message) msg.Type = TypeMethodCall - msg.serial = o.conn.getSerial() msg.Flags = flags & (FlagNoAutoStart | FlagNoReplyExpected) msg.Headers = make(map[HeaderField]Variant) msg.Headers[FieldPath] = MakeVariant(o.path) @@ -122,68 +122,31 @@ func (o *Object) createCall(ctx context.Context, method string, flags Flags, ch if len(args) > 0 { msg.Headers[FieldSignature] = MakeVariant(SignatureOf(args...)) } - if msg.Flags&FlagNoReplyExpected == 0 { - if ch == nil { - ch = make(chan *Call, 1) - } else if cap(ch) == 0 { - panic("dbus: unbuffered channel passed to (*Object).Go") - } - ctx, cancel := context.WithCancel(ctx) - call := &Call{ - Destination: o.dest, - Path: o.path, - Method: method, - Args: args, - Done: ch, - ctxCanceler: cancel, - ctx: ctx, - } - o.conn.calls.track(msg.serial, call) - o.conn.sendMessageAndIfClosed(msg, func() { - o.conn.calls.handleSendError(msg, ErrClosed) - cancel() - }) - go func() { - <-ctx.Done() - o.conn.calls.handleSendError(msg, ctx.Err()) - }() - - return call - } - done := make(chan *Call, 1) - call := &Call{ - Err: nil, - Done: done, - } - defer func() { - call.Done <- call - close(done) - }() - o.conn.sendMessageAndIfClosed(msg, func() { - call.Err = ErrClosed - }) - return call + return o.conn.SendWithContext(ctx, msg, ch) } // GetProperty calls org.freedesktop.DBus.Properties.Get on the given // object. The property name must be given in interface.member notation. func (o *Object) GetProperty(p string) (Variant, error) { + var result Variant + err := o.StoreProperty(p, &result) + return result, err +} + +// StoreProperty calls org.freedesktop.DBus.Properties.Get on the given +// object. The property name must be given in interface.member notation. +// It stores the returned property into the provided value. +func (o *Object) StoreProperty(p string, value interface{}) error { idx := strings.LastIndex(p, ".") if idx == -1 || idx+1 == len(p) { - return Variant{}, errors.New("dbus: invalid property " + p) + return errors.New("dbus: invalid property " + p) } iface := p[:idx] prop := p[idx+1:] - result := Variant{} - err := o.Call("org.freedesktop.DBus.Properties.Get", 0, iface, prop).Store(&result) - - if err != nil { - return Variant{}, err - } - - return result, nil + return o.Call("org.freedesktop.DBus.Properties.Get", 0, iface, prop). + Store(value) } // SetProperty calls org.freedesktop.DBus.Properties.Set on the given diff --git a/mantle/vendor/github.com/godbus/dbus/v5/sequence.go b/mantle/vendor/github.com/godbus/dbus/v5/sequence.go new file mode 100644 index 0000000000..89435d3933 --- /dev/null +++ b/mantle/vendor/github.com/godbus/dbus/v5/sequence.go @@ -0,0 +1,24 @@ +package dbus + +// Sequence represents the value of a monotonically increasing counter. +type Sequence uint64 + +const ( + // NoSequence indicates the absence of a sequence value. + NoSequence Sequence = 0 +) + +// sequenceGenerator represents a monotonically increasing counter. +type sequenceGenerator struct { + nextSequence Sequence +} + +func (generator *sequenceGenerator) next() Sequence { + result := generator.nextSequence + generator.nextSequence++ + return result +} + +func newSequenceGenerator() *sequenceGenerator { + return &sequenceGenerator{nextSequence: 1} +} diff --git a/mantle/vendor/github.com/godbus/dbus/v5/sequential_handler.go b/mantle/vendor/github.com/godbus/dbus/v5/sequential_handler.go new file mode 100644 index 0000000000..ef2fcdba17 --- /dev/null +++ b/mantle/vendor/github.com/godbus/dbus/v5/sequential_handler.go @@ -0,0 +1,125 @@ +package dbus + +import ( + "sync" +) + +// NewSequentialSignalHandler returns an instance of a new +// signal handler that guarantees sequential processing of signals. It is a +// guarantee of this signal handler that signals will be written to +// channels in the order they are received on the DBus connection. +func NewSequentialSignalHandler() SignalHandler { + return &sequentialSignalHandler{} +} + +type sequentialSignalHandler struct { + mu sync.RWMutex + closed bool + signals []*sequentialSignalChannelData +} + +func (sh *sequentialSignalHandler) DeliverSignal(intf, name string, signal *Signal) { + sh.mu.RLock() + defer sh.mu.RUnlock() + if sh.closed { + return + } + for _, scd := range sh.signals { + scd.deliver(signal) + } +} + +func (sh *sequentialSignalHandler) Terminate() { + sh.mu.Lock() + defer sh.mu.Unlock() + if sh.closed { + return + } + + for _, scd := range sh.signals { + scd.close() + close(scd.ch) + } + sh.closed = true + sh.signals = nil +} + +func (sh *sequentialSignalHandler) AddSignal(ch chan<- *Signal) { + sh.mu.Lock() + defer sh.mu.Unlock() + if sh.closed { + return + } + sh.signals = append(sh.signals, newSequentialSignalChannelData(ch)) +} + +func (sh *sequentialSignalHandler) RemoveSignal(ch chan<- *Signal) { + sh.mu.Lock() + defer sh.mu.Unlock() + if sh.closed { + return + } + for i := len(sh.signals) - 1; i >= 0; i-- { + if ch == sh.signals[i].ch { + sh.signals[i].close() + copy(sh.signals[i:], sh.signals[i+1:]) + sh.signals[len(sh.signals)-1] = nil + sh.signals = sh.signals[:len(sh.signals)-1] + } + } +} + +type sequentialSignalChannelData struct { + ch chan<- *Signal + in chan *Signal + done chan struct{} +} + +func newSequentialSignalChannelData(ch chan<- *Signal) *sequentialSignalChannelData { + scd := &sequentialSignalChannelData{ + ch: ch, + in: make(chan *Signal), + done: make(chan struct{}), + } + go scd.bufferSignals() + return scd +} + +func (scd *sequentialSignalChannelData) bufferSignals() { + defer close(scd.done) + + // Ensure that signals are delivered to scd.ch in the same + // order they are received from scd.in. + var queue []*Signal + for { + if len(queue) == 0 { + signal, ok := <- scd.in + if !ok { + return + } + queue = append(queue, signal) + } + select { + case scd.ch <- queue[0]: + copy(queue, queue[1:]) + queue[len(queue)-1] = nil + queue = queue[:len(queue)-1] + case signal, ok := <-scd.in: + if !ok { + return + } + queue = append(queue, signal) + } + } +} + +func (scd *sequentialSignalChannelData) deliver(signal *Signal) { + scd.in <- signal +} + +func (scd *sequentialSignalChannelData) close() { + close(scd.in) + // Ensure that bufferSignals() has exited and won't attempt + // any future sends on scd.ch + <-scd.done +} diff --git a/mantle/vendor/github.com/godbus/dbus/v5/sig.go b/mantle/vendor/github.com/godbus/dbus/v5/sig.go index c1b809202c..2d326cebc0 100644 --- a/mantle/vendor/github.com/godbus/dbus/v5/sig.go +++ b/mantle/vendor/github.com/godbus/dbus/v5/sig.go @@ -137,7 +137,7 @@ func ParseSignatureMust(s string) Signature { return sig } -// Empty retruns whether the signature is the empty signature. +// Empty returns whether the signature is the empty signature. func (s Signature) Empty() bool { return s.str == "" } diff --git a/mantle/vendor/github.com/godbus/dbus/v5/transport_unixcred_freebsd.go b/mantle/vendor/github.com/godbus/dbus/v5/transport_unixcred_freebsd.go index 0fc5b92739..1b5ed2089d 100644 --- a/mantle/vendor/github.com/godbus/dbus/v5/transport_unixcred_freebsd.go +++ b/mantle/vendor/github.com/godbus/dbus/v5/transport_unixcred_freebsd.go @@ -10,6 +10,7 @@ package dbus /* const int sizeofPtr = sizeof(void*); #define _WANT_UCRED +#include #include */ import "C" diff --git a/mantle/vendor/github.com/godbus/dbus/v5/variant.go b/mantle/vendor/github.com/godbus/dbus/v5/variant.go index 5b51828c82..f1e81f3ede 100644 --- a/mantle/vendor/github.com/godbus/dbus/v5/variant.go +++ b/mantle/vendor/github.com/godbus/dbus/v5/variant.go @@ -142,3 +142,9 @@ func (v Variant) String() string { func (v Variant) Value() interface{} { return v.value } + +// Store converts the variant into a native go type using the same +// mechanism as the "Store" function. +func (v Variant) Store(value interface{}) error { + return storeInterfaces(v.value, value) +} diff --git a/mantle/vendor/github.com/stretchr/testify/assert/assertion_compare.go b/mantle/vendor/github.com/stretchr/testify/assert/assertion_compare.go index 41649d2679..95d8e59da6 100644 --- a/mantle/vendor/github.com/stretchr/testify/assert/assertion_compare.go +++ b/mantle/vendor/github.com/stretchr/testify/assert/assertion_compare.go @@ -1,8 +1,10 @@ package assert import ( + "bytes" "fmt" "reflect" + "time" ) type CompareType int @@ -30,6 +32,9 @@ var ( float64Type = reflect.TypeOf(float64(1)) stringType = reflect.TypeOf("") + + timeType = reflect.TypeOf(time.Time{}) + bytesType = reflect.TypeOf([]byte{}) ) func compare(obj1, obj2 interface{}, kind reflect.Kind) (CompareType, bool) { @@ -299,6 +304,47 @@ func compare(obj1, obj2 interface{}, kind reflect.Kind) (CompareType, bool) { return compareLess, true } } + // Check for known struct types we can check for compare results. + case reflect.Struct: + { + // All structs enter here. We're not interested in most types. + if !canConvert(obj1Value, timeType) { + break + } + + // time.Time can compared! + timeObj1, ok := obj1.(time.Time) + if !ok { + timeObj1 = obj1Value.Convert(timeType).Interface().(time.Time) + } + + timeObj2, ok := obj2.(time.Time) + if !ok { + timeObj2 = obj2Value.Convert(timeType).Interface().(time.Time) + } + + return compare(timeObj1.UnixNano(), timeObj2.UnixNano(), reflect.Int64) + } + case reflect.Slice: + { + // We only care about the []byte type. + if !canConvert(obj1Value, bytesType) { + break + } + + // []byte can be compared! + bytesObj1, ok := obj1.([]byte) + if !ok { + bytesObj1 = obj1Value.Convert(bytesType).Interface().([]byte) + + } + bytesObj2, ok := obj2.([]byte) + if !ok { + bytesObj2 = obj2Value.Convert(bytesType).Interface().([]byte) + } + + return CompareType(bytes.Compare(bytesObj1, bytesObj2)), true + } } return compareEqual, false @@ -310,7 +356,10 @@ func compare(obj1, obj2 interface{}, kind reflect.Kind) (CompareType, bool) { // assert.Greater(t, float64(2), float64(1)) // assert.Greater(t, "b", "a") func Greater(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { - return compareTwoValues(t, e1, e2, []CompareType{compareGreater}, "\"%v\" is not greater than \"%v\"", msgAndArgs) + if h, ok := t.(tHelper); ok { + h.Helper() + } + return compareTwoValues(t, e1, e2, []CompareType{compareGreater}, "\"%v\" is not greater than \"%v\"", msgAndArgs...) } // GreaterOrEqual asserts that the first element is greater than or equal to the second @@ -320,7 +369,10 @@ func Greater(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface // assert.GreaterOrEqual(t, "b", "a") // assert.GreaterOrEqual(t, "b", "b") func GreaterOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { - return compareTwoValues(t, e1, e2, []CompareType{compareGreater, compareEqual}, "\"%v\" is not greater than or equal to \"%v\"", msgAndArgs) + if h, ok := t.(tHelper); ok { + h.Helper() + } + return compareTwoValues(t, e1, e2, []CompareType{compareGreater, compareEqual}, "\"%v\" is not greater than or equal to \"%v\"", msgAndArgs...) } // Less asserts that the first element is less than the second @@ -329,7 +381,10 @@ func GreaterOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...in // assert.Less(t, float64(1), float64(2)) // assert.Less(t, "a", "b") func Less(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { - return compareTwoValues(t, e1, e2, []CompareType{compareLess}, "\"%v\" is not less than \"%v\"", msgAndArgs) + if h, ok := t.(tHelper); ok { + h.Helper() + } + return compareTwoValues(t, e1, e2, []CompareType{compareLess}, "\"%v\" is not less than \"%v\"", msgAndArgs...) } // LessOrEqual asserts that the first element is less than or equal to the second @@ -339,7 +394,10 @@ func Less(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) // assert.LessOrEqual(t, "a", "b") // assert.LessOrEqual(t, "b", "b") func LessOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { - return compareTwoValues(t, e1, e2, []CompareType{compareLess, compareEqual}, "\"%v\" is not less than or equal to \"%v\"", msgAndArgs) + if h, ok := t.(tHelper); ok { + h.Helper() + } + return compareTwoValues(t, e1, e2, []CompareType{compareLess, compareEqual}, "\"%v\" is not less than or equal to \"%v\"", msgAndArgs...) } // Positive asserts that the specified element is positive @@ -347,8 +405,11 @@ func LessOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...inter // assert.Positive(t, 1) // assert.Positive(t, 1.23) func Positive(t TestingT, e interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } zero := reflect.Zero(reflect.TypeOf(e)) - return compareTwoValues(t, e, zero.Interface(), []CompareType{compareGreater}, "\"%v\" is not positive", msgAndArgs) + return compareTwoValues(t, e, zero.Interface(), []CompareType{compareGreater}, "\"%v\" is not positive", msgAndArgs...) } // Negative asserts that the specified element is negative @@ -356,8 +417,11 @@ func Positive(t TestingT, e interface{}, msgAndArgs ...interface{}) bool { // assert.Negative(t, -1) // assert.Negative(t, -1.23) func Negative(t TestingT, e interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } zero := reflect.Zero(reflect.TypeOf(e)) - return compareTwoValues(t, e, zero.Interface(), []CompareType{compareLess}, "\"%v\" is not negative", msgAndArgs) + return compareTwoValues(t, e, zero.Interface(), []CompareType{compareLess}, "\"%v\" is not negative", msgAndArgs...) } func compareTwoValues(t TestingT, e1 interface{}, e2 interface{}, allowedComparesResults []CompareType, failMessage string, msgAndArgs ...interface{}) bool { diff --git a/mantle/vendor/github.com/stretchr/testify/assert/assertion_compare_can_convert.go b/mantle/vendor/github.com/stretchr/testify/assert/assertion_compare_can_convert.go new file mode 100644 index 0000000000..da867903e2 --- /dev/null +++ b/mantle/vendor/github.com/stretchr/testify/assert/assertion_compare_can_convert.go @@ -0,0 +1,16 @@ +//go:build go1.17 +// +build go1.17 + +// TODO: once support for Go 1.16 is dropped, this file can be +// merged/removed with assertion_compare_go1.17_test.go and +// assertion_compare_legacy.go + +package assert + +import "reflect" + +// Wrapper around reflect.Value.CanConvert, for compatibility +// reasons. +func canConvert(value reflect.Value, to reflect.Type) bool { + return value.CanConvert(to) +} diff --git a/mantle/vendor/github.com/stretchr/testify/assert/assertion_compare_legacy.go b/mantle/vendor/github.com/stretchr/testify/assert/assertion_compare_legacy.go new file mode 100644 index 0000000000..1701af2a3c --- /dev/null +++ b/mantle/vendor/github.com/stretchr/testify/assert/assertion_compare_legacy.go @@ -0,0 +1,16 @@ +//go:build !go1.17 +// +build !go1.17 + +// TODO: once support for Go 1.16 is dropped, this file can be +// merged/removed with assertion_compare_go1.17_test.go and +// assertion_compare_can_convert.go + +package assert + +import "reflect" + +// Older versions of Go does not have the reflect.Value.CanConvert +// method. +func canConvert(value reflect.Value, to reflect.Type) bool { + return false +} diff --git a/mantle/vendor/github.com/stretchr/testify/assert/assertion_format.go b/mantle/vendor/github.com/stretchr/testify/assert/assertion_format.go index 4dfd1229a8..7880b8f943 100644 --- a/mantle/vendor/github.com/stretchr/testify/assert/assertion_format.go +++ b/mantle/vendor/github.com/stretchr/testify/assert/assertion_format.go @@ -123,6 +123,18 @@ func ErrorAsf(t TestingT, err error, target interface{}, msg string, args ...int return ErrorAs(t, err, target, append([]interface{}{msg}, args...)...) } +// ErrorContainsf asserts that a function returned an error (i.e. not `nil`) +// and that the error contains the specified substring. +// +// actualObj, err := SomeFunction() +// assert.ErrorContainsf(t, err, expectedErrorSubString, "error message %s", "formatted") +func ErrorContainsf(t TestingT, theError error, contains string, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return ErrorContains(t, theError, contains, append([]interface{}{msg}, args...)...) +} + // ErrorIsf asserts that at least one of the errors in err's chain matches target. // This is a wrapper for errors.Is. func ErrorIsf(t TestingT, err error, target error, msg string, args ...interface{}) bool { @@ -724,6 +736,16 @@ func WithinDurationf(t TestingT, expected time.Time, actual time.Time, delta tim return WithinDuration(t, expected, actual, delta, append([]interface{}{msg}, args...)...) } +// WithinRangef asserts that a time is within a time range (inclusive). +// +// assert.WithinRangef(t, time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second), "error message %s", "formatted") +func WithinRangef(t TestingT, actual time.Time, start time.Time, end time.Time, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return WithinRange(t, actual, start, end, append([]interface{}{msg}, args...)...) +} + // YAMLEqf asserts that two YAML strings are equivalent. func YAMLEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { diff --git a/mantle/vendor/github.com/stretchr/testify/assert/assertion_forward.go b/mantle/vendor/github.com/stretchr/testify/assert/assertion_forward.go index 25337a6f07..339515b8bf 100644 --- a/mantle/vendor/github.com/stretchr/testify/assert/assertion_forward.go +++ b/mantle/vendor/github.com/stretchr/testify/assert/assertion_forward.go @@ -222,6 +222,30 @@ func (a *Assertions) ErrorAsf(err error, target interface{}, msg string, args .. return ErrorAsf(a.t, err, target, msg, args...) } +// ErrorContains asserts that a function returned an error (i.e. not `nil`) +// and that the error contains the specified substring. +// +// actualObj, err := SomeFunction() +// a.ErrorContains(err, expectedErrorSubString) +func (a *Assertions) ErrorContains(theError error, contains string, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return ErrorContains(a.t, theError, contains, msgAndArgs...) +} + +// ErrorContainsf asserts that a function returned an error (i.e. not `nil`) +// and that the error contains the specified substring. +// +// actualObj, err := SomeFunction() +// a.ErrorContainsf(err, expectedErrorSubString, "error message %s", "formatted") +func (a *Assertions) ErrorContainsf(theError error, contains string, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return ErrorContainsf(a.t, theError, contains, msg, args...) +} + // ErrorIs asserts that at least one of the errors in err's chain matches target. // This is a wrapper for errors.Is. func (a *Assertions) ErrorIs(err error, target error, msgAndArgs ...interface{}) bool { @@ -1437,6 +1461,26 @@ func (a *Assertions) WithinDurationf(expected time.Time, actual time.Time, delta return WithinDurationf(a.t, expected, actual, delta, msg, args...) } +// WithinRange asserts that a time is within a time range (inclusive). +// +// a.WithinRange(time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second)) +func (a *Assertions) WithinRange(actual time.Time, start time.Time, end time.Time, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return WithinRange(a.t, actual, start, end, msgAndArgs...) +} + +// WithinRangef asserts that a time is within a time range (inclusive). +// +// a.WithinRangef(time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second), "error message %s", "formatted") +func (a *Assertions) WithinRangef(actual time.Time, start time.Time, end time.Time, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return WithinRangef(a.t, actual, start, end, msg, args...) +} + // YAMLEq asserts that two YAML strings are equivalent. func (a *Assertions) YAMLEq(expected string, actual string, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { diff --git a/mantle/vendor/github.com/stretchr/testify/assert/assertion_order.go b/mantle/vendor/github.com/stretchr/testify/assert/assertion_order.go index 1c3b47182a..7594487835 100644 --- a/mantle/vendor/github.com/stretchr/testify/assert/assertion_order.go +++ b/mantle/vendor/github.com/stretchr/testify/assert/assertion_order.go @@ -50,7 +50,7 @@ func isOrdered(t TestingT, object interface{}, allowedComparesResults []CompareT // assert.IsIncreasing(t, []float{1, 2}) // assert.IsIncreasing(t, []string{"a", "b"}) func IsIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { - return isOrdered(t, object, []CompareType{compareLess}, "\"%v\" is not less than \"%v\"", msgAndArgs) + return isOrdered(t, object, []CompareType{compareLess}, "\"%v\" is not less than \"%v\"", msgAndArgs...) } // IsNonIncreasing asserts that the collection is not increasing @@ -59,7 +59,7 @@ func IsIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) boo // assert.IsNonIncreasing(t, []float{2, 1}) // assert.IsNonIncreasing(t, []string{"b", "a"}) func IsNonIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { - return isOrdered(t, object, []CompareType{compareEqual, compareGreater}, "\"%v\" is not greater than or equal to \"%v\"", msgAndArgs) + return isOrdered(t, object, []CompareType{compareEqual, compareGreater}, "\"%v\" is not greater than or equal to \"%v\"", msgAndArgs...) } // IsDecreasing asserts that the collection is decreasing @@ -68,7 +68,7 @@ func IsNonIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) // assert.IsDecreasing(t, []float{2, 1}) // assert.IsDecreasing(t, []string{"b", "a"}) func IsDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { - return isOrdered(t, object, []CompareType{compareGreater}, "\"%v\" is not greater than \"%v\"", msgAndArgs) + return isOrdered(t, object, []CompareType{compareGreater}, "\"%v\" is not greater than \"%v\"", msgAndArgs...) } // IsNonDecreasing asserts that the collection is not decreasing @@ -77,5 +77,5 @@ func IsDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) boo // assert.IsNonDecreasing(t, []float{1, 2}) // assert.IsNonDecreasing(t, []string{"a", "b"}) func IsNonDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { - return isOrdered(t, object, []CompareType{compareLess, compareEqual}, "\"%v\" is not less than or equal to \"%v\"", msgAndArgs) + return isOrdered(t, object, []CompareType{compareLess, compareEqual}, "\"%v\" is not less than or equal to \"%v\"", msgAndArgs...) } diff --git a/mantle/vendor/github.com/stretchr/testify/assert/assertions.go b/mantle/vendor/github.com/stretchr/testify/assert/assertions.go index bcac4401f5..fa1245b189 100644 --- a/mantle/vendor/github.com/stretchr/testify/assert/assertions.go +++ b/mantle/vendor/github.com/stretchr/testify/assert/assertions.go @@ -8,6 +8,7 @@ import ( "fmt" "math" "os" + "path/filepath" "reflect" "regexp" "runtime" @@ -144,7 +145,8 @@ func CallerInfo() []string { if len(parts) > 1 { dir := parts[len(parts)-2] if (dir != "assert" && dir != "mock" && dir != "require") || file == "mock_test.go" { - callers = append(callers, fmt.Sprintf("%s:%d", file, line)) + path, _ := filepath.Abs(file) + callers = append(callers, fmt.Sprintf("%s:%d", path, line)) } } @@ -563,16 +565,17 @@ func isEmpty(object interface{}) bool { switch objValue.Kind() { // collection types are empty when they have no element - case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice: + case reflect.Chan, reflect.Map, reflect.Slice: return objValue.Len() == 0 - // pointers are empty if nil or if the value they point to is empty + // pointers are empty if nil or if the value they point to is empty case reflect.Ptr: if objValue.IsNil() { return true } deref := objValue.Elem().Interface() return isEmpty(deref) - // for all other types, compare against the zero value + // for all other types, compare against the zero value + // array types are empty when they match their zero-initialized state default: zero := reflect.Zero(objValue.Type()) return reflect.DeepEqual(object, zero.Interface()) @@ -718,10 +721,14 @@ func NotEqualValues(t TestingT, expected, actual interface{}, msgAndArgs ...inte // return (false, false) if impossible. // return (true, false) if element was not found. // return (true, true) if element was found. -func includeElement(list interface{}, element interface{}) (ok, found bool) { +func containsElement(list interface{}, element interface{}) (ok, found bool) { listValue := reflect.ValueOf(list) - listKind := reflect.TypeOf(list).Kind() + listType := reflect.TypeOf(list) + if listType == nil { + return false, false + } + listKind := listType.Kind() defer func() { if e := recover(); e != nil { ok = false @@ -764,7 +771,7 @@ func Contains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bo h.Helper() } - ok, found := includeElement(s, contains) + ok, found := containsElement(s, contains) if !ok { return Fail(t, fmt.Sprintf("%#v could not be applied builtin len()", s), msgAndArgs...) } @@ -787,7 +794,7 @@ func NotContains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) h.Helper() } - ok, found := includeElement(s, contains) + ok, found := containsElement(s, contains) if !ok { return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", s), msgAndArgs...) } @@ -811,7 +818,6 @@ func Subset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok return true // we consider nil to be equal to the nil set } - subsetValue := reflect.ValueOf(subset) defer func() { if e := recover(); e != nil { ok = false @@ -821,17 +827,35 @@ func Subset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok listKind := reflect.TypeOf(list).Kind() subsetKind := reflect.TypeOf(subset).Kind() - if listKind != reflect.Array && listKind != reflect.Slice { + if listKind != reflect.Array && listKind != reflect.Slice && listKind != reflect.Map { return Fail(t, fmt.Sprintf("%q has an unsupported type %s", list, listKind), msgAndArgs...) } - if subsetKind != reflect.Array && subsetKind != reflect.Slice { + if subsetKind != reflect.Array && subsetKind != reflect.Slice && listKind != reflect.Map { return Fail(t, fmt.Sprintf("%q has an unsupported type %s", subset, subsetKind), msgAndArgs...) } + subsetValue := reflect.ValueOf(subset) + if subsetKind == reflect.Map && listKind == reflect.Map { + listValue := reflect.ValueOf(list) + subsetKeys := subsetValue.MapKeys() + + for i := 0; i < len(subsetKeys); i++ { + subsetKey := subsetKeys[i] + subsetElement := subsetValue.MapIndex(subsetKey).Interface() + listElement := listValue.MapIndex(subsetKey).Interface() + + if !ObjectsAreEqual(subsetElement, listElement) { + return Fail(t, fmt.Sprintf("\"%s\" does not contain \"%s\"", list, subsetElement), msgAndArgs...) + } + } + + return true + } + for i := 0; i < subsetValue.Len(); i++ { element := subsetValue.Index(i).Interface() - ok, found := includeElement(list, element) + ok, found := containsElement(list, element) if !ok { return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", list), msgAndArgs...) } @@ -852,10 +876,9 @@ func NotSubset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) h.Helper() } if subset == nil { - return Fail(t, fmt.Sprintf("nil is the empty set which is a subset of every set"), msgAndArgs...) + return Fail(t, "nil is the empty set which is a subset of every set", msgAndArgs...) } - subsetValue := reflect.ValueOf(subset) defer func() { if e := recover(); e != nil { ok = false @@ -865,17 +888,35 @@ func NotSubset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) listKind := reflect.TypeOf(list).Kind() subsetKind := reflect.TypeOf(subset).Kind() - if listKind != reflect.Array && listKind != reflect.Slice { + if listKind != reflect.Array && listKind != reflect.Slice && listKind != reflect.Map { return Fail(t, fmt.Sprintf("%q has an unsupported type %s", list, listKind), msgAndArgs...) } - if subsetKind != reflect.Array && subsetKind != reflect.Slice { + if subsetKind != reflect.Array && subsetKind != reflect.Slice && listKind != reflect.Map { return Fail(t, fmt.Sprintf("%q has an unsupported type %s", subset, subsetKind), msgAndArgs...) } + subsetValue := reflect.ValueOf(subset) + if subsetKind == reflect.Map && listKind == reflect.Map { + listValue := reflect.ValueOf(list) + subsetKeys := subsetValue.MapKeys() + + for i := 0; i < len(subsetKeys); i++ { + subsetKey := subsetKeys[i] + subsetElement := subsetValue.MapIndex(subsetKey).Interface() + listElement := listValue.MapIndex(subsetKey).Interface() + + if !ObjectsAreEqual(subsetElement, listElement) { + return true + } + } + + return Fail(t, fmt.Sprintf("%q is a subset of %q", subset, list), msgAndArgs...) + } + for i := 0; i < subsetValue.Len(); i++ { element := subsetValue.Index(i).Interface() - ok, found := includeElement(list, element) + ok, found := containsElement(list, element) if !ok { return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", list), msgAndArgs...) } @@ -1000,27 +1041,21 @@ func Condition(t TestingT, comp Comparison, msgAndArgs ...interface{}) bool { type PanicTestFunc func() // didPanic returns true if the function passed to it panics. Otherwise, it returns false. -func didPanic(f PanicTestFunc) (bool, interface{}, string) { - - didPanic := false - var message interface{} - var stack string - func() { - - defer func() { - if message = recover(); message != nil { - didPanic = true - stack = string(debug.Stack()) - } - }() - - // call the target function - f() +func didPanic(f PanicTestFunc) (didPanic bool, message interface{}, stack string) { + didPanic = true + defer func() { + message = recover() + if didPanic { + stack = string(debug.Stack()) + } }() - return didPanic, message, stack + // call the target function + f() + didPanic = false + return } // Panics asserts that the code inside the specified PanicTestFunc panics. @@ -1111,6 +1146,27 @@ func WithinDuration(t TestingT, expected, actual time.Time, delta time.Duration, return true } +// WithinRange asserts that a time is within a time range (inclusive). +// +// assert.WithinRange(t, time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second)) +func WithinRange(t TestingT, actual, start, end time.Time, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + + if end.Before(start) { + return Fail(t, "Start should be before end", msgAndArgs...) + } + + if actual.Before(start) { + return Fail(t, fmt.Sprintf("Time %v expected to be in time range %v to %v, but is before the range", actual, start, end), msgAndArgs...) + } else if actual.After(end) { + return Fail(t, fmt.Sprintf("Time %v expected to be in time range %v to %v, but is after the range", actual, start, end), msgAndArgs...) + } + + return true +} + func toFloat(x interface{}) (float64, bool) { var xf float64 xok := true @@ -1161,11 +1217,15 @@ func InDelta(t TestingT, expected, actual interface{}, delta float64, msgAndArgs bf, bok := toFloat(actual) if !aok || !bok { - return Fail(t, fmt.Sprintf("Parameters must be numerical"), msgAndArgs...) + return Fail(t, "Parameters must be numerical", msgAndArgs...) + } + + if math.IsNaN(af) && math.IsNaN(bf) { + return true } if math.IsNaN(af) { - return Fail(t, fmt.Sprintf("Expected must not be NaN"), msgAndArgs...) + return Fail(t, "Expected must not be NaN", msgAndArgs...) } if math.IsNaN(bf) { @@ -1188,7 +1248,7 @@ func InDeltaSlice(t TestingT, expected, actual interface{}, delta float64, msgAn if expected == nil || actual == nil || reflect.TypeOf(actual).Kind() != reflect.Slice || reflect.TypeOf(expected).Kind() != reflect.Slice { - return Fail(t, fmt.Sprintf("Parameters must be slice"), msgAndArgs...) + return Fail(t, "Parameters must be slice", msgAndArgs...) } actualSlice := reflect.ValueOf(actual) @@ -1250,8 +1310,12 @@ func InDeltaMapValues(t TestingT, expected, actual interface{}, delta float64, m func calcRelativeError(expected, actual interface{}) (float64, error) { af, aok := toFloat(expected) - if !aok { - return 0, fmt.Errorf("expected value %q cannot be converted to float", expected) + bf, bok := toFloat(actual) + if !aok || !bok { + return 0, fmt.Errorf("Parameters must be numerical") + } + if math.IsNaN(af) && math.IsNaN(bf) { + return 0, nil } if math.IsNaN(af) { return 0, errors.New("expected value must not be NaN") @@ -1259,10 +1323,6 @@ func calcRelativeError(expected, actual interface{}) (float64, error) { if af == 0 { return 0, fmt.Errorf("expected value must have a value other than zero to calculate the relative error") } - bf, bok := toFloat(actual) - if !bok { - return 0, fmt.Errorf("actual value %q cannot be converted to float", actual) - } if math.IsNaN(bf) { return 0, errors.New("actual value must not be NaN") } @@ -1298,7 +1358,7 @@ func InEpsilonSlice(t TestingT, expected, actual interface{}, epsilon float64, m if expected == nil || actual == nil || reflect.TypeOf(actual).Kind() != reflect.Slice || reflect.TypeOf(expected).Kind() != reflect.Slice { - return Fail(t, fmt.Sprintf("Parameters must be slice"), msgAndArgs...) + return Fail(t, "Parameters must be slice", msgAndArgs...) } actualSlice := reflect.ValueOf(actual) @@ -1375,6 +1435,27 @@ func EqualError(t TestingT, theError error, errString string, msgAndArgs ...inte return true } +// ErrorContains asserts that a function returned an error (i.e. not `nil`) +// and that the error contains the specified substring. +// +// actualObj, err := SomeFunction() +// assert.ErrorContains(t, err, expectedErrorSubString) +func ErrorContains(t TestingT, theError error, contains string, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if !Error(t, theError, msgAndArgs...) { + return false + } + + actual := theError.Error() + if !strings.Contains(actual, contains) { + return Fail(t, fmt.Sprintf("Error %#v does not contain %#v", actual, contains), msgAndArgs...) + } + + return true +} + // matchRegexp return true if a specified regexp matches a string. func matchRegexp(rx interface{}, str interface{}) bool { @@ -1588,12 +1669,17 @@ func diff(expected interface{}, actual interface{}) string { } var e, a string - if et != reflect.TypeOf("") { - e = spewConfig.Sdump(expected) - a = spewConfig.Sdump(actual) - } else { + + switch et { + case reflect.TypeOf(""): e = reflect.ValueOf(expected).String() a = reflect.ValueOf(actual).String() + case reflect.TypeOf(time.Time{}): + e = spewConfigStringerEnabled.Sdump(expected) + a = spewConfigStringerEnabled.Sdump(actual) + default: + e = spewConfig.Sdump(expected) + a = spewConfig.Sdump(actual) } diff, _ := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{ @@ -1625,6 +1711,14 @@ var spewConfig = spew.ConfigState{ MaxDepth: 10, } +var spewConfigStringerEnabled = spew.ConfigState{ + Indent: " ", + DisablePointerAddresses: true, + DisableCapacities: true, + SortKeys: true, + MaxDepth: 10, +} + type tHelper interface { Helper() } diff --git a/mantle/vendor/gopkg.in/yaml.v3/decode.go b/mantle/vendor/gopkg.in/yaml.v3/decode.go index df36e3a30f..0173b6982e 100644 --- a/mantle/vendor/gopkg.in/yaml.v3/decode.go +++ b/mantle/vendor/gopkg.in/yaml.v3/decode.go @@ -100,7 +100,10 @@ func (p *parser) peek() yaml_event_type_t { if p.event.typ != yaml_NO_EVENT { return p.event.typ } - if !yaml_parser_parse(&p.parser, &p.event) { + // It's curious choice from the underlying API to generally return a + // positive result on success, but on this case return true in an error + // scenario. This was the source of bugs in the past (issue #666). + if !yaml_parser_parse(&p.parser, &p.event) || p.parser.error != yaml_NO_ERROR { p.fail() } return p.event.typ @@ -320,6 +323,8 @@ type decoder struct { decodeCount int aliasCount int aliasDepth int + + mergedFields map[interface{}]bool } var ( @@ -808,6 +813,11 @@ func (d *decoder) mapping(n *Node, out reflect.Value) (good bool) { } } + mergedFields := d.mergedFields + d.mergedFields = nil + + var mergeNode *Node + mapIsNew := false if out.IsNil() { out.Set(reflect.MakeMap(outt)) @@ -815,11 +825,18 @@ func (d *decoder) mapping(n *Node, out reflect.Value) (good bool) { } for i := 0; i < l; i += 2 { if isMerge(n.Content[i]) { - d.merge(n.Content[i+1], out) + mergeNode = n.Content[i+1] continue } k := reflect.New(kt).Elem() if d.unmarshal(n.Content[i], k) { + if mergedFields != nil { + ki := k.Interface() + if mergedFields[ki] { + continue + } + mergedFields[ki] = true + } kkind := k.Kind() if kkind == reflect.Interface { kkind = k.Elem().Kind() @@ -833,6 +850,12 @@ func (d *decoder) mapping(n *Node, out reflect.Value) (good bool) { } } } + + d.mergedFields = mergedFields + if mergeNode != nil { + d.merge(n, mergeNode, out) + } + d.stringMapType = stringMapType d.generalMapType = generalMapType return true @@ -844,7 +867,8 @@ func isStringMap(n *Node) bool { } l := len(n.Content) for i := 0; i < l; i += 2 { - if n.Content[i].ShortTag() != strTag { + shortTag := n.Content[i].ShortTag() + if shortTag != strTag && shortTag != mergeTag { return false } } @@ -861,7 +885,6 @@ func (d *decoder) mappingStruct(n *Node, out reflect.Value) (good bool) { var elemType reflect.Type if sinfo.InlineMap != -1 { inlineMap = out.Field(sinfo.InlineMap) - inlineMap.Set(reflect.New(inlineMap.Type()).Elem()) elemType = inlineMap.Type().Elem() } @@ -870,6 +893,9 @@ func (d *decoder) mappingStruct(n *Node, out reflect.Value) (good bool) { d.prepare(n, field) } + mergedFields := d.mergedFields + d.mergedFields = nil + var mergeNode *Node var doneFields []bool if d.uniqueKeys { doneFields = make([]bool, len(sinfo.FieldsList)) @@ -879,13 +905,20 @@ func (d *decoder) mappingStruct(n *Node, out reflect.Value) (good bool) { for i := 0; i < l; i += 2 { ni := n.Content[i] if isMerge(ni) { - d.merge(n.Content[i+1], out) + mergeNode = n.Content[i+1] continue } if !d.unmarshal(ni, name) { continue } - if info, ok := sinfo.FieldsMap[name.String()]; ok { + sname := name.String() + if mergedFields != nil { + if mergedFields[sname] { + continue + } + mergedFields[sname] = true + } + if info, ok := sinfo.FieldsMap[sname]; ok { if d.uniqueKeys { if doneFields[info.Id] { d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s already set in type %s", ni.Line, name.String(), out.Type())) @@ -911,6 +944,11 @@ func (d *decoder) mappingStruct(n *Node, out reflect.Value) (good bool) { d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s not found in type %s", ni.Line, name.String(), out.Type())) } } + + d.mergedFields = mergedFields + if mergeNode != nil { + d.merge(n, mergeNode, out) + } return true } @@ -918,19 +956,29 @@ func failWantMap() { failf("map merge requires map or sequence of maps as the value") } -func (d *decoder) merge(n *Node, out reflect.Value) { - switch n.Kind { +func (d *decoder) merge(parent *Node, merge *Node, out reflect.Value) { + mergedFields := d.mergedFields + if mergedFields == nil { + d.mergedFields = make(map[interface{}]bool) + for i := 0; i < len(parent.Content); i += 2 { + k := reflect.New(ifaceType).Elem() + if d.unmarshal(parent.Content[i], k) { + d.mergedFields[k.Interface()] = true + } + } + } + + switch merge.Kind { case MappingNode: - d.unmarshal(n, out) + d.unmarshal(merge, out) case AliasNode: - if n.Alias != nil && n.Alias.Kind != MappingNode { + if merge.Alias != nil && merge.Alias.Kind != MappingNode { failWantMap() } - d.unmarshal(n, out) + d.unmarshal(merge, out) case SequenceNode: - // Step backwards as earlier nodes take precedence. - for i := len(n.Content) - 1; i >= 0; i-- { - ni := n.Content[i] + for i := 0; i < len(merge.Content); i++ { + ni := merge.Content[i] if ni.Kind == AliasNode { if ni.Alias != nil && ni.Alias.Kind != MappingNode { failWantMap() @@ -943,6 +991,8 @@ func (d *decoder) merge(n *Node, out reflect.Value) { default: failWantMap() } + + d.mergedFields = mergedFields } func isMerge(n *Node) bool { diff --git a/mantle/vendor/gopkg.in/yaml.v3/parserc.go b/mantle/vendor/gopkg.in/yaml.v3/parserc.go index ac66fccc05..268558a0d6 100644 --- a/mantle/vendor/gopkg.in/yaml.v3/parserc.go +++ b/mantle/vendor/gopkg.in/yaml.v3/parserc.go @@ -687,6 +687,9 @@ func yaml_parser_parse_node(parser *yaml_parser_t, event *yaml_event_t, block, i func yaml_parser_parse_block_sequence_entry(parser *yaml_parser_t, event *yaml_event_t, first bool) bool { if first { token := peek_token(parser) + if token == nil { + return false + } parser.marks = append(parser.marks, token.start_mark) skip_token(parser) } @@ -786,7 +789,7 @@ func yaml_parser_split_stem_comment(parser *yaml_parser_t, stem_len int) { } token := peek_token(parser) - if token.typ != yaml_BLOCK_SEQUENCE_START_TOKEN && token.typ != yaml_BLOCK_MAPPING_START_TOKEN { + if token == nil || token.typ != yaml_BLOCK_SEQUENCE_START_TOKEN && token.typ != yaml_BLOCK_MAPPING_START_TOKEN { return } @@ -813,6 +816,9 @@ func yaml_parser_split_stem_comment(parser *yaml_parser_t, stem_len int) { func yaml_parser_parse_block_mapping_key(parser *yaml_parser_t, event *yaml_event_t, first bool) bool { if first { token := peek_token(parser) + if token == nil { + return false + } parser.marks = append(parser.marks, token.start_mark) skip_token(parser) } @@ -922,6 +928,9 @@ func yaml_parser_parse_block_mapping_value(parser *yaml_parser_t, event *yaml_ev func yaml_parser_parse_flow_sequence_entry(parser *yaml_parser_t, event *yaml_event_t, first bool) bool { if first { token := peek_token(parser) + if token == nil { + return false + } parser.marks = append(parser.marks, token.start_mark) skip_token(parser) } diff --git a/mantle/vendor/modules.txt b/mantle/vendor/modules.txt index 296ee8a0ab..7fb88cef48 100644 --- a/mantle/vendor/modules.txt +++ b/mantle/vendor/modules.txt @@ -154,9 +154,9 @@ github.com/aws/aws-sdk-go/service/s3/s3iface github.com/aws/aws-sdk-go/service/s3/s3manager github.com/aws/aws-sdk-go/service/sts github.com/aws/aws-sdk-go/service/sts/stsiface -# github.com/clarketm/json v1.14.1 +# github.com/clarketm/json v1.17.1 github.com/clarketm/json -# github.com/coreos/butane v0.14.0 +# github.com/coreos/butane v0.16.0 github.com/coreos/butane/base/util github.com/coreos/butane/base/v0_1 github.com/coreos/butane/base/v0_2 @@ -171,10 +171,16 @@ github.com/coreos/butane/config/fcos/v1_2 github.com/coreos/butane/config/fcos/v1_3 github.com/coreos/butane/config/fcos/v1_4 github.com/coreos/butane/config/fcos/v1_5_exp +github.com/coreos/butane/config/flatcar/v1_0 +github.com/coreos/butane/config/flatcar/v1_1_exp github.com/coreos/butane/config/openshift/v4_10 github.com/coreos/butane/config/openshift/v4_10/result -github.com/coreos/butane/config/openshift/v4_11_exp -github.com/coreos/butane/config/openshift/v4_11_exp/result +github.com/coreos/butane/config/openshift/v4_11 +github.com/coreos/butane/config/openshift/v4_11/result +github.com/coreos/butane/config/openshift/v4_12 +github.com/coreos/butane/config/openshift/v4_12/result +github.com/coreos/butane/config/openshift/v4_13_exp +github.com/coreos/butane/config/openshift/v4_13_exp/result github.com/coreos/butane/config/openshift/v4_8 github.com/coreos/butane/config/openshift/v4_8/result github.com/coreos/butane/config/openshift/v4_9 @@ -184,14 +190,14 @@ github.com/coreos/butane/config/util github.com/coreos/butane/translate # github.com/coreos/coreos-assembler-schema v0.0.0-00010101000000-000000000000 => ../schema github.com/coreos/coreos-assembler-schema/cosa -# github.com/coreos/go-json v0.0.0-20211020211907-c63f628265de +# github.com/coreos/go-json v0.0.0-20220810161552-7cce03887f34 github.com/coreos/go-json # github.com/coreos/go-semver v0.3.0 github.com/coreos/go-semver/semver # github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e github.com/coreos/go-systemd/journal github.com/coreos/go-systemd/unit -# github.com/coreos/go-systemd/v22 v22.0.0 +# github.com/coreos/go-systemd/v22 v22.4.0 github.com/coreos/go-systemd/v22/dbus github.com/coreos/go-systemd/v22/journal github.com/coreos/go-systemd/v22/unit @@ -227,7 +233,7 @@ github.com/coreos/stream-metadata-go/release github.com/coreos/stream-metadata-go/release/rhcos github.com/coreos/stream-metadata-go/stream github.com/coreos/stream-metadata-go/stream/rhcos -# github.com/coreos/vcontext v0.0.0-20211021162308-f1dbbca7bef4 +# github.com/coreos/vcontext v0.0.0-20220810162454-88bd546c634c github.com/coreos/vcontext/json github.com/coreos/vcontext/path github.com/coreos/vcontext/report @@ -250,7 +256,7 @@ github.com/digitalocean/godo github.com/dimchansky/utfbom # github.com/dustin/go-humanize v1.0.0 github.com/dustin/go-humanize -# github.com/godbus/dbus/v5 v5.0.3 +# github.com/godbus/dbus/v5 v5.0.4 github.com/godbus/dbus/v5 # github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e github.com/golang/groupcache/lru @@ -348,7 +354,7 @@ github.com/sirupsen/logrus github.com/spf13/cobra # github.com/spf13/pflag v1.0.6-0.20210604193023-d5e0c0615ace github.com/spf13/pflag -# github.com/stretchr/testify v1.7.0 +# github.com/stretchr/testify v1.8.0 github.com/stretchr/testify/assert # github.com/vincent-petithory/dataurl v1.0.0 github.com/vincent-petithory/dataurl @@ -554,5 +560,5 @@ google.golang.org/protobuf/types/known/timestamppb gopkg.in/ini.v1 # gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v2 -# gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b +# gopkg.in/yaml.v3 v3.0.1 gopkg.in/yaml.v3