mirror of
https://github.com/moby/moby.git
synced 2026-01-11 18:51:37 +00:00
NRI: import containerd's NRI adaptation package
Signed-off-by: Rob Murray <rob.murray@docker.com>
This commit is contained in:
7
daemon/internal/nri/nri.go
Normal file
7
daemon/internal/nri/nri.go
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
package nri
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/containerd/nri/pkg/adaptation"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = *adaptation.Adaptation
|
||||||
3
go.mod
3
go.mod
@@ -27,6 +27,7 @@ require (
|
|||||||
github.com/containerd/errdefs v1.0.0
|
github.com/containerd/errdefs v1.0.0
|
||||||
github.com/containerd/fifo v1.1.0
|
github.com/containerd/fifo v1.1.0
|
||||||
github.com/containerd/log v0.1.0
|
github.com/containerd/log v0.1.0
|
||||||
|
github.com/containerd/nri v0.10.0
|
||||||
github.com/containerd/platforms v1.0.0-rc.2
|
github.com/containerd/platforms v1.0.0-rc.2
|
||||||
github.com/containerd/typeurl/v2 v2.2.3
|
github.com/containerd/typeurl/v2 v2.2.3
|
||||||
github.com/coreos/go-systemd/v22 v22.6.0
|
github.com/coreos/go-systemd/v22 v22.6.0
|
||||||
@@ -194,6 +195,7 @@ require (
|
|||||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||||
github.com/jmoiron/sqlx v1.3.3 // indirect
|
github.com/jmoiron/sqlx v1.3.3 // indirect
|
||||||
github.com/klauspost/compress v1.18.2 // indirect
|
github.com/klauspost/compress v1.18.2 // indirect
|
||||||
|
github.com/knqyf263/go-plugin v0.9.0 // indirect
|
||||||
github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect
|
github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect
|
||||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||||
github.com/moby/sys/capability v0.4.0 // indirect
|
github.com/moby/sys/capability v0.4.0 // indirect
|
||||||
@@ -215,6 +217,7 @@ require (
|
|||||||
github.com/shibumi/go-pathspec v1.3.0 // indirect
|
github.com/shibumi/go-pathspec v1.3.0 // indirect
|
||||||
github.com/spdx/tools-golang v0.5.5 // indirect
|
github.com/spdx/tools-golang v0.5.5 // indirect
|
||||||
github.com/stretchr/testify v1.11.1 // indirect
|
github.com/stretchr/testify v1.11.1 // indirect
|
||||||
|
github.com/tetratelabs/wazero v1.9.0 // indirect
|
||||||
github.com/tinylib/msgp v1.3.0 // indirect
|
github.com/tinylib/msgp v1.3.0 // indirect
|
||||||
github.com/tonistiigi/dchapes-mode v0.0.0-20250318174251-73d941a28323 // indirect
|
github.com/tonistiigi/dchapes-mode v0.0.0-20250318174251-73d941a28323 // indirect
|
||||||
github.com/tonistiigi/fsutil v0.0.0-20250605211040-586307ad452f // indirect
|
github.com/tonistiigi/fsutil v0.0.0-20250605211040-586307ad452f // indirect
|
||||||
|
|||||||
6
go.sum
6
go.sum
@@ -154,6 +154,8 @@ github.com/containerd/go-runc v1.1.0 h1:OX4f+/i2y5sUT7LhmcJH7GYrjjhHa1QI4e8yO0gG
|
|||||||
github.com/containerd/go-runc v1.1.0/go.mod h1:xJv2hFF7GvHtTJd9JqTS2UVxMkULUYw4JN5XAUZqH5U=
|
github.com/containerd/go-runc v1.1.0/go.mod h1:xJv2hFF7GvHtTJd9JqTS2UVxMkULUYw4JN5XAUZqH5U=
|
||||||
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
|
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
|
||||||
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
|
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
|
||||||
|
github.com/containerd/nri v0.10.0 h1:bt2NzfvlY6OJE0i+fB5WVeGQEycxY7iFVQpEbh7J3Go=
|
||||||
|
github.com/containerd/nri v0.10.0/go.mod h1:5VyvLa/4uL8FjyO8nis1UjbCutXDpngil17KvBSL6BU=
|
||||||
github.com/containerd/nydus-snapshotter v0.15.4 h1:l59kGRVMtwMLDLh322HsWhEsBCkRKMkGWYV5vBeLYCE=
|
github.com/containerd/nydus-snapshotter v0.15.4 h1:l59kGRVMtwMLDLh322HsWhEsBCkRKMkGWYV5vBeLYCE=
|
||||||
github.com/containerd/nydus-snapshotter v0.15.4/go.mod h1:eRJqnxQDr48HNop15kZdLZpFF5B6vf6Q11Aq1K0E4Ms=
|
github.com/containerd/nydus-snapshotter v0.15.4/go.mod h1:eRJqnxQDr48HNop15kZdLZpFF5B6vf6Q11Aq1K0E4Ms=
|
||||||
github.com/containerd/platforms v1.0.0-rc.2 h1:0SPgaNZPVWGEi4grZdV8VRYQn78y+nm6acgLGv/QzE4=
|
github.com/containerd/platforms v1.0.0-rc.2 h1:0SPgaNZPVWGEi4grZdV8VRYQn78y+nm6acgLGv/QzE4=
|
||||||
@@ -377,6 +379,8 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI
|
|||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
github.com/klauspost/compress v1.18.2 h1:iiPHWW0YrcFgpBYhsA6D1+fqHssJscY/Tm/y2Uqnapk=
|
github.com/klauspost/compress v1.18.2 h1:iiPHWW0YrcFgpBYhsA6D1+fqHssJscY/Tm/y2Uqnapk=
|
||||||
github.com/klauspost/compress v1.18.2/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4=
|
github.com/klauspost/compress v1.18.2/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4=
|
||||||
|
github.com/knqyf263/go-plugin v0.9.0 h1:CQs2+lOPIlkZVtcb835ZYDEoyyWJWLbSTWeCs0EwTwI=
|
||||||
|
github.com/knqyf263/go-plugin v0.9.0/go.mod h1:2z5lCO1/pez6qGo8CvCxSlBFSEat4MEp1DrnA+f7w8Q=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
@@ -598,6 +602,8 @@ github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu
|
|||||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||||
github.com/tedsuo/ifrit v0.0.0-20230516164442-7862c310ad26 h1:mWCRvpoEMVlslxEvvptKgIUb35va9yj9Oq5wGw/er5I=
|
github.com/tedsuo/ifrit v0.0.0-20230516164442-7862c310ad26 h1:mWCRvpoEMVlslxEvvptKgIUb35va9yj9Oq5wGw/er5I=
|
||||||
github.com/tedsuo/ifrit v0.0.0-20230516164442-7862c310ad26/go.mod h1:0uD3VMXkZ7Bw0ojGCwDzebBBzPBXtzEZeXai+56BLX4=
|
github.com/tedsuo/ifrit v0.0.0-20230516164442-7862c310ad26/go.mod h1:0uD3VMXkZ7Bw0ojGCwDzebBBzPBXtzEZeXai+56BLX4=
|
||||||
|
github.com/tetratelabs/wazero v1.9.0 h1:IcZ56OuxrtaEz8UYNRHBrUa9bYeX9oVY93KspZZBf/I=
|
||||||
|
github.com/tetratelabs/wazero v1.9.0/go.mod h1:TSbcXCfFP0L2FGkRPxHphadXPjo1T6W+CseNNY7EkjM=
|
||||||
github.com/tinylib/msgp v1.3.0 h1:ULuf7GPooDaIlbyvgAxBV/FI7ynli6LZ1/nVUNu+0ww=
|
github.com/tinylib/msgp v1.3.0 h1:ULuf7GPooDaIlbyvgAxBV/FI7ynli6LZ1/nVUNu+0ww=
|
||||||
github.com/tinylib/msgp v1.3.0/go.mod h1:ykjzy2wzgrlvpDCRc4LA8UXy6D8bzMSuAF3WD57Gok0=
|
github.com/tinylib/msgp v1.3.0/go.mod h1:ykjzy2wzgrlvpDCRc4LA8UXy6D8bzMSuAF3WD57Gok0=
|
||||||
github.com/tonistiigi/dchapes-mode v0.0.0-20250318174251-73d941a28323 h1:r0p7fK56l8WPequOaR3i9LBqfPtEdXIQbUTzT55iqT4=
|
github.com/tonistiigi/dchapes-mode v0.0.0-20250318174251-73d941a28323 h1:r0p7fK56l8WPequOaR3i9LBqfPtEdXIQbUTzT55iqT4=
|
||||||
|
|||||||
201
vendor/github.com/containerd/nri/LICENSE
generated
vendored
Normal file
201
vendor/github.com/containerd/nri/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
731
vendor/github.com/containerd/nri/pkg/adaptation/adaptation.go
generated
vendored
Normal file
731
vendor/github.com/containerd/nri/pkg/adaptation/adaptation.go
generated
vendored
Normal file
@@ -0,0 +1,731 @@
|
|||||||
|
/*
|
||||||
|
Copyright The containerd Authors.
|
||||||
|
|
||||||
|
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 adaptation
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io/fs"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"sort"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/containerd/nri/pkg/adaptation/builtin"
|
||||||
|
"github.com/containerd/nri/pkg/api"
|
||||||
|
"github.com/containerd/nri/pkg/log"
|
||||||
|
validator "github.com/containerd/nri/plugins/default-validator/builtin"
|
||||||
|
"github.com/containerd/ttrpc"
|
||||||
|
"github.com/tetratelabs/wazero"
|
||||||
|
"github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1"
|
||||||
|
|
||||||
|
"google.golang.org/protobuf/proto"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// DefaultPluginPath is the default path to search for NRI plugins.
|
||||||
|
DefaultPluginPath = "/opt/nri/plugins"
|
||||||
|
// DefaultSocketPath is the default socket path for external plugins.
|
||||||
|
DefaultSocketPath = api.DefaultSocketPath
|
||||||
|
// PluginConfigDir is the drop-in directory for NRI-launched plugin configuration.
|
||||||
|
DefaultPluginConfigPath = "/etc/nri/conf.d"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SyncFn is a container runtime function for state synchronization.
|
||||||
|
type SyncFn func(context.Context, SyncCB) error
|
||||||
|
|
||||||
|
// SyncCB is an NRI function used to synchronize plugins with the runtime.
|
||||||
|
type SyncCB func(context.Context, []*PodSandbox, []*Container) ([]*ContainerUpdate, error)
|
||||||
|
|
||||||
|
// UpdateFn is a container runtime function for unsolicited container updates.
|
||||||
|
type UpdateFn func(context.Context, []*ContainerUpdate) ([]*ContainerUpdate, error)
|
||||||
|
|
||||||
|
// Adaptation is the NRI abstraction for container runtime NRI adaptation/integration.
|
||||||
|
type Adaptation struct {
|
||||||
|
sync.Mutex
|
||||||
|
name string
|
||||||
|
version string
|
||||||
|
dropinPath string
|
||||||
|
pluginPath string
|
||||||
|
socketPath string
|
||||||
|
dontListen bool
|
||||||
|
syncFn SyncFn
|
||||||
|
updateFn UpdateFn
|
||||||
|
clientOpts []ttrpc.ClientOpts
|
||||||
|
serverOpts []ttrpc.ServerOpt
|
||||||
|
listener net.Listener
|
||||||
|
plugins []*plugin
|
||||||
|
validators []*plugin
|
||||||
|
builtin []*builtin.BuiltinPlugin
|
||||||
|
syncLock sync.RWMutex
|
||||||
|
wasmService *api.PluginPlugin
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
// Used instead of nil Context in logging.
|
||||||
|
noCtx = context.TODO()
|
||||||
|
)
|
||||||
|
|
||||||
|
// Option to apply to the NRI runtime.
|
||||||
|
type Option func(*Adaptation) error
|
||||||
|
|
||||||
|
// WithPluginPath returns an option to override the default NRI plugin path.
|
||||||
|
func WithPluginPath(path string) Option {
|
||||||
|
return func(r *Adaptation) error {
|
||||||
|
r.pluginPath = path
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithPluginConfigPath returns an option to override the default NRI plugin config path.
|
||||||
|
func WithPluginConfigPath(path string) Option {
|
||||||
|
return func(r *Adaptation) error {
|
||||||
|
r.dropinPath = path
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithSocketPath returns an option to override the default NRI socket path.
|
||||||
|
func WithSocketPath(path string) Option {
|
||||||
|
return func(r *Adaptation) error {
|
||||||
|
r.socketPath = path
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithDisabledExternalConnections returns an options to disable accepting plugin connections.
|
||||||
|
func WithDisabledExternalConnections() Option {
|
||||||
|
return func(r *Adaptation) error {
|
||||||
|
r.dontListen = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithTTRPCOptions sets extra client and server options to use for ttrpc.
|
||||||
|
func WithTTRPCOptions(clientOpts []ttrpc.ClientOpts, serverOpts []ttrpc.ServerOpt) Option {
|
||||||
|
return func(r *Adaptation) error {
|
||||||
|
r.clientOpts = append(r.clientOpts, clientOpts...)
|
||||||
|
r.serverOpts = append(r.serverOpts, serverOpts...)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithBuiltinPlugins sets extra builtin plugins to register.
|
||||||
|
func WithBuiltinPlugins(plugins ...*builtin.BuiltinPlugin) Option {
|
||||||
|
return func(r *Adaptation) error {
|
||||||
|
r.builtin = append(r.builtin, plugins...)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithDefaultValidator sets up builtin validator plugin if it is configured.
|
||||||
|
func WithDefaultValidator(cfg *validator.DefaultValidatorConfig) Option {
|
||||||
|
return func(r *Adaptation) error {
|
||||||
|
if plugin := validator.GetDefaultValidator(cfg); plugin != nil {
|
||||||
|
r.builtin = append([]*builtin.BuiltinPlugin{plugin}, r.builtin...)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// New creates a new NRI Runtime.
|
||||||
|
func New(name, version string, syncFn SyncFn, updateFn UpdateFn, opts ...Option) (*Adaptation, error) {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if syncFn == nil {
|
||||||
|
return nil, fmt.Errorf("failed to create NRI adaptation, nil SyncFn")
|
||||||
|
}
|
||||||
|
if updateFn == nil {
|
||||||
|
return nil, fmt.Errorf("failed to create NRI adaptation, nil UpdateFn")
|
||||||
|
}
|
||||||
|
|
||||||
|
wasmWithCloseOnContextDone := func(ctx context.Context) (wazero.Runtime, error) {
|
||||||
|
var (
|
||||||
|
cfg = wazero.NewRuntimeConfig().WithCloseOnContextDone(true)
|
||||||
|
r = wazero.NewRuntimeWithConfig(ctx, cfg)
|
||||||
|
)
|
||||||
|
if _, err := wasi_snapshot_preview1.Instantiate(ctx, r); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return r, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
wasmPlugins, err := api.NewPluginPlugin(
|
||||||
|
context.Background(),
|
||||||
|
api.WazeroRuntime(wasmWithCloseOnContextDone),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to initialize WASM service: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
r := &Adaptation{
|
||||||
|
name: name,
|
||||||
|
version: version,
|
||||||
|
syncFn: syncFn,
|
||||||
|
updateFn: updateFn,
|
||||||
|
pluginPath: DefaultPluginPath,
|
||||||
|
dropinPath: DefaultPluginConfigPath,
|
||||||
|
socketPath: DefaultSocketPath,
|
||||||
|
syncLock: sync.RWMutex{},
|
||||||
|
wasmService: wasmPlugins,
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, o := range opts {
|
||||||
|
if err = o(r); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to apply option: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Infof(noCtx, "runtime interface created")
|
||||||
|
|
||||||
|
return r, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start up the NRI runtime.
|
||||||
|
func (r *Adaptation) Start() error {
|
||||||
|
log.Infof(noCtx, "runtime interface starting up...")
|
||||||
|
|
||||||
|
r.Lock()
|
||||||
|
defer r.Unlock()
|
||||||
|
|
||||||
|
if err := r.startPlugins(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := r.startListener(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop the NRI runtime.
|
||||||
|
func (r *Adaptation) Stop() {
|
||||||
|
log.Infof(noCtx, "runtime interface shutting down...")
|
||||||
|
|
||||||
|
r.Lock()
|
||||||
|
defer r.Unlock()
|
||||||
|
|
||||||
|
r.stopListener()
|
||||||
|
r.stopPlugins()
|
||||||
|
}
|
||||||
|
|
||||||
|
// RunPodSandbox relays the corresponding CRI event to plugins.
|
||||||
|
func (r *Adaptation) RunPodSandbox(ctx context.Context, evt *StateChangeEvent) error {
|
||||||
|
evt.Event = Event_RUN_POD_SANDBOX
|
||||||
|
return r.StateChange(ctx, evt)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdatePodSandbox relays the corresponding CRI request to plugins.
|
||||||
|
func (r *Adaptation) UpdatePodSandbox(ctx context.Context, req *UpdatePodSandboxRequest) (*UpdatePodSandboxResponse, error) {
|
||||||
|
r.Lock()
|
||||||
|
defer r.Unlock()
|
||||||
|
defer r.removeClosedPlugins()
|
||||||
|
|
||||||
|
for _, plugin := range r.plugins {
|
||||||
|
_, err := plugin.updatePodSandbox(ctx, req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &UpdatePodSandboxResponse{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// PostUpdatePodSandbox relays the corresponding CRI event to plugins.
|
||||||
|
func (r *Adaptation) PostUpdatePodSandbox(ctx context.Context, evt *StateChangeEvent) error {
|
||||||
|
evt.Event = Event_POST_UPDATE_POD_SANDBOX
|
||||||
|
return r.StateChange(ctx, evt)
|
||||||
|
}
|
||||||
|
|
||||||
|
// StopPodSandbox relays the corresponding CRI event to plugins.
|
||||||
|
func (r *Adaptation) StopPodSandbox(ctx context.Context, evt *StateChangeEvent) error {
|
||||||
|
evt.Event = Event_STOP_POD_SANDBOX
|
||||||
|
return r.StateChange(ctx, evt)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemovePodSandbox relays the corresponding CRI event to plugins.
|
||||||
|
func (r *Adaptation) RemovePodSandbox(ctx context.Context, evt *StateChangeEvent) error {
|
||||||
|
evt.Event = Event_REMOVE_POD_SANDBOX
|
||||||
|
return r.StateChange(ctx, evt)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateContainer relays the corresponding CRI request to plugins.
|
||||||
|
func (r *Adaptation) CreateContainer(ctx context.Context, req *CreateContainerRequest) (*CreateContainerResponse, error) {
|
||||||
|
r.Lock()
|
||||||
|
defer r.Unlock()
|
||||||
|
defer r.removeClosedPlugins()
|
||||||
|
|
||||||
|
var (
|
||||||
|
result = collectCreateContainerResult(req)
|
||||||
|
validate *ValidateContainerAdjustmentRequest
|
||||||
|
)
|
||||||
|
|
||||||
|
if r.hasValidators() {
|
||||||
|
validate = &ValidateContainerAdjustmentRequest{
|
||||||
|
Pod: req.Pod,
|
||||||
|
Container: proto.Clone(req.Container).(*Container),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, plugin := range r.plugins {
|
||||||
|
if validate != nil {
|
||||||
|
validate.AddPlugin(plugin.base, plugin.idx)
|
||||||
|
}
|
||||||
|
rpl, err := plugin.createContainer(ctx, req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
err = result.apply(rpl, plugin.name())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.validateContainerAdjustment(ctx, validate, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PostCreateContainer relays the corresponding CRI event to plugins.
|
||||||
|
func (r *Adaptation) PostCreateContainer(ctx context.Context, evt *StateChangeEvent) error {
|
||||||
|
evt.Event = Event_POST_CREATE_CONTAINER
|
||||||
|
return r.StateChange(ctx, evt)
|
||||||
|
}
|
||||||
|
|
||||||
|
// StartContainer relays the corresponding CRI event to plugins.
|
||||||
|
func (r *Adaptation) StartContainer(ctx context.Context, evt *StateChangeEvent) error {
|
||||||
|
evt.Event = Event_START_CONTAINER
|
||||||
|
return r.StateChange(ctx, evt)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PostStartContainer relays the corresponding CRI event to plugins.
|
||||||
|
func (r *Adaptation) PostStartContainer(ctx context.Context, evt *StateChangeEvent) error {
|
||||||
|
evt.Event = Event_POST_START_CONTAINER
|
||||||
|
return r.StateChange(ctx, evt)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateContainer relays the corresponding CRI request to plugins.
|
||||||
|
func (r *Adaptation) UpdateContainer(ctx context.Context, req *UpdateContainerRequest) (*UpdateContainerResponse, error) {
|
||||||
|
r.Lock()
|
||||||
|
defer r.Unlock()
|
||||||
|
defer r.removeClosedPlugins()
|
||||||
|
|
||||||
|
result := collectUpdateContainerResult(req)
|
||||||
|
for _, plugin := range r.plugins {
|
||||||
|
rpl, err := plugin.updateContainer(ctx, req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
err = result.apply(rpl, plugin.name())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.updateContainerResponse(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// PostUpdateContainer relays the corresponding CRI event to plugins.
|
||||||
|
func (r *Adaptation) PostUpdateContainer(ctx context.Context, evt *StateChangeEvent) error {
|
||||||
|
evt.Event = Event_POST_UPDATE_CONTAINER
|
||||||
|
return r.StateChange(ctx, evt)
|
||||||
|
}
|
||||||
|
|
||||||
|
// StopContainer relays the corresponding CRI request to plugins.
|
||||||
|
func (r *Adaptation) StopContainer(ctx context.Context, req *StopContainerRequest) (*StopContainerResponse, error) {
|
||||||
|
r.Lock()
|
||||||
|
defer r.Unlock()
|
||||||
|
defer r.removeClosedPlugins()
|
||||||
|
|
||||||
|
result := collectStopContainerResult()
|
||||||
|
for _, plugin := range r.plugins {
|
||||||
|
rpl, err := plugin.stopContainer(ctx, req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
err = result.apply(rpl, plugin.name())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.stopContainerResponse(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveContainer relays the corresponding CRI event to plugins.
|
||||||
|
func (r *Adaptation) RemoveContainer(ctx context.Context, evt *StateChangeEvent) error {
|
||||||
|
evt.Event = Event_REMOVE_CONTAINER
|
||||||
|
return r.StateChange(ctx, evt)
|
||||||
|
}
|
||||||
|
|
||||||
|
// StateChange relays pod- or container events to plugins.
|
||||||
|
func (r *Adaptation) StateChange(ctx context.Context, evt *StateChangeEvent) error {
|
||||||
|
if evt.Event == Event_UNKNOWN {
|
||||||
|
return errors.New("invalid (unset) event in state change notification")
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Lock()
|
||||||
|
defer r.Unlock()
|
||||||
|
defer r.removeClosedPlugins()
|
||||||
|
|
||||||
|
for _, plugin := range r.plugins {
|
||||||
|
err := plugin.StateChange(ctx, evt)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform a set of unsolicited container updates requested by a plugin.
|
||||||
|
func (r *Adaptation) updateContainers(ctx context.Context, req []*ContainerUpdate) ([]*ContainerUpdate, error) {
|
||||||
|
r.Lock()
|
||||||
|
defer r.Unlock()
|
||||||
|
|
||||||
|
return r.updateFn(ctx, req)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate requested container adjustments.
|
||||||
|
func (r *Adaptation) validateContainerAdjustment(ctx context.Context, req *ValidateContainerAdjustmentRequest, result *result) (*CreateContainerResponse, error) {
|
||||||
|
rpl := result.createContainerResponse()
|
||||||
|
|
||||||
|
if req == nil || len(r.validators) == 0 {
|
||||||
|
return rpl, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
req.AddResponse(rpl)
|
||||||
|
req.AddOwners(result.owners)
|
||||||
|
|
||||||
|
errors := make(chan error, len(r.validators))
|
||||||
|
wg := sync.WaitGroup{}
|
||||||
|
|
||||||
|
for _, p := range r.validators {
|
||||||
|
wg.Add(1)
|
||||||
|
go func(p *plugin) {
|
||||||
|
defer wg.Done()
|
||||||
|
errors <- p.ValidateContainerAdjustment(ctx, req)
|
||||||
|
}(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
wg.Wait()
|
||||||
|
close(errors)
|
||||||
|
|
||||||
|
for err := range errors {
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rpl, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start up pre-installed plugins.
|
||||||
|
func (r *Adaptation) startPlugins() (retErr error) {
|
||||||
|
var plugins []*plugin
|
||||||
|
|
||||||
|
log.Infof(noCtx, "starting plugins...")
|
||||||
|
|
||||||
|
ids, names, configs, err := r.discoverPlugins()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if retErr != nil {
|
||||||
|
for _, p := range plugins {
|
||||||
|
p.stop()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
for _, b := range r.builtin {
|
||||||
|
log.Infof(noCtx, "starting builtin NRI plugin %q...", b.Index+"-"+b.Base)
|
||||||
|
p, err := r.newBuiltinPlugin(b)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to initialize builtin NRI plugin %q: %v", b.Base, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := p.start(r.name, r.version); err != nil {
|
||||||
|
return fmt.Errorf("failed to start builtin NRI plugin %q: %v", b.Base, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
plugins = append(plugins, p)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, name := range names {
|
||||||
|
log.Infof(noCtx, "starting pre-installed NRI plugin %q...", name)
|
||||||
|
|
||||||
|
id := ids[i]
|
||||||
|
p, err := r.newLaunchedPlugin(r.pluginPath, id, name, configs[i])
|
||||||
|
if err != nil {
|
||||||
|
log.Warnf(noCtx, "failed to initialize pre-installed NRI plugin %q: %v", name, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := p.start(r.name, r.version); err != nil {
|
||||||
|
log.Warnf(noCtx, "failed to start pre-installed NRI plugin %q: %v", name, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
plugins = append(plugins, p)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Although the error returned by syncPlugins may not be nil, r.syncFn could still ignores this error and returns a nil error.
|
||||||
|
// We need to make sure that the plugins are successfully synchronized in the `plugins`
|
||||||
|
syncPlugins := func(ctx context.Context, pods []*PodSandbox, containers []*Container) (updates []*ContainerUpdate, err error) {
|
||||||
|
startedPlugins := plugins
|
||||||
|
plugins = make([]*plugin, 0, len(plugins))
|
||||||
|
for _, plugin := range startedPlugins {
|
||||||
|
us, err := plugin.synchronize(ctx, pods, containers)
|
||||||
|
if err != nil {
|
||||||
|
plugin.stop()
|
||||||
|
log.Warnf(noCtx, "failed to synchronize pre-installed NRI plugin %q: %v", plugin.name(), err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
plugins = append(plugins, plugin)
|
||||||
|
updates = append(updates, us...)
|
||||||
|
log.Infof(noCtx, "pre-installed NRI plugin %q synchronization success", plugin.name())
|
||||||
|
}
|
||||||
|
return updates, nil
|
||||||
|
}
|
||||||
|
if err := r.syncFn(noCtx, syncPlugins); err != nil {
|
||||||
|
return fmt.Errorf("failed to synchronize pre-installed NRI Plugins: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
r.plugins = plugins
|
||||||
|
r.sortPlugins()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop plugins.
|
||||||
|
func (r *Adaptation) stopPlugins() {
|
||||||
|
log.Infof(noCtx, "stopping plugins...")
|
||||||
|
|
||||||
|
for _, p := range r.plugins {
|
||||||
|
p.stop()
|
||||||
|
}
|
||||||
|
r.plugins = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Adaptation) removeClosedPlugins() {
|
||||||
|
var active, closed, validators []*plugin
|
||||||
|
for _, p := range r.plugins {
|
||||||
|
if p.isClosed() {
|
||||||
|
closed = append(closed, p)
|
||||||
|
} else {
|
||||||
|
active = append(active, p)
|
||||||
|
if p.isContainerAdjustmentValidator() {
|
||||||
|
validators = append(validators, p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(closed) != 0 {
|
||||||
|
go func() {
|
||||||
|
for _, plugin := range closed {
|
||||||
|
plugin.stop()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
r.plugins = active
|
||||||
|
r.validators = validators
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Adaptation) startListener() error {
|
||||||
|
if r.dontListen {
|
||||||
|
log.Infof(noCtx, "connection from external plugins disabled")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
os.Remove(r.socketPath)
|
||||||
|
if err := os.MkdirAll(filepath.Dir(r.socketPath), 0700); err != nil {
|
||||||
|
return fmt.Errorf("failed to create socket %q: %w", r.socketPath, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
l, err := net.ListenUnix("unix", &net.UnixAddr{
|
||||||
|
Name: r.socketPath,
|
||||||
|
Net: "unix",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create socket %q: %w", r.socketPath, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
r.acceptPluginConnections(l)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Adaptation) stopListener() {
|
||||||
|
if r.listener != nil {
|
||||||
|
r.listener.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Adaptation) acceptPluginConnections(l net.Listener) error {
|
||||||
|
r.listener = l
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
conn, err := l.Accept()
|
||||||
|
if err != nil {
|
||||||
|
log.Infof(ctx, "stopped accepting plugin connections (%v)", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
p, err := r.newExternalPlugin(conn)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf(ctx, "failed to create external plugin: %v", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := p.start(r.name, r.version); err != nil {
|
||||||
|
log.Errorf(ctx, "failed to start external plugin: %v", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
r.requestPluginSync()
|
||||||
|
|
||||||
|
err = r.syncFn(ctx, p.synchronize)
|
||||||
|
if err != nil {
|
||||||
|
log.Infof(ctx, "failed to synchronize plugin: %v", err)
|
||||||
|
} else {
|
||||||
|
r.Lock()
|
||||||
|
r.plugins = append(r.plugins, p)
|
||||||
|
if p.isContainerAdjustmentValidator() {
|
||||||
|
r.validators = append(r.validators, p)
|
||||||
|
}
|
||||||
|
r.sortPlugins()
|
||||||
|
r.Unlock()
|
||||||
|
log.Infof(ctx, "plugin %q connected and synchronized", p.name())
|
||||||
|
}
|
||||||
|
|
||||||
|
r.finishedPluginSync()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Adaptation) discoverPlugins() ([]string, []string, []string, error) {
|
||||||
|
var (
|
||||||
|
plugins []string
|
||||||
|
indices []string
|
||||||
|
configs []string
|
||||||
|
entries []os.DirEntry
|
||||||
|
info fs.FileInfo
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
|
||||||
|
if entries, err = os.ReadDir(r.pluginPath); err != nil {
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
return nil, nil, nil, nil
|
||||||
|
}
|
||||||
|
return nil, nil, nil, fmt.Errorf("failed to discover plugins in %s: %w",
|
||||||
|
r.pluginPath, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, e := range entries {
|
||||||
|
if e.IsDir() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if info, err = e.Info(); err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if info.Mode()&fs.FileMode(0o111) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
name := e.Name()
|
||||||
|
idx, base, err := api.ParsePluginName(name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, nil, fmt.Errorf("failed to discover plugins in %s: %w",
|
||||||
|
r.pluginPath, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg, err := r.getPluginConfig(idx, base)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, nil, fmt.Errorf("failed to discover plugins in %s: %w",
|
||||||
|
r.pluginPath, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Infof(noCtx, "discovered plugin %s", name)
|
||||||
|
|
||||||
|
indices = append(indices, idx)
|
||||||
|
plugins = append(plugins, base)
|
||||||
|
configs = append(configs, cfg)
|
||||||
|
}
|
||||||
|
|
||||||
|
return indices, plugins, configs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Adaptation) sortPlugins() {
|
||||||
|
r.removeClosedPlugins()
|
||||||
|
sort.Slice(r.plugins, func(i, j int) bool {
|
||||||
|
return r.plugins[i].idx < r.plugins[j].idx
|
||||||
|
})
|
||||||
|
sort.Slice(r.validators, func(i, j int) bool {
|
||||||
|
return r.validators[i].idx < r.validators[j].idx
|
||||||
|
})
|
||||||
|
if len(r.plugins) > 0 {
|
||||||
|
log.Infof(noCtx, "plugin invocation order")
|
||||||
|
for i, p := range r.plugins {
|
||||||
|
log.Infof(noCtx, " #%d: %q (%s)", i+1, p.name(), p.qualifiedName())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(r.validators) > 0 {
|
||||||
|
log.Infof(noCtx, "validator plugins")
|
||||||
|
for _, p := range r.validators {
|
||||||
|
log.Infof(noCtx, " %q (%s)", p.name(), p.qualifiedName())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Adaptation) hasValidators() bool {
|
||||||
|
return len(r.validators) > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Adaptation) requestPluginSync() {
|
||||||
|
r.syncLock.Lock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Adaptation) finishedPluginSync() {
|
||||||
|
r.syncLock.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
type PluginSyncBlock struct {
|
||||||
|
r *Adaptation
|
||||||
|
}
|
||||||
|
|
||||||
|
// BlockPluginSync blocks plugins from being synchronized/fully registered.
|
||||||
|
func (r *Adaptation) BlockPluginSync() *PluginSyncBlock {
|
||||||
|
r.syncLock.RLock()
|
||||||
|
return &PluginSyncBlock{r: r}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unblock a plugin sync. block put in place by BlockPluginSync. Safe to call
|
||||||
|
// multiple times but only from a single goroutine.
|
||||||
|
func (b *PluginSyncBlock) Unblock() {
|
||||||
|
if b != nil && b.r != nil {
|
||||||
|
b.r.syncLock.RUnlock()
|
||||||
|
b.r = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
175
vendor/github.com/containerd/nri/pkg/adaptation/api.go
generated
vendored
Normal file
175
vendor/github.com/containerd/nri/pkg/adaptation/api.go
generated
vendored
Normal file
@@ -0,0 +1,175 @@
|
|||||||
|
/*
|
||||||
|
Copyright The containerd Authors.
|
||||||
|
|
||||||
|
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 adaptation
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/containerd/nri/pkg/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
//
|
||||||
|
// Alias types, consts and functions from api for the runtime.
|
||||||
|
//
|
||||||
|
|
||||||
|
// Aliased request/response/event types for api/api.proto.
|
||||||
|
// nolint
|
||||||
|
type (
|
||||||
|
RegisterPluginRequest = api.RegisterPluginRequest
|
||||||
|
RegisterPluginResponse = api.Empty
|
||||||
|
UpdateContainersRequest = api.UpdateContainersRequest
|
||||||
|
UpdateContainersResponse = api.UpdateContainersResponse
|
||||||
|
|
||||||
|
ConfigureRequest = api.ConfigureRequest
|
||||||
|
ConfigureResponse = api.ConfigureResponse
|
||||||
|
SynchronizeRequest = api.SynchronizeRequest
|
||||||
|
SynchronizeResponse = api.SynchronizeResponse
|
||||||
|
|
||||||
|
ShutdownRequest = api.Empty
|
||||||
|
ShutdownResponse = api.Empty
|
||||||
|
|
||||||
|
CreateContainerRequest = api.CreateContainerRequest
|
||||||
|
CreateContainerResponse = api.CreateContainerResponse
|
||||||
|
UpdateContainerRequest = api.UpdateContainerRequest
|
||||||
|
UpdateContainerResponse = api.UpdateContainerResponse
|
||||||
|
StopContainerRequest = api.StopContainerRequest
|
||||||
|
StopContainerResponse = api.StopContainerResponse
|
||||||
|
|
||||||
|
StateChangeEvent = api.StateChangeEvent
|
||||||
|
StateChangeResponse = api.StateChangeResponse
|
||||||
|
RunPodSandboxRequest = api.RunPodSandboxRequest
|
||||||
|
UpdatePodSandboxRequest = api.UpdatePodSandboxRequest
|
||||||
|
UpdatePodSandboxResponse = api.UpdatePodSandboxResponse
|
||||||
|
StopPodSandboxRequest = api.StopPodSandboxRequest
|
||||||
|
RemovePodSandboxRequest = api.RemovePodSandboxRequest
|
||||||
|
PostUpdatePodSandboxRequest = api.PostUpdatePodSandboxRequest
|
||||||
|
PostUpdatePodSandboxResponse = api.PostUpdatePodSandboxResponse
|
||||||
|
StartContainerRequest = api.StartContainerRequest
|
||||||
|
StartContainerResponse = api.StartContainerResponse
|
||||||
|
RemoveContainerRequest = api.RemoveContainerRequest
|
||||||
|
RemoveContainerResponse = api.RemoveContainerResponse
|
||||||
|
PostCreateContainerRequest = api.PostCreateContainerRequest
|
||||||
|
PostCreateContainerResponse = api.PostCreateContainerResponse
|
||||||
|
PostStartContainerRequest = api.PostStartContainerRequest
|
||||||
|
PostStartContainerResponse = api.PostStartContainerResponse
|
||||||
|
PostUpdateContainerRequest = api.PostUpdateContainerRequest
|
||||||
|
PostUpdateContainerResponse = api.PostUpdateContainerResponse
|
||||||
|
|
||||||
|
ValidateContainerAdjustmentRequest = api.ValidateContainerAdjustmentRequest
|
||||||
|
ValidateContainerAdjustmentResponse = api.ValidateContainerAdjustmentResponse
|
||||||
|
PluginInstance = api.PluginInstance
|
||||||
|
|
||||||
|
PodSandbox = api.PodSandbox
|
||||||
|
LinuxPodSandbox = api.LinuxPodSandbox
|
||||||
|
Container = api.Container
|
||||||
|
ContainerAdjustment = api.ContainerAdjustment
|
||||||
|
LinuxContainerAdjustment = api.LinuxContainerAdjustment
|
||||||
|
ContainerUpdate = api.ContainerUpdate
|
||||||
|
LinuxContainerUpdate = api.LinuxContainerUpdate
|
||||||
|
ContainerEviction = api.ContainerEviction
|
||||||
|
ContainerState = api.ContainerState
|
||||||
|
KeyValue = api.KeyValue
|
||||||
|
Mount = api.Mount
|
||||||
|
LinuxContainer = api.LinuxContainer
|
||||||
|
LinuxNamespace = api.LinuxNamespace
|
||||||
|
LinuxResources = api.LinuxResources
|
||||||
|
LinuxCPU = api.LinuxCPU
|
||||||
|
LinuxMemory = api.LinuxMemory
|
||||||
|
LinuxDevice = api.LinuxDevice
|
||||||
|
LinuxDeviceCgroup = api.LinuxDeviceCgroup
|
||||||
|
LinuxIOPriority = api.LinuxIOPriority
|
||||||
|
LinuxSeccomp = api.LinuxSeccomp
|
||||||
|
CDIDevice = api.CDIDevice
|
||||||
|
HugepageLimit = api.HugepageLimit
|
||||||
|
Hooks = api.Hooks
|
||||||
|
Hook = api.Hook
|
||||||
|
POSIXRlimit = api.POSIXRlimit
|
||||||
|
SecurityProfile = api.SecurityProfile
|
||||||
|
|
||||||
|
EventMask = api.EventMask
|
||||||
|
)
|
||||||
|
|
||||||
|
// Aliased consts for api/api.proto.
|
||||||
|
// nolint
|
||||||
|
const (
|
||||||
|
Event_UNKNOWN = api.Event_UNKNOWN
|
||||||
|
Event_RUN_POD_SANDBOX = api.Event_RUN_POD_SANDBOX
|
||||||
|
Event_UPDATE_POD_SANDBOX = api.Event_UPDATE_POD_SANDBOX
|
||||||
|
Event_POST_UPDATE_POD_SANDBOX = api.Event_POST_UPDATE_POD_SANDBOX
|
||||||
|
Event_STOP_POD_SANDBOX = api.Event_STOP_POD_SANDBOX
|
||||||
|
Event_REMOVE_POD_SANDBOX = api.Event_REMOVE_POD_SANDBOX
|
||||||
|
Event_CREATE_CONTAINER = api.Event_CREATE_CONTAINER
|
||||||
|
Event_POST_CREATE_CONTAINER = api.Event_POST_CREATE_CONTAINER
|
||||||
|
Event_START_CONTAINER = api.Event_START_CONTAINER
|
||||||
|
Event_POST_START_CONTAINER = api.Event_POST_START_CONTAINER
|
||||||
|
Event_UPDATE_CONTAINER = api.Event_UPDATE_CONTAINER
|
||||||
|
Event_POST_UPDATE_CONTAINER = api.Event_POST_UPDATE_CONTAINER
|
||||||
|
Event_STOP_CONTAINER = api.Event_STOP_CONTAINER
|
||||||
|
Event_REMOVE_CONTAINER = api.Event_REMOVE_CONTAINER
|
||||||
|
Event_VALIDATE_CONTAINER_ADJUSTMENT = api.Event_VALIDATE_CONTAINER_ADJUSTMENT
|
||||||
|
ValidEvents = api.ValidEvents
|
||||||
|
|
||||||
|
ContainerState_CONTAINER_UNKNOWN = api.ContainerState_CONTAINER_UNKNOWN
|
||||||
|
ContainerState_CONTAINER_CREATED = api.ContainerState_CONTAINER_CREATED
|
||||||
|
ContainerState_CONTAINER_PAUSED = api.ContainerState_CONTAINER_PAUSED
|
||||||
|
ContainerState_CONTAINER_RUNNING = api.ContainerState_CONTAINER_RUNNING
|
||||||
|
ContainerState_CONTAINER_STOPPED = api.ContainerState_CONTAINER_STOPPED
|
||||||
|
ContainerState_CONTAINER_EXITED = api.ContainerState_CONTAINER_STOPPED
|
||||||
|
|
||||||
|
SecurityProfile_RUNTIME_DEFAULT = api.SecurityProfile_RUNTIME_DEFAULT
|
||||||
|
SecurityProfile_UNCONFINED = api.SecurityProfile_UNCONFINED
|
||||||
|
SecurityProfile_LOCALHOST = api.SecurityProfile_LOCALHOST
|
||||||
|
)
|
||||||
|
|
||||||
|
// Aliased types for api/optional.go.
|
||||||
|
// nolint
|
||||||
|
type (
|
||||||
|
OptionalString = api.OptionalString
|
||||||
|
OptionalInt = api.OptionalInt
|
||||||
|
OptionalInt32 = api.OptionalInt32
|
||||||
|
OptionalUInt32 = api.OptionalUInt32
|
||||||
|
OptionalInt64 = api.OptionalInt64
|
||||||
|
OptionalUInt64 = api.OptionalUInt64
|
||||||
|
OptionalBool = api.OptionalBool
|
||||||
|
OptionalFileMode = api.OptionalFileMode
|
||||||
|
)
|
||||||
|
|
||||||
|
// Aliased functions for api/optional.go.
|
||||||
|
// nolint
|
||||||
|
var (
|
||||||
|
String = api.String
|
||||||
|
Int = api.Int
|
||||||
|
Int32 = api.Int32
|
||||||
|
UInt32 = api.UInt32
|
||||||
|
Int64 = api.Int64
|
||||||
|
UInt64 = api.UInt64
|
||||||
|
Bool = api.Bool
|
||||||
|
FileMode = api.FileMode
|
||||||
|
)
|
||||||
|
|
||||||
|
// Aliased functions for api/types.go.
|
||||||
|
// nolint
|
||||||
|
var (
|
||||||
|
FromOCIMounts = api.FromOCIMounts
|
||||||
|
FromOCIHooks = api.FromOCIHooks
|
||||||
|
FromOCILinuxNamespaces = api.FromOCILinuxNamespaces
|
||||||
|
FromOCILinuxDevices = api.FromOCILinuxDevices
|
||||||
|
FromOCILinuxResources = api.FromOCILinuxResources
|
||||||
|
FromOCILinuxIOPriority = api.FromOCILinuxIOPriority
|
||||||
|
DupStringSlice = api.DupStringSlice
|
||||||
|
DupStringMap = api.DupStringMap
|
||||||
|
IsMarkedForRemoval = api.IsMarkedForRemoval
|
||||||
|
MarkForRemoval = api.MarkForRemoval
|
||||||
|
)
|
||||||
210
vendor/github.com/containerd/nri/pkg/adaptation/builtin/plugin.go
generated
vendored
Normal file
210
vendor/github.com/containerd/nri/pkg/adaptation/builtin/plugin.go
generated
vendored
Normal file
@@ -0,0 +1,210 @@
|
|||||||
|
/*
|
||||||
|
Copyright The containerd Authors.
|
||||||
|
|
||||||
|
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 builtin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/containerd/nri/pkg/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
type BuiltinPlugin struct {
|
||||||
|
Base string
|
||||||
|
Index string
|
||||||
|
Handlers BuiltinHandlers
|
||||||
|
}
|
||||||
|
|
||||||
|
type BuiltinHandlers struct {
|
||||||
|
Configure func(context.Context, *api.ConfigureRequest) (*api.ConfigureResponse, error)
|
||||||
|
Synchronize func(context.Context, *api.SynchronizeRequest) (*api.SynchronizeResponse, error)
|
||||||
|
RunPodSandbox func(context.Context, *api.RunPodSandboxRequest) error
|
||||||
|
StopPodSandbox func(context.Context, *api.StopPodSandboxRequest) error
|
||||||
|
RemovePodSandbox func(context.Context, *api.RemovePodSandboxRequest) error
|
||||||
|
UpdatePodSandbox func(context.Context, *api.UpdatePodSandboxRequest) (*api.UpdatePodSandboxResponse, error)
|
||||||
|
PostUpdatePodSandbox func(context.Context, *api.PostUpdatePodSandboxRequest) error
|
||||||
|
|
||||||
|
CreateContainer func(context.Context, *api.CreateContainerRequest) (*api.CreateContainerResponse, error)
|
||||||
|
PostCreateContainer func(context.Context, *api.PostCreateContainerRequest) error
|
||||||
|
StartContainer func(context.Context, *api.StartContainerRequest) error
|
||||||
|
PostStartContainer func(context.Context, *api.PostStartContainerRequest) error
|
||||||
|
UpdateContainer func(context.Context, *api.UpdateContainerRequest) (*api.UpdateContainerResponse, error)
|
||||||
|
PostUpdateContainer func(context.Context, *api.PostUpdateContainerRequest) error
|
||||||
|
StopContainer func(context.Context, *api.StopContainerRequest) (*api.StopContainerResponse, error)
|
||||||
|
RemoveContainer func(context.Context, *api.RemoveContainerRequest) error
|
||||||
|
ValidateContainerAdjustment func(context.Context, *api.ValidateContainerAdjustmentRequest) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BuiltinPlugin) Configure(ctx context.Context, req *api.ConfigureRequest) (*api.ConfigureResponse, error) {
|
||||||
|
var (
|
||||||
|
rpl = &api.ConfigureResponse{}
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
|
||||||
|
if b.Handlers.Configure != nil {
|
||||||
|
rpl, err = b.Handlers.Configure(ctx, req)
|
||||||
|
}
|
||||||
|
|
||||||
|
if rpl.Events == 0 {
|
||||||
|
var events api.EventMask
|
||||||
|
|
||||||
|
if b.Handlers.RunPodSandbox != nil {
|
||||||
|
events.Set(api.Event_RUN_POD_SANDBOX)
|
||||||
|
}
|
||||||
|
if b.Handlers.StopPodSandbox != nil {
|
||||||
|
events.Set(api.Event_STOP_POD_SANDBOX)
|
||||||
|
}
|
||||||
|
if b.Handlers.RemovePodSandbox != nil {
|
||||||
|
events.Set(api.Event_REMOVE_POD_SANDBOX)
|
||||||
|
}
|
||||||
|
if b.Handlers.UpdatePodSandbox != nil {
|
||||||
|
events.Set(api.Event_UPDATE_POD_SANDBOX)
|
||||||
|
}
|
||||||
|
if b.Handlers.PostUpdatePodSandbox != nil {
|
||||||
|
events.Set(api.Event_POST_UPDATE_POD_SANDBOX)
|
||||||
|
}
|
||||||
|
if b.Handlers.CreateContainer != nil {
|
||||||
|
events.Set(api.Event_CREATE_CONTAINER)
|
||||||
|
}
|
||||||
|
if b.Handlers.PostCreateContainer != nil {
|
||||||
|
events.Set(api.Event_POST_CREATE_CONTAINER)
|
||||||
|
}
|
||||||
|
if b.Handlers.StartContainer != nil {
|
||||||
|
events.Set(api.Event_START_CONTAINER)
|
||||||
|
}
|
||||||
|
if b.Handlers.PostStartContainer != nil {
|
||||||
|
events.Set(api.Event_POST_START_CONTAINER)
|
||||||
|
}
|
||||||
|
if b.Handlers.UpdateContainer != nil {
|
||||||
|
events.Set(api.Event_UPDATE_CONTAINER)
|
||||||
|
}
|
||||||
|
if b.Handlers.PostUpdateContainer != nil {
|
||||||
|
events.Set(api.Event_POST_UPDATE_CONTAINER)
|
||||||
|
}
|
||||||
|
if b.Handlers.StopContainer != nil {
|
||||||
|
events.Set(api.Event_STOP_CONTAINER)
|
||||||
|
}
|
||||||
|
if b.Handlers.RemoveContainer != nil {
|
||||||
|
events.Set(api.Event_REMOVE_CONTAINER)
|
||||||
|
}
|
||||||
|
if b.Handlers.ValidateContainerAdjustment != nil {
|
||||||
|
events.Set(api.Event_VALIDATE_CONTAINER_ADJUSTMENT)
|
||||||
|
}
|
||||||
|
|
||||||
|
rpl.Events = int32(events)
|
||||||
|
}
|
||||||
|
|
||||||
|
return rpl, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BuiltinPlugin) Synchronize(ctx context.Context, req *api.SynchronizeRequest) (*api.SynchronizeResponse, error) {
|
||||||
|
if b.Handlers.Synchronize != nil {
|
||||||
|
return b.Handlers.Synchronize(ctx, req)
|
||||||
|
}
|
||||||
|
return &api.SynchronizeResponse{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BuiltinPlugin) Shutdown(context.Context, *api.ShutdownRequest) (*api.ShutdownResponse, error) {
|
||||||
|
return &api.ShutdownResponse{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BuiltinPlugin) CreateContainer(ctx context.Context, req *api.CreateContainerRequest) (*api.CreateContainerResponse, error) {
|
||||||
|
if b.Handlers.CreateContainer != nil {
|
||||||
|
return b.Handlers.CreateContainer(ctx, req)
|
||||||
|
}
|
||||||
|
return &api.CreateContainerResponse{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BuiltinPlugin) UpdateContainer(ctx context.Context, req *api.UpdateContainerRequest) (*api.UpdateContainerResponse, error) {
|
||||||
|
if b.Handlers.UpdateContainer != nil {
|
||||||
|
return b.Handlers.UpdateContainer(ctx, req)
|
||||||
|
}
|
||||||
|
return &api.UpdateContainerResponse{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BuiltinPlugin) StopContainer(ctx context.Context, req *api.StopContainerRequest) (*api.StopContainerResponse, error) {
|
||||||
|
if b.Handlers.StopContainer != nil {
|
||||||
|
return b.Handlers.StopContainer(ctx, req)
|
||||||
|
}
|
||||||
|
return &api.StopContainerResponse{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BuiltinPlugin) StateChange(ctx context.Context, evt *api.StateChangeEvent) (*api.StateChangeResponse, error) {
|
||||||
|
var err error
|
||||||
|
switch evt.Event {
|
||||||
|
case api.Event_RUN_POD_SANDBOX:
|
||||||
|
if b.Handlers.RunPodSandbox != nil {
|
||||||
|
err = b.Handlers.RunPodSandbox(ctx, evt)
|
||||||
|
}
|
||||||
|
case api.Event_STOP_POD_SANDBOX:
|
||||||
|
if b.Handlers.StopPodSandbox != nil {
|
||||||
|
err = b.Handlers.StopPodSandbox(ctx, evt)
|
||||||
|
}
|
||||||
|
case api.Event_REMOVE_POD_SANDBOX:
|
||||||
|
if b.Handlers.RemovePodSandbox != nil {
|
||||||
|
err = b.Handlers.RemovePodSandbox(ctx, evt)
|
||||||
|
}
|
||||||
|
case api.Event_POST_CREATE_CONTAINER:
|
||||||
|
if b.Handlers.PostCreateContainer != nil {
|
||||||
|
err = b.Handlers.PostCreateContainer(ctx, evt)
|
||||||
|
}
|
||||||
|
case api.Event_START_CONTAINER:
|
||||||
|
if b.Handlers.StartContainer != nil {
|
||||||
|
err = b.Handlers.StartContainer(ctx, evt)
|
||||||
|
}
|
||||||
|
case api.Event_POST_START_CONTAINER:
|
||||||
|
if b.Handlers.PostStartContainer != nil {
|
||||||
|
err = b.Handlers.PostStartContainer(ctx, evt)
|
||||||
|
}
|
||||||
|
case api.Event_POST_UPDATE_CONTAINER:
|
||||||
|
if b.Handlers.PostUpdateContainer != nil {
|
||||||
|
err = b.Handlers.PostUpdateContainer(ctx, evt)
|
||||||
|
}
|
||||||
|
case api.Event_REMOVE_CONTAINER:
|
||||||
|
if b.Handlers.RemoveContainer != nil {
|
||||||
|
err = b.Handlers.RemoveContainer(ctx, evt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &api.StateChangeResponse{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BuiltinPlugin) UpdatePodSandbox(ctx context.Context, req *api.UpdatePodSandboxRequest) (*api.UpdatePodSandboxResponse, error) {
|
||||||
|
if b.Handlers.UpdatePodSandbox != nil {
|
||||||
|
return b.Handlers.UpdatePodSandbox(ctx, req)
|
||||||
|
}
|
||||||
|
return &api.UpdatePodSandboxResponse{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BuiltinPlugin) PostUpdatePodSandbox(ctx context.Context, req *api.PostUpdatePodSandboxRequest) error {
|
||||||
|
if b.Handlers.PostUpdatePodSandbox != nil {
|
||||||
|
return b.Handlers.PostUpdatePodSandbox(ctx, req)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BuiltinPlugin) ValidateContainerAdjustment(ctx context.Context, req *api.ValidateContainerAdjustmentRequest) (*api.ValidateContainerAdjustmentResponse, error) {
|
||||||
|
if b.Handlers.ValidateContainerAdjustment != nil {
|
||||||
|
if err := b.Handlers.ValidateContainerAdjustment(ctx, req); err != nil {
|
||||||
|
return &api.ValidateContainerAdjustmentResponse{
|
||||||
|
Reject: true,
|
||||||
|
Reason: err.Error(),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &api.ValidateContainerAdjustmentResponse{}, nil
|
||||||
|
}
|
||||||
758
vendor/github.com/containerd/nri/pkg/adaptation/plugin.go
generated
vendored
Normal file
758
vendor/github.com/containerd/nri/pkg/adaptation/plugin.go
generated
vendored
Normal file
@@ -0,0 +1,758 @@
|
|||||||
|
/*
|
||||||
|
Copyright The containerd Authors.
|
||||||
|
|
||||||
|
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 adaptation
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
stdnet "net"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/containerd/nri/pkg/adaptation/builtin"
|
||||||
|
"github.com/containerd/nri/pkg/api"
|
||||||
|
"github.com/containerd/nri/pkg/log"
|
||||||
|
"github.com/containerd/nri/pkg/net"
|
||||||
|
"github.com/containerd/nri/pkg/net/multiplex"
|
||||||
|
"github.com/containerd/ttrpc"
|
||||||
|
"google.golang.org/grpc/codes"
|
||||||
|
"google.golang.org/grpc/status"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// DefaultPluginRegistrationTimeout is the default timeout for plugin registration.
|
||||||
|
DefaultPluginRegistrationTimeout = api.DefaultPluginRegistrationTimeout
|
||||||
|
// DefaultPluginRequestTimeout is the default timeout for plugins to handle a request.
|
||||||
|
DefaultPluginRequestTimeout = api.DefaultPluginRequestTimeout
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
pluginRegistrationTimeout = DefaultPluginRegistrationTimeout
|
||||||
|
pluginRequestTimeout = DefaultPluginRequestTimeout
|
||||||
|
timeoutCfgLock sync.RWMutex
|
||||||
|
)
|
||||||
|
|
||||||
|
type plugin struct {
|
||||||
|
sync.Mutex
|
||||||
|
idx string
|
||||||
|
base string
|
||||||
|
cfg string
|
||||||
|
pid int
|
||||||
|
cmd *exec.Cmd
|
||||||
|
mux multiplex.Mux
|
||||||
|
rpcc *ttrpc.Client
|
||||||
|
rpcl stdnet.Listener
|
||||||
|
rpcs *ttrpc.Server
|
||||||
|
events EventMask
|
||||||
|
closed bool
|
||||||
|
regC chan error
|
||||||
|
closeC chan struct{}
|
||||||
|
r *Adaptation
|
||||||
|
impl *pluginType
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetPluginRegistrationTimeout sets the timeout for plugin registration.
|
||||||
|
func SetPluginRegistrationTimeout(t time.Duration) {
|
||||||
|
timeoutCfgLock.Lock()
|
||||||
|
defer timeoutCfgLock.Unlock()
|
||||||
|
pluginRegistrationTimeout = t
|
||||||
|
}
|
||||||
|
|
||||||
|
func getPluginRegistrationTimeout() time.Duration {
|
||||||
|
timeoutCfgLock.RLock()
|
||||||
|
defer timeoutCfgLock.RUnlock()
|
||||||
|
return pluginRegistrationTimeout
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetPluginRequestTimeout sets the timeout for plugins to handle a request.
|
||||||
|
func SetPluginRequestTimeout(t time.Duration) {
|
||||||
|
timeoutCfgLock.Lock()
|
||||||
|
defer timeoutCfgLock.Unlock()
|
||||||
|
pluginRequestTimeout = t
|
||||||
|
}
|
||||||
|
|
||||||
|
func getPluginRequestTimeout() time.Duration {
|
||||||
|
timeoutCfgLock.RLock()
|
||||||
|
defer timeoutCfgLock.RUnlock()
|
||||||
|
return pluginRequestTimeout
|
||||||
|
}
|
||||||
|
|
||||||
|
// newLaunchedPlugin launches a pre-installed plugin with a pre-connected socketpair.
|
||||||
|
// If the plugin is a wasm binary, then it will use the internal wasm service
|
||||||
|
// to setup the plugin.
|
||||||
|
func (r *Adaptation) newLaunchedPlugin(dir, idx, base, cfg string) (p *plugin, retErr error) {
|
||||||
|
name := idx + "-" + base
|
||||||
|
fullPath := filepath.Join(dir, name)
|
||||||
|
|
||||||
|
if isWasm(fullPath) {
|
||||||
|
log.Infof(noCtx, "Found WASM plugin: %s", fullPath)
|
||||||
|
wasm, err := r.wasmService.Load(context.Background(), fullPath, wasmHostFunctions{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("load WASM plugin %s: %w", fullPath, err)
|
||||||
|
}
|
||||||
|
return &plugin{
|
||||||
|
cfg: cfg,
|
||||||
|
idx: idx,
|
||||||
|
base: base,
|
||||||
|
r: r,
|
||||||
|
impl: &pluginType{wasmImpl: wasm},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
sockets, err := net.NewSocketPair()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create plugin connection for plugin %q: %w", name, err)
|
||||||
|
}
|
||||||
|
defer sockets.Close()
|
||||||
|
|
||||||
|
conn, err := sockets.LocalConn()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to set up local connection for plugin %q: %w", name, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
peerFile := sockets.PeerFile()
|
||||||
|
defer func() {
|
||||||
|
peerFile.Close()
|
||||||
|
if retErr != nil {
|
||||||
|
conn.Close()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
cmd := exec.Command(fullPath)
|
||||||
|
cmd.ExtraFiles = []*os.File{peerFile}
|
||||||
|
cmd.Env = []string{
|
||||||
|
api.PluginNameEnvVar + "=" + base,
|
||||||
|
api.PluginIdxEnvVar + "=" + idx,
|
||||||
|
api.PluginSocketEnvVar + "=3",
|
||||||
|
}
|
||||||
|
|
||||||
|
p = &plugin{
|
||||||
|
cfg: cfg,
|
||||||
|
cmd: cmd,
|
||||||
|
idx: idx,
|
||||||
|
base: base,
|
||||||
|
regC: make(chan error, 1),
|
||||||
|
closeC: make(chan struct{}),
|
||||||
|
r: r,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = p.cmd.Start(); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to launch plugin %q: %w", p.name(), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = p.connect(conn); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return p, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Adaptation) newBuiltinPlugin(b *builtin.BuiltinPlugin) (*plugin, error) {
|
||||||
|
if b.Base == "" || b.Index == "" {
|
||||||
|
return nil, fmt.Errorf("builtin plugin without index or name (%q, %q)", b.Index, b.Base)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &plugin{
|
||||||
|
idx: b.Index,
|
||||||
|
base: b.Base,
|
||||||
|
closeC: make(chan struct{}),
|
||||||
|
r: r,
|
||||||
|
impl: &pluginType{builtinImpl: b},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func isWasm(path string) bool {
|
||||||
|
file, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf(noCtx, "Unable to open file %s: %v", path, err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
const headerLen = 8
|
||||||
|
buf := make([]byte, headerLen)
|
||||||
|
if _, err := file.Read(buf); err != nil {
|
||||||
|
log.Errorf(noCtx, "Unable to read file %s: %v", path, err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// WASM has starts with `\0asm`, followed by the version.
|
||||||
|
// http://webassembly.github.io/spec/core/binary/modules.html#binary-magic
|
||||||
|
return len(buf) >= headerLen &&
|
||||||
|
buf[0] == 0x00 && buf[1] == 0x61 &&
|
||||||
|
buf[2] == 0x73 && buf[3] == 0x6D &&
|
||||||
|
buf[4] == 0x01 && buf[5] == 0x00 &&
|
||||||
|
buf[6] == 0x00 && buf[7] == 0x00
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a plugin (stub) for an accepted external plugin connection.
|
||||||
|
func (r *Adaptation) newExternalPlugin(conn stdnet.Conn) (p *plugin, retErr error) {
|
||||||
|
p = &plugin{
|
||||||
|
regC: make(chan error, 1),
|
||||||
|
closeC: make(chan struct{}),
|
||||||
|
r: r,
|
||||||
|
}
|
||||||
|
if err := p.connect(conn); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return p, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get plugin-specific configuration for an NRI-launched plugin.
|
||||||
|
func (r *Adaptation) getPluginConfig(id, base string) (string, error) {
|
||||||
|
name := id + "-" + base
|
||||||
|
dropIns := []string{
|
||||||
|
filepath.Join(r.dropinPath, name+".conf"),
|
||||||
|
filepath.Join(r.dropinPath, base+".conf"),
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, path := range dropIns {
|
||||||
|
buf, err := os.ReadFile(path)
|
||||||
|
if err == nil {
|
||||||
|
return string(buf), nil
|
||||||
|
}
|
||||||
|
if !os.IsNotExist(err) {
|
||||||
|
return "", fmt.Errorf("failed to read configuration for plugin %q: %w", name, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the plugin is external (was not launched by us).
|
||||||
|
func (p *plugin) isExternal() bool {
|
||||||
|
return p.cmd == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the plugin is a container adjustment validator.
|
||||||
|
func (p *plugin) isContainerAdjustmentValidator() bool {
|
||||||
|
return p.events.IsSet(Event_VALIDATE_CONTAINER_ADJUSTMENT)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 'connect' a plugin, setting up multiplexing on its socket.
|
||||||
|
func (p *plugin) connect(conn stdnet.Conn) (retErr error) {
|
||||||
|
mux := multiplex.Multiplex(conn, multiplex.WithBlockedRead())
|
||||||
|
defer func() {
|
||||||
|
if retErr != nil {
|
||||||
|
mux.Close()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
pconn, err := mux.Open(multiplex.PluginServiceConn)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to mux plugin connection for plugin %q: %w", p.name(), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
clientOpts := []ttrpc.ClientOpts{
|
||||||
|
ttrpc.WithOnClose(
|
||||||
|
func() {
|
||||||
|
log.Infof(noCtx, "connection to plugin %q closed", p.name())
|
||||||
|
close(p.closeC)
|
||||||
|
p.close()
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
rpcc := ttrpc.NewClient(pconn, append(clientOpts, p.r.clientOpts...)...)
|
||||||
|
defer func() {
|
||||||
|
if retErr != nil {
|
||||||
|
rpcc.Close()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
rpcs, err := ttrpc.NewServer(p.r.serverOpts...)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create ttrpc server for plugin %q: %w", p.name(), err)
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
if retErr != nil {
|
||||||
|
rpcs.Close()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
rpcl, err := mux.Listen(multiplex.RuntimeServiceConn)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create mux runtime listener for plugin %q: %w", p.name(), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
p.mux = mux
|
||||||
|
p.rpcc = rpcc
|
||||||
|
p.rpcl = rpcl
|
||||||
|
p.rpcs = rpcs
|
||||||
|
p.impl = &pluginType{ttrpcImpl: api.NewPluginClient(rpcc)}
|
||||||
|
|
||||||
|
p.pid, err = getPeerPid(p.mux.Trunk())
|
||||||
|
if err != nil {
|
||||||
|
log.Warnf(noCtx, "failed to determine plugin pid: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
api.RegisterRuntimeService(p.rpcs, p)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start Runtime service, wait for plugin to register, then configure it.
|
||||||
|
func (p *plugin) start(name, version string) (err error) {
|
||||||
|
// skip start for WASM and builtin plugins and head right to the registration for
|
||||||
|
// events config
|
||||||
|
if p.impl.isTtrpc() {
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
timeout = getPluginRegistrationTimeout()
|
||||||
|
)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
err := p.rpcs.Serve(context.Background(), p.rpcl)
|
||||||
|
if err != ttrpc.ErrServerClosed {
|
||||||
|
log.Infof(noCtx, "ttrpc server for plugin %q closed (%v)", p.name(), err)
|
||||||
|
}
|
||||||
|
p.close()
|
||||||
|
}()
|
||||||
|
|
||||||
|
p.mux.Unblock()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case err = <-p.regC:
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to register plugin: %w", err)
|
||||||
|
}
|
||||||
|
case <-p.closeC:
|
||||||
|
return fmt.Errorf("failed to register plugin, connection closed")
|
||||||
|
case <-time.After(timeout):
|
||||||
|
p.close()
|
||||||
|
p.stop()
|
||||||
|
return errors.New("plugin registration timed out")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = p.configure(context.Background(), name, version, p.cfg)
|
||||||
|
if err != nil {
|
||||||
|
p.close()
|
||||||
|
p.stop()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// close a plugin shutting down its multiplexed ttrpc connections.
|
||||||
|
func (p *plugin) close() {
|
||||||
|
if p.impl.isWasm() || p.impl.isBuiltin() {
|
||||||
|
p.closed = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
p.Lock()
|
||||||
|
defer p.Unlock()
|
||||||
|
if p.closed {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
p.closed = true
|
||||||
|
p.mux.Close()
|
||||||
|
p.rpcc.Close()
|
||||||
|
p.rpcs.Close()
|
||||||
|
p.rpcl.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *plugin) isClosed() bool {
|
||||||
|
p.Lock()
|
||||||
|
defer p.Unlock()
|
||||||
|
return p.closed
|
||||||
|
}
|
||||||
|
|
||||||
|
// stop a plugin (if it was launched by us)
|
||||||
|
func (p *plugin) stop() error {
|
||||||
|
if p.isExternal() || p.cmd.Process == nil || p.impl.isWasm() || p.impl.isBuiltin() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(klihub):
|
||||||
|
// We should attempt a graceful shutdown of the process here...
|
||||||
|
// - send it SIGINT
|
||||||
|
// - give the it some slack waiting with a timeout
|
||||||
|
// - butcher it with SIGKILL after the timeout
|
||||||
|
|
||||||
|
p.cmd.Process.Kill()
|
||||||
|
p.cmd.Process.Wait()
|
||||||
|
p.cmd.Process.Release()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name returns a string indentication for the plugin.
|
||||||
|
func (p *plugin) name() string {
|
||||||
|
return p.idx + "-" + p.base
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *plugin) qualifiedName() string {
|
||||||
|
var kind, idx, base, pid string
|
||||||
|
if p.impl.isBuiltin() {
|
||||||
|
kind = "builtin"
|
||||||
|
} else {
|
||||||
|
if p.isExternal() {
|
||||||
|
kind = "external"
|
||||||
|
} else {
|
||||||
|
kind = "pre-connected"
|
||||||
|
}
|
||||||
|
if p.impl.isWasm() {
|
||||||
|
kind += "-wasm"
|
||||||
|
} else {
|
||||||
|
pid = "[" + strconv.Itoa(p.pid) + "]"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if idx = p.idx; idx == "" {
|
||||||
|
idx = "??"
|
||||||
|
}
|
||||||
|
if base = p.base; base == "" {
|
||||||
|
base = "plugin"
|
||||||
|
}
|
||||||
|
return kind + ":" + idx + "-" + base + pid
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterPlugin handles the plugin's registration request.
|
||||||
|
func (p *plugin) RegisterPlugin(ctx context.Context, req *RegisterPluginRequest) (*RegisterPluginResponse, error) {
|
||||||
|
if p.isExternal() {
|
||||||
|
if req.PluginName == "" {
|
||||||
|
p.regC <- fmt.Errorf("plugin %q registered with an empty name", p.qualifiedName())
|
||||||
|
return &RegisterPluginResponse{}, errors.New("invalid (empty) plugin name")
|
||||||
|
}
|
||||||
|
if err := api.CheckPluginIndex(req.PluginIdx); err != nil {
|
||||||
|
p.regC <- fmt.Errorf("plugin %q registered with an invalid index: %w", req.PluginName, err)
|
||||||
|
return &RegisterPluginResponse{}, fmt.Errorf("invalid plugin index: %w", err)
|
||||||
|
}
|
||||||
|
p.base = req.PluginName
|
||||||
|
p.idx = req.PluginIdx
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Infof(ctx, "plugin %q registered as %q", p.qualifiedName(), p.name())
|
||||||
|
|
||||||
|
p.regC <- nil
|
||||||
|
return &RegisterPluginResponse{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateContainers relays container update request to the runtime.
|
||||||
|
func (p *plugin) UpdateContainers(ctx context.Context, req *UpdateContainersRequest) (*UpdateContainersResponse, error) {
|
||||||
|
log.Infof(ctx, "plugin %q requested container updates", p.name())
|
||||||
|
|
||||||
|
failed, err := p.r.updateContainers(ctx, req.Update)
|
||||||
|
return &UpdateContainersResponse{
|
||||||
|
Failed: failed,
|
||||||
|
}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// configure the plugin and subscribe it for the events it requested.
|
||||||
|
func (p *plugin) configure(ctx context.Context, name, version, config string) (err error) {
|
||||||
|
ctx, cancel := context.WithTimeout(ctx, getPluginRequestTimeout())
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
req := &ConfigureRequest{
|
||||||
|
Config: config,
|
||||||
|
RuntimeName: name,
|
||||||
|
RuntimeVersion: version,
|
||||||
|
RegistrationTimeout: getPluginRegistrationTimeout().Milliseconds(),
|
||||||
|
RequestTimeout: getPluginRequestTimeout().Milliseconds(),
|
||||||
|
}
|
||||||
|
|
||||||
|
rpl, err := p.impl.Configure(ctx, req)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to configure plugin: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
events := EventMask(rpl.Events)
|
||||||
|
if events != 0 {
|
||||||
|
if extra := events &^ ValidEvents; extra != 0 {
|
||||||
|
return fmt.Errorf("invalid plugin events: 0x%x", extra)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
events = ValidEvents
|
||||||
|
}
|
||||||
|
p.events = events
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// synchronize the plugin with the current state of the runtime.
|
||||||
|
func (p *plugin) synchronize(ctx context.Context, pods []*PodSandbox, containers []*Container) ([]*ContainerUpdate, error) {
|
||||||
|
log.Infof(ctx, "synchronizing plugin %s", p.name())
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(ctx, getPluginRequestTimeout())
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
var (
|
||||||
|
podsToSend = pods
|
||||||
|
ctrsToSend = containers
|
||||||
|
podsPerMsg = len(pods)
|
||||||
|
ctrsPerMsg = len(containers)
|
||||||
|
|
||||||
|
rpl *SynchronizeResponse
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
|
||||||
|
for {
|
||||||
|
req := &SynchronizeRequest{
|
||||||
|
Pods: podsToSend[:podsPerMsg],
|
||||||
|
Containers: ctrsToSend[:ctrsPerMsg],
|
||||||
|
More: len(podsToSend) > podsPerMsg || len(ctrsToSend) > ctrsPerMsg,
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf(ctx, "sending sync message, %d/%d, %d/%d (more: %v)",
|
||||||
|
len(req.Pods), len(podsToSend), len(req.Containers), len(ctrsToSend), req.More)
|
||||||
|
|
||||||
|
rpl, err = p.impl.Synchronize(ctx, req)
|
||||||
|
if err == nil {
|
||||||
|
if !req.More {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(rpl.Update) > 0 || rpl.More != req.More {
|
||||||
|
p.close()
|
||||||
|
return nil, fmt.Errorf("plugin does not handle split sync requests")
|
||||||
|
}
|
||||||
|
|
||||||
|
podsToSend = podsToSend[podsPerMsg:]
|
||||||
|
ctrsToSend = ctrsToSend[ctrsPerMsg:]
|
||||||
|
|
||||||
|
if podsPerMsg > len(podsToSend) {
|
||||||
|
podsPerMsg = len(podsToSend)
|
||||||
|
}
|
||||||
|
if ctrsPerMsg > len(ctrsToSend) {
|
||||||
|
ctrsPerMsg = len(ctrsToSend)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
podsPerMsg, ctrsPerMsg, err = recalcObjsPerSyncMsg(podsPerMsg, ctrsPerMsg, err)
|
||||||
|
if err != nil {
|
||||||
|
p.close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf(ctx, "oversized message, retrying in smaller chunks")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rpl.Update, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func recalcObjsPerSyncMsg(pods, ctrs int, err error) (int, int, error) {
|
||||||
|
const (
|
||||||
|
minObjsPerMsg = 8
|
||||||
|
)
|
||||||
|
|
||||||
|
if status.Code(err) != codes.ResourceExhausted {
|
||||||
|
return pods, ctrs, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if pods+ctrs <= minObjsPerMsg {
|
||||||
|
return pods, ctrs, fmt.Errorf("failed to synchronize plugin with split messages")
|
||||||
|
}
|
||||||
|
|
||||||
|
var e *ttrpc.OversizedMessageErr
|
||||||
|
if !errors.As(err, &e) {
|
||||||
|
return pods, ctrs, fmt.Errorf("failed to synchronize plugin with split messages")
|
||||||
|
}
|
||||||
|
|
||||||
|
maxLen := e.MaximumLength()
|
||||||
|
msgLen := e.RejectedLength()
|
||||||
|
|
||||||
|
if msgLen == 0 || maxLen == 0 || msgLen <= maxLen {
|
||||||
|
return pods, ctrs, fmt.Errorf("failed to synchronize plugin with split messages")
|
||||||
|
}
|
||||||
|
|
||||||
|
factor := float64(maxLen) / float64(msgLen)
|
||||||
|
if factor > 0.9 {
|
||||||
|
factor = 0.9
|
||||||
|
}
|
||||||
|
|
||||||
|
pods = int(float64(pods) * factor)
|
||||||
|
ctrs = int(float64(ctrs) * factor)
|
||||||
|
|
||||||
|
if pods+ctrs < minObjsPerMsg {
|
||||||
|
pods = minObjsPerMsg / 2
|
||||||
|
ctrs = minObjsPerMsg / 2
|
||||||
|
}
|
||||||
|
|
||||||
|
return pods, ctrs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Relay CreateContainer request to plugin.
|
||||||
|
func (p *plugin) createContainer(ctx context.Context, req *CreateContainerRequest) (*CreateContainerResponse, error) {
|
||||||
|
if !p.events.IsSet(Event_CREATE_CONTAINER) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(ctx, getPluginRequestTimeout())
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
rpl, err := p.impl.CreateContainer(ctx, req)
|
||||||
|
if err != nil {
|
||||||
|
if isFatalError(err) {
|
||||||
|
log.Errorf(ctx, "closing plugin %s, failed to handle CreateContainer request: %v",
|
||||||
|
p.name(), err)
|
||||||
|
p.close()
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return rpl, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Relay UpdateContainer request to plugin.
|
||||||
|
func (p *plugin) updateContainer(ctx context.Context, req *UpdateContainerRequest) (*UpdateContainerResponse, error) {
|
||||||
|
if !p.events.IsSet(Event_UPDATE_CONTAINER) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(ctx, getPluginRequestTimeout())
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
rpl, err := p.impl.UpdateContainer(ctx, req)
|
||||||
|
if err != nil {
|
||||||
|
if isFatalError(err) {
|
||||||
|
log.Errorf(ctx, "closing plugin %s, failed to handle UpdateContainer request: %v",
|
||||||
|
p.name(), err)
|
||||||
|
p.close()
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return rpl, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Relay StopContainer request to the plugin.
|
||||||
|
func (p *plugin) stopContainer(ctx context.Context, req *StopContainerRequest) (rpl *StopContainerResponse, err error) {
|
||||||
|
if !p.events.IsSet(Event_STOP_CONTAINER) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(ctx, getPluginRequestTimeout())
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
rpl, err = p.impl.StopContainer(ctx, req)
|
||||||
|
if err != nil {
|
||||||
|
if isFatalError(err) {
|
||||||
|
log.Errorf(ctx, "closing plugin %s, failed to handle StopContainer request: %v",
|
||||||
|
p.name(), err)
|
||||||
|
p.close()
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return rpl, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *plugin) updatePodSandbox(ctx context.Context, req *UpdatePodSandboxRequest) (*UpdatePodSandboxResponse, error) {
|
||||||
|
if !p.events.IsSet(Event_UPDATE_POD_SANDBOX) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(ctx, getPluginRequestTimeout())
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
if _, err := p.impl.UpdatePodSandbox(ctx, req); err != nil {
|
||||||
|
if isFatalError(err) {
|
||||||
|
log.Errorf(ctx, "closing plugin %s, failed to handle event %d: %v",
|
||||||
|
p.name(), Event_UPDATE_POD_SANDBOX, err)
|
||||||
|
p.close()
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &UpdatePodSandboxResponse{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Relay other pod or container state change events to the plugin.
|
||||||
|
func (p *plugin) StateChange(ctx context.Context, evt *StateChangeEvent) (err error) {
|
||||||
|
if !p.events.IsSet(evt.Event) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(ctx, getPluginRequestTimeout())
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
if err = p.impl.StateChange(ctx, evt); err != nil {
|
||||||
|
if isFatalError(err) {
|
||||||
|
log.Errorf(ctx, "closing plugin %s, failed to handle event %d: %v",
|
||||||
|
p.name(), evt.Event, err)
|
||||||
|
p.close()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *plugin) ValidateContainerAdjustment(ctx context.Context, req *ValidateContainerAdjustmentRequest) error {
|
||||||
|
if !p.events.IsSet(Event_VALIDATE_CONTAINER_ADJUSTMENT) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(ctx, getPluginRequestTimeout())
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
rpl, err := p.impl.ValidateContainerAdjustment(ctx, req)
|
||||||
|
if err != nil {
|
||||||
|
if isFatalError(err) {
|
||||||
|
log.Errorf(ctx, "closing plugin %s, failed to validate request: %v", p.name(), err)
|
||||||
|
p.close()
|
||||||
|
}
|
||||||
|
return fmt.Errorf("validator plugin %s failed: %v", p.name(), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return rpl.ValidationResult(p.name())
|
||||||
|
}
|
||||||
|
|
||||||
|
// isFatalError returns true if the error is fatal and the plugin connection should be closed.
|
||||||
|
func isFatalError(err error) bool {
|
||||||
|
switch {
|
||||||
|
case errors.Is(err, ttrpc.ErrClosed):
|
||||||
|
return true
|
||||||
|
case errors.Is(err, ttrpc.ErrServerClosed):
|
||||||
|
return true
|
||||||
|
case errors.Is(err, ttrpc.ErrProtocol):
|
||||||
|
return true
|
||||||
|
case errors.Is(err, context.DeadlineExceeded):
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// wasmHostFunctions implements the webassembly host functions
|
||||||
|
type wasmHostFunctions struct{}
|
||||||
|
|
||||||
|
func (wasmHostFunctions) Log(ctx context.Context, request *api.LogRequest) (*api.Empty, error) {
|
||||||
|
switch request.GetLevel() {
|
||||||
|
case api.LogRequest_LEVEL_INFO:
|
||||||
|
log.Infof(ctx, request.GetMsg())
|
||||||
|
case api.LogRequest_LEVEL_WARN:
|
||||||
|
log.Warnf(ctx, request.GetMsg())
|
||||||
|
case api.LogRequest_LEVEL_ERROR:
|
||||||
|
log.Errorf(ctx, request.GetMsg())
|
||||||
|
default:
|
||||||
|
log.Debugf(ctx, request.GetMsg())
|
||||||
|
}
|
||||||
|
|
||||||
|
return &api.Empty{}, nil
|
||||||
|
}
|
||||||
54
vendor/github.com/containerd/nri/pkg/adaptation/plugin_linux.go
generated
vendored
Normal file
54
vendor/github.com/containerd/nri/pkg/adaptation/plugin_linux.go
generated
vendored
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
//go:build linux
|
||||||
|
|
||||||
|
/*
|
||||||
|
Copyright The containerd Authors.
|
||||||
|
|
||||||
|
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 adaptation
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
stdnet "net"
|
||||||
|
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
// getPeerPid returns the process id at the other end of the connection.
|
||||||
|
func getPeerPid(conn stdnet.Conn) (int, error) {
|
||||||
|
var cred *unix.Ucred
|
||||||
|
|
||||||
|
uc, ok := conn.(*stdnet.UnixConn)
|
||||||
|
if !ok {
|
||||||
|
return 0, errors.New("invalid connection, not *net.UnixConn")
|
||||||
|
}
|
||||||
|
|
||||||
|
raw, err := uc.SyscallConn()
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("failed to get raw unix domain connection: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctrlErr := raw.Control(func(fd uintptr) {
|
||||||
|
cred, err = unix.GetsockoptUcred(int(fd), unix.SOL_SOCKET, unix.SO_PEERCRED)
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("failed to get process credentials: %w", err)
|
||||||
|
}
|
||||||
|
if ctrlErr != nil {
|
||||||
|
return 0, fmt.Errorf("uc.SyscallConn().Control() failed: %w", ctrlErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
return int(cred.Pid), nil
|
||||||
|
}
|
||||||
30
vendor/github.com/containerd/nri/pkg/adaptation/plugin_other.go
generated
vendored
Normal file
30
vendor/github.com/containerd/nri/pkg/adaptation/plugin_other.go
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
//go:build !linux
|
||||||
|
|
||||||
|
/*
|
||||||
|
Copyright The containerd Authors.
|
||||||
|
|
||||||
|
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 adaptation
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
// getPeerPid returns the process id at the other end of the connection.
|
||||||
|
func getPeerPid(conn net.Conn) (int, error) {
|
||||||
|
return 0, fmt.Errorf("getPeerPid() unimplemented on %s", runtime.GOOS)
|
||||||
|
}
|
||||||
151
vendor/github.com/containerd/nri/pkg/adaptation/plugin_type.go
generated
vendored
Normal file
151
vendor/github.com/containerd/nri/pkg/adaptation/plugin_type.go
generated
vendored
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
/*
|
||||||
|
Copyright The containerd Authors.
|
||||||
|
|
||||||
|
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 adaptation
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/containerd/nri/pkg/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
type pluginType struct {
|
||||||
|
wasmImpl api.Plugin
|
||||||
|
ttrpcImpl api.PluginService
|
||||||
|
builtinImpl api.PluginService
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
errUnknownImpl = errors.New("unknown plugin implementation type")
|
||||||
|
)
|
||||||
|
|
||||||
|
func (p *pluginType) isWasm() bool {
|
||||||
|
return p.wasmImpl != nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *pluginType) isTtrpc() bool {
|
||||||
|
return p.ttrpcImpl != nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *pluginType) isBuiltin() bool {
|
||||||
|
return p.builtinImpl != nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *pluginType) Synchronize(ctx context.Context, req *SynchronizeRequest) (*SynchronizeResponse, error) {
|
||||||
|
switch {
|
||||||
|
case p.ttrpcImpl != nil:
|
||||||
|
return p.ttrpcImpl.Synchronize(ctx, req)
|
||||||
|
case p.builtinImpl != nil:
|
||||||
|
return p.builtinImpl.Synchronize(ctx, req)
|
||||||
|
case p.wasmImpl != nil:
|
||||||
|
return p.wasmImpl.Synchronize(ctx, req)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, errUnknownImpl
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *pluginType) Configure(ctx context.Context, req *ConfigureRequest) (*ConfigureResponse, error) {
|
||||||
|
switch {
|
||||||
|
case p.ttrpcImpl != nil:
|
||||||
|
return p.ttrpcImpl.Configure(ctx, req)
|
||||||
|
case p.builtinImpl != nil:
|
||||||
|
return p.builtinImpl.Configure(ctx, req)
|
||||||
|
case p.wasmImpl != nil:
|
||||||
|
return p.wasmImpl.Configure(ctx, req)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, errUnknownImpl
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *pluginType) CreateContainer(ctx context.Context, req *CreateContainerRequest) (*CreateContainerResponse, error) {
|
||||||
|
switch {
|
||||||
|
case p.ttrpcImpl != nil:
|
||||||
|
return p.ttrpcImpl.CreateContainer(ctx, req)
|
||||||
|
case p.builtinImpl != nil:
|
||||||
|
return p.builtinImpl.CreateContainer(ctx, req)
|
||||||
|
case p.wasmImpl != nil:
|
||||||
|
return p.wasmImpl.CreateContainer(ctx, req)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, errUnknownImpl
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *pluginType) UpdateContainer(ctx context.Context, req *UpdateContainerRequest) (*UpdateContainerResponse, error) {
|
||||||
|
switch {
|
||||||
|
case p.ttrpcImpl != nil:
|
||||||
|
return p.ttrpcImpl.UpdateContainer(ctx, req)
|
||||||
|
case p.builtinImpl != nil:
|
||||||
|
return p.builtinImpl.UpdateContainer(ctx, req)
|
||||||
|
case p.wasmImpl != nil:
|
||||||
|
return p.wasmImpl.UpdateContainer(ctx, req)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, errUnknownImpl
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *pluginType) StopContainer(ctx context.Context, req *StopContainerRequest) (*StopContainerResponse, error) {
|
||||||
|
switch {
|
||||||
|
case p.ttrpcImpl != nil:
|
||||||
|
return p.ttrpcImpl.StopContainer(ctx, req)
|
||||||
|
case p.builtinImpl != nil:
|
||||||
|
return p.builtinImpl.StopContainer(ctx, req)
|
||||||
|
case p.wasmImpl != nil:
|
||||||
|
return p.wasmImpl.StopContainer(ctx, req)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, errUnknownImpl
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *pluginType) UpdatePodSandbox(ctx context.Context, req *UpdatePodSandboxRequest) (*UpdatePodSandboxResponse, error) {
|
||||||
|
switch {
|
||||||
|
case p.ttrpcImpl != nil:
|
||||||
|
return p.ttrpcImpl.UpdatePodSandbox(ctx, req)
|
||||||
|
case p.builtinImpl != nil:
|
||||||
|
return p.builtinImpl.UpdatePodSandbox(ctx, req)
|
||||||
|
case p.wasmImpl != nil:
|
||||||
|
return p.wasmImpl.UpdatePodSandbox(ctx, req)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, errUnknownImpl
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *pluginType) StateChange(ctx context.Context, req *StateChangeEvent) (err error) {
|
||||||
|
switch {
|
||||||
|
case p.ttrpcImpl != nil:
|
||||||
|
_, err = p.ttrpcImpl.StateChange(ctx, req)
|
||||||
|
case p.builtinImpl != nil:
|
||||||
|
_, err = p.builtinImpl.StateChange(ctx, req)
|
||||||
|
case p.wasmImpl != nil:
|
||||||
|
_, err = p.wasmImpl.StateChange(ctx, req)
|
||||||
|
default:
|
||||||
|
err = errUnknownImpl
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *pluginType) ValidateContainerAdjustment(ctx context.Context, req *ValidateContainerAdjustmentRequest) (*ValidateContainerAdjustmentResponse, error) {
|
||||||
|
switch {
|
||||||
|
case p.ttrpcImpl != nil:
|
||||||
|
return p.ttrpcImpl.ValidateContainerAdjustment(ctx, req)
|
||||||
|
case p.builtinImpl != nil:
|
||||||
|
return p.builtinImpl.ValidateContainerAdjustment(ctx, req)
|
||||||
|
case p.wasmImpl != nil:
|
||||||
|
return p.wasmImpl.ValidateContainerAdjustment(ctx, req)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, errUnknownImpl
|
||||||
|
}
|
||||||
1069
vendor/github.com/containerd/nri/pkg/adaptation/result.go
generated
vendored
Normal file
1069
vendor/github.com/containerd/nri/pkg/adaptation/result.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
380
vendor/github.com/containerd/nri/pkg/api/adjustment.go
generated
vendored
Normal file
380
vendor/github.com/containerd/nri/pkg/api/adjustment.go
generated
vendored
Normal file
@@ -0,0 +1,380 @@
|
|||||||
|
/*
|
||||||
|
Copyright The containerd Authors.
|
||||||
|
|
||||||
|
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 api
|
||||||
|
|
||||||
|
import "slices"
|
||||||
|
|
||||||
|
//
|
||||||
|
// Notes:
|
||||||
|
// Adjustment of metadata that is stored in maps (labels and annotations)
|
||||||
|
// currently assumes that a single plugin will never do an add prior to a
|
||||||
|
// delete for any key. IOW, it is always assumed that if both a deletion
|
||||||
|
// and an addition/setting was recorded for a key then the final desired
|
||||||
|
// state is the addition. This seems like a reasonably safe assumption. A
|
||||||
|
// removal is usually done only to protect against triggering the conflict
|
||||||
|
// in the runtime when a plugin intends to touch a key which is known to
|
||||||
|
// have been put there or already modified by another plugin.
|
||||||
|
//
|
||||||
|
// An alternative without this implicit ordering assumption would be to
|
||||||
|
// store the adjustment for such data as a sequence of add/del operations
|
||||||
|
// in a slice. At the moment that does not seem to be necessary.
|
||||||
|
//
|
||||||
|
|
||||||
|
// AddAnnotation records the addition of the annotation key=value.
|
||||||
|
func (a *ContainerAdjustment) AddAnnotation(key, value string) {
|
||||||
|
a.initAnnotations()
|
||||||
|
a.Annotations[key] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveAnnotation records the removal of the annotation for the given key.
|
||||||
|
// Normally it is an error for a plugin to try and alter an annotation
|
||||||
|
// touched by another plugin. However, this is not an error if the plugin
|
||||||
|
// removes that annotation prior to touching it.
|
||||||
|
func (a *ContainerAdjustment) RemoveAnnotation(key string) {
|
||||||
|
a.initAnnotations()
|
||||||
|
a.Annotations[MarkForRemoval(key)] = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddMount records the addition of a mount to a container.
|
||||||
|
func (a *ContainerAdjustment) AddMount(m *Mount) {
|
||||||
|
a.Mounts = append(a.Mounts, m) // TODO: should we dup m here ?
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveMount records the removal of a mount from a container.
|
||||||
|
// Normally it is an error for a plugin to try and alter a mount
|
||||||
|
// touched by another plugin. However, this is not an error if the
|
||||||
|
// plugin removes that mount prior to touching it.
|
||||||
|
func (a *ContainerAdjustment) RemoveMount(ContainerPath string) {
|
||||||
|
a.Mounts = append(a.Mounts, &Mount{
|
||||||
|
Destination: MarkForRemoval(ContainerPath),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddEnv records the addition of an environment variable to a container.
|
||||||
|
func (a *ContainerAdjustment) AddEnv(key, value string) {
|
||||||
|
a.Env = append(a.Env, &KeyValue{
|
||||||
|
Key: key,
|
||||||
|
Value: value,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveEnv records the removal of an environment variable from a container.
|
||||||
|
// Normally it is an error for a plugin to try and alter an environment
|
||||||
|
// variable touched by another container. However, this is not an error if
|
||||||
|
// the plugin removes that variable prior to touching it.
|
||||||
|
func (a *ContainerAdjustment) RemoveEnv(key string) {
|
||||||
|
a.Env = append(a.Env, &KeyValue{
|
||||||
|
Key: MarkForRemoval(key),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetArgs overrides the container command with the given arguments.
|
||||||
|
func (a *ContainerAdjustment) SetArgs(args []string) {
|
||||||
|
a.Args = slices.Clone(args)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateArgs overrides the container command with the given arguments.
|
||||||
|
// It won't fail if another plugin has already set the command line.
|
||||||
|
func (a *ContainerAdjustment) UpdateArgs(args []string) {
|
||||||
|
a.Args = append([]string{""}, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddHooks records the addition of the given hooks to a container.
|
||||||
|
func (a *ContainerAdjustment) AddHooks(h *Hooks) {
|
||||||
|
a.initHooks()
|
||||||
|
if h.Prestart != nil {
|
||||||
|
a.Hooks.Prestart = append(a.Hooks.Prestart, h.Prestart...)
|
||||||
|
}
|
||||||
|
if h.CreateRuntime != nil {
|
||||||
|
a.Hooks.CreateRuntime = append(a.Hooks.CreateRuntime, h.CreateRuntime...)
|
||||||
|
}
|
||||||
|
if h.CreateContainer != nil {
|
||||||
|
a.Hooks.CreateContainer = append(a.Hooks.CreateContainer, h.CreateContainer...)
|
||||||
|
}
|
||||||
|
if h.StartContainer != nil {
|
||||||
|
a.Hooks.StartContainer = append(a.Hooks.StartContainer, h.StartContainer...)
|
||||||
|
}
|
||||||
|
if h.Poststart != nil {
|
||||||
|
a.Hooks.Poststart = append(a.Hooks.Poststart, h.Poststart...)
|
||||||
|
}
|
||||||
|
if h.Poststop != nil {
|
||||||
|
a.Hooks.Poststop = append(a.Hooks.Poststop, h.Poststop...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ContainerAdjustment) AddRlimit(typ string, hard, soft uint64) {
|
||||||
|
a.initRlimits()
|
||||||
|
a.Rlimits = append(a.Rlimits, &POSIXRlimit{
|
||||||
|
Type: typ,
|
||||||
|
Hard: hard,
|
||||||
|
Soft: soft,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddDevice records the addition of the given device to a container.
|
||||||
|
func (a *ContainerAdjustment) AddDevice(d *LinuxDevice) {
|
||||||
|
a.initLinux()
|
||||||
|
a.Linux.Devices = append(a.Linux.Devices, d) // TODO: should we dup d here ?
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveDevice records the removal of a device from a container.
|
||||||
|
// Normally it is an error for a plugin to try and alter an device
|
||||||
|
// touched by another container. However, this is not an error if
|
||||||
|
// the plugin removes that device prior to touching it.
|
||||||
|
func (a *ContainerAdjustment) RemoveDevice(path string) {
|
||||||
|
a.initLinux()
|
||||||
|
a.Linux.Devices = append(a.Linux.Devices, &LinuxDevice{
|
||||||
|
Path: MarkForRemoval(path),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddCDIDevice records the addition of the given CDI device to a container.
|
||||||
|
func (a *ContainerAdjustment) AddCDIDevice(d *CDIDevice) {
|
||||||
|
a.CDIDevices = append(a.CDIDevices, d) // TODO: should we dup d here ?
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddOrReplaceNamespace records the addition or replacement of the given namespace to a container.
|
||||||
|
func (a *ContainerAdjustment) AddOrReplaceNamespace(n *LinuxNamespace) {
|
||||||
|
a.initLinuxNamespaces()
|
||||||
|
a.Linux.Namespaces = append(a.Linux.Namespaces, n) // TODO: should we dup n here ?
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveNamespace records the removal of the given namespace from a container.
|
||||||
|
func (a *ContainerAdjustment) RemoveNamespace(n *LinuxNamespace) {
|
||||||
|
a.initLinuxNamespaces()
|
||||||
|
a.Linux.Namespaces = append(a.Linux.Namespaces, &LinuxNamespace{
|
||||||
|
Type: MarkForRemoval(n.Type),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLinuxMemoryLimit records setting the memory limit for a container.
|
||||||
|
func (a *ContainerAdjustment) SetLinuxMemoryLimit(value int64) {
|
||||||
|
a.initLinuxResourcesMemory()
|
||||||
|
a.Linux.Resources.Memory.Limit = Int64(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLinuxMemoryReservation records setting the memory reservation for a container.
|
||||||
|
func (a *ContainerAdjustment) SetLinuxMemoryReservation(value int64) {
|
||||||
|
a.initLinuxResourcesMemory()
|
||||||
|
a.Linux.Resources.Memory.Reservation = Int64(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLinuxMemorySwap records records setting the memory swap limit for a container.
|
||||||
|
func (a *ContainerAdjustment) SetLinuxMemorySwap(value int64) {
|
||||||
|
a.initLinuxResourcesMemory()
|
||||||
|
a.Linux.Resources.Memory.Swap = Int64(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLinuxMemoryKernel records setting the memory kernel limit for a container.
|
||||||
|
func (a *ContainerAdjustment) SetLinuxMemoryKernel(value int64) {
|
||||||
|
a.initLinuxResourcesMemory()
|
||||||
|
a.Linux.Resources.Memory.Kernel = Int64(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLinuxMemoryKernelTCP records setting the memory kernel TCP limit for a container.
|
||||||
|
func (a *ContainerAdjustment) SetLinuxMemoryKernelTCP(value int64) {
|
||||||
|
a.initLinuxResourcesMemory()
|
||||||
|
a.Linux.Resources.Memory.KernelTcp = Int64(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLinuxMemorySwappiness records setting the memory swappiness for a container.
|
||||||
|
func (a *ContainerAdjustment) SetLinuxMemorySwappiness(value uint64) {
|
||||||
|
a.initLinuxResourcesMemory()
|
||||||
|
a.Linux.Resources.Memory.Swappiness = UInt64(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLinuxMemoryDisableOomKiller records disabling the OOM killer for a container.
|
||||||
|
func (a *ContainerAdjustment) SetLinuxMemoryDisableOomKiller() {
|
||||||
|
a.initLinuxResourcesMemory()
|
||||||
|
a.Linux.Resources.Memory.DisableOomKiller = Bool(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLinuxMemoryUseHierarchy records enabling hierarchical memory accounting for a container.
|
||||||
|
func (a *ContainerAdjustment) SetLinuxMemoryUseHierarchy() {
|
||||||
|
a.initLinuxResourcesMemory()
|
||||||
|
a.Linux.Resources.Memory.UseHierarchy = Bool(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLinuxCPUShares records setting the scheduler's CPU shares for a container.
|
||||||
|
func (a *ContainerAdjustment) SetLinuxCPUShares(value uint64) {
|
||||||
|
a.initLinuxResourcesCPU()
|
||||||
|
a.Linux.Resources.Cpu.Shares = UInt64(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLinuxCPUQuota records setting the scheduler's CPU quota for a container.
|
||||||
|
func (a *ContainerAdjustment) SetLinuxCPUQuota(value int64) {
|
||||||
|
a.initLinuxResourcesCPU()
|
||||||
|
a.Linux.Resources.Cpu.Quota = Int64(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLinuxCPUPeriod records setting the scheduler's CPU period for a container.
|
||||||
|
func (a *ContainerAdjustment) SetLinuxCPUPeriod(value int64) {
|
||||||
|
a.initLinuxResourcesCPU()
|
||||||
|
a.Linux.Resources.Cpu.Period = UInt64(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLinuxCPURealtimeRuntime records setting the scheduler's realtime runtime for a container.
|
||||||
|
func (a *ContainerAdjustment) SetLinuxCPURealtimeRuntime(value int64) {
|
||||||
|
a.initLinuxResourcesCPU()
|
||||||
|
a.Linux.Resources.Cpu.RealtimeRuntime = Int64(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLinuxCPURealtimePeriod records setting the scheduler's realtime period for a container.
|
||||||
|
func (a *ContainerAdjustment) SetLinuxCPURealtimePeriod(value uint64) {
|
||||||
|
a.initLinuxResourcesCPU()
|
||||||
|
a.Linux.Resources.Cpu.RealtimePeriod = UInt64(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLinuxCPUSetCPUs records setting the cpuset CPUs for a container.
|
||||||
|
func (a *ContainerAdjustment) SetLinuxCPUSetCPUs(value string) {
|
||||||
|
a.initLinuxResourcesCPU()
|
||||||
|
a.Linux.Resources.Cpu.Cpus = value
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLinuxCPUSetMems records setting the cpuset memory for a container.
|
||||||
|
func (a *ContainerAdjustment) SetLinuxCPUSetMems(value string) {
|
||||||
|
a.initLinuxResourcesCPU()
|
||||||
|
a.Linux.Resources.Cpu.Mems = value
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLinuxPidLimits records setting the pid max number for a container.
|
||||||
|
func (a *ContainerAdjustment) SetLinuxPidLimits(value int64) {
|
||||||
|
a.initLinuxResourcesPids()
|
||||||
|
a.Linux.Resources.Pids.Limit = value
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddLinuxHugepageLimit records adding a hugepage limit for a container.
|
||||||
|
func (a *ContainerAdjustment) AddLinuxHugepageLimit(pageSize string, value uint64) {
|
||||||
|
a.initLinuxResources()
|
||||||
|
a.Linux.Resources.HugepageLimits = append(a.Linux.Resources.HugepageLimits,
|
||||||
|
&HugepageLimit{
|
||||||
|
PageSize: pageSize,
|
||||||
|
Limit: value,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLinuxBlockIOClass records setting the Block I/O class for a container.
|
||||||
|
func (a *ContainerAdjustment) SetLinuxBlockIOClass(value string) {
|
||||||
|
a.initLinuxResources()
|
||||||
|
a.Linux.Resources.BlockioClass = String(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLinuxRDTClass records setting the RDT class for a container.
|
||||||
|
func (a *ContainerAdjustment) SetLinuxRDTClass(value string) {
|
||||||
|
a.initLinuxResources()
|
||||||
|
a.Linux.Resources.RdtClass = String(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddLinuxUnified sets a cgroupv2 unified resource.
|
||||||
|
func (a *ContainerAdjustment) AddLinuxUnified(key, value string) {
|
||||||
|
a.initLinuxResourcesUnified()
|
||||||
|
a.Linux.Resources.Unified[key] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLinuxCgroupsPath records setting the cgroups path for a container.
|
||||||
|
func (a *ContainerAdjustment) SetLinuxCgroupsPath(value string) {
|
||||||
|
a.initLinux()
|
||||||
|
a.Linux.CgroupsPath = value
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLinuxOomScoreAdj records setting the kernel's Out-Of-Memory (OOM) killer score for a container.
|
||||||
|
func (a *ContainerAdjustment) SetLinuxOomScoreAdj(value *int) {
|
||||||
|
a.initLinux()
|
||||||
|
a.Linux.OomScoreAdj = Int(value) // using Int(value) from ./options.go to optionally allocate a pointer to normalized copy of value
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLinuxIOPriority records setting the I/O priority for a container.
|
||||||
|
func (a *ContainerAdjustment) SetLinuxIOPriority(ioprio *LinuxIOPriority) {
|
||||||
|
a.initLinux()
|
||||||
|
a.Linux.IoPriority = ioprio
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLinuxSeccompPolicy overrides the container seccomp policy with the given arguments.
|
||||||
|
func (a *ContainerAdjustment) SetLinuxSeccompPolicy(seccomp *LinuxSeccomp) {
|
||||||
|
a.initLinux()
|
||||||
|
a.Linux.SeccompPolicy = seccomp
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Initializing a container adjustment and container update.
|
||||||
|
//
|
||||||
|
|
||||||
|
func (a *ContainerAdjustment) initAnnotations() {
|
||||||
|
if a.Annotations == nil {
|
||||||
|
a.Annotations = make(map[string]string)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ContainerAdjustment) initHooks() {
|
||||||
|
if a.Hooks == nil {
|
||||||
|
a.Hooks = &Hooks{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ContainerAdjustment) initRlimits() {
|
||||||
|
if a.Rlimits == nil {
|
||||||
|
a.Rlimits = []*POSIXRlimit{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ContainerAdjustment) initLinux() {
|
||||||
|
if a.Linux == nil {
|
||||||
|
a.Linux = &LinuxContainerAdjustment{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ContainerAdjustment) initLinuxNamespaces() {
|
||||||
|
a.initLinux()
|
||||||
|
if a.Linux.Namespaces == nil {
|
||||||
|
a.Linux.Namespaces = []*LinuxNamespace{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ContainerAdjustment) initLinuxResources() {
|
||||||
|
a.initLinux()
|
||||||
|
if a.Linux.Resources == nil {
|
||||||
|
a.Linux.Resources = &LinuxResources{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ContainerAdjustment) initLinuxResourcesMemory() {
|
||||||
|
a.initLinuxResources()
|
||||||
|
if a.Linux.Resources.Memory == nil {
|
||||||
|
a.Linux.Resources.Memory = &LinuxMemory{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ContainerAdjustment) initLinuxResourcesCPU() {
|
||||||
|
a.initLinuxResources()
|
||||||
|
if a.Linux.Resources.Cpu == nil {
|
||||||
|
a.Linux.Resources.Cpu = &LinuxCPU{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ContainerAdjustment) initLinuxResourcesPids() {
|
||||||
|
a.initLinuxResources()
|
||||||
|
if a.Linux.Resources.Pids == nil {
|
||||||
|
a.Linux.Resources.Pids = &LinuxPids{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ContainerAdjustment) initLinuxResourcesUnified() {
|
||||||
|
a.initLinuxResources()
|
||||||
|
if a.Linux.Resources.Unified == nil {
|
||||||
|
a.Linux.Resources.Unified = make(map[string]string)
|
||||||
|
}
|
||||||
|
}
|
||||||
6424
vendor/github.com/containerd/nri/pkg/api/api.pb.go
generated
vendored
Normal file
6424
vendor/github.com/containerd/nri/pkg/api/api.pb.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
668
vendor/github.com/containerd/nri/pkg/api/api.proto
generated
vendored
Normal file
668
vendor/github.com/containerd/nri/pkg/api/api.proto
generated
vendored
Normal file
@@ -0,0 +1,668 @@
|
|||||||
|
/*
|
||||||
|
Copyright The containerd Authors.
|
||||||
|
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package nri.pkg.api.v1alpha1;
|
||||||
|
|
||||||
|
option go_package = "github.com/containerd/nri/pkg/api;api";
|
||||||
|
|
||||||
|
// Runtime service is the public API runtimes expose for NRI plugins.
|
||||||
|
// On this interface RPC requests are initiated by the plugin. This
|
||||||
|
// only covers plugin registration and unsolicited container updates.
|
||||||
|
// The rest of the API is defined by the Plugin service.
|
||||||
|
service Runtime {
|
||||||
|
// RegisterPlugin registers the plugin with the runtime.
|
||||||
|
rpc RegisterPlugin(RegisterPluginRequest) returns (Empty);
|
||||||
|
// UpdateContainers requests unsolicited updates to a set of containers.
|
||||||
|
rpc UpdateContainers(UpdateContainersRequest) returns (UpdateContainersResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
message RegisterPluginRequest {
|
||||||
|
// Name of the plugin to register.
|
||||||
|
string plugin_name = 1;
|
||||||
|
// Plugin invocation index. Plugins are called in ascending index order.
|
||||||
|
string plugin_idx = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message UpdateContainersRequest {
|
||||||
|
// List of containers to update.
|
||||||
|
repeated ContainerUpdate update = 1;
|
||||||
|
// List of containers to evict.
|
||||||
|
repeated ContainerEviction evict = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message UpdateContainersResponse {
|
||||||
|
// Containers that the runtime failed to update.
|
||||||
|
repeated ContainerUpdate failed = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Plugin is the API NRI uses to interact with plugins. It is used to
|
||||||
|
// - configure a plugin and subscribe it for lifecycle events
|
||||||
|
// - synchronize the state of a plugin with that of the runtime
|
||||||
|
// - hook a plugin into the lifecycle events of its interest
|
||||||
|
//
|
||||||
|
// During configuration the plugin tells the runtime which lifecycle events
|
||||||
|
// it wishes to get hooked into. Once configured, the plugin is synchronized
|
||||||
|
// with the runtime by receiving the list of pods and containers known to
|
||||||
|
// the runtime. The plugin can request changes to any of the containers in
|
||||||
|
// response. After initial synchronization the plugin starts receiving the
|
||||||
|
// events it subscribed for as they occur in the runtime. For container
|
||||||
|
// creation, update, and stop events, the plugin can request changes, both
|
||||||
|
// to the container that triggered the event or any other existing container
|
||||||
|
// in the runtime.
|
||||||
|
//
|
||||||
|
// For a subset of the container lifecycle events, NRI defines an additional
|
||||||
|
// Post-variant of the event. These variants are defined for CreateContainer,
|
||||||
|
// StartContainer, and UpdateContainer. For creation and update, these events
|
||||||
|
// can be used by plugins to discover the full extent of changes applied to
|
||||||
|
// the container, including any changes made by other active plugins.
|
||||||
|
//
|
||||||
|
// go:plugin type=plugin version=1
|
||||||
|
service Plugin {
|
||||||
|
// Configure the plugin and get its event subscription.
|
||||||
|
rpc Configure(ConfigureRequest) returns (ConfigureResponse);
|
||||||
|
|
||||||
|
// Synchronize the plugin with the state of the runtime.
|
||||||
|
rpc Synchronize(SynchronizeRequest) returns (SynchronizeResponse);
|
||||||
|
|
||||||
|
// Shutdown a plugin (let it know the runtime is going down).
|
||||||
|
rpc Shutdown(Empty) returns (Empty);
|
||||||
|
|
||||||
|
// CreateContainer relays the corresponding request to the plugin. In
|
||||||
|
// response, the plugin can adjust the container being created, and
|
||||||
|
// update other containers in the runtime. Container adjustment can
|
||||||
|
// alter labels, annotations, mounts, devices, environment variables,
|
||||||
|
// OCI hooks, and assigned container resources. Updates can alter
|
||||||
|
// assigned container resources.
|
||||||
|
rpc CreateContainer(CreateContainerRequest) returns (CreateContainerResponse);
|
||||||
|
|
||||||
|
// UpdateContainer relays the corresponding request to the plugin.
|
||||||
|
// The plugin can alter how the container is updated and request updates
|
||||||
|
// to additional containers in the runtime.
|
||||||
|
rpc UpdateContainer(UpdateContainerRequest) returns (UpdateContainerResponse);
|
||||||
|
|
||||||
|
// StopContainer relays the corresponding request to the plugin. The plugin
|
||||||
|
// can update any of the remaining containers in the runtime in response.
|
||||||
|
rpc StopContainer(StopContainerRequest) returns (StopContainerResponse);
|
||||||
|
|
||||||
|
// UpdatePodSandbox relays the corresponding request to the plugin.
|
||||||
|
rpc UpdatePodSandbox(UpdatePodSandboxRequest) returns (UpdatePodSandboxResponse);
|
||||||
|
|
||||||
|
// StateChange relays any remaining pod or container lifecycle/state change
|
||||||
|
// events the plugin has subscribed for. These can be used to trigger any
|
||||||
|
// plugin-specific processing which needs to occur in connection with any of
|
||||||
|
// these events.
|
||||||
|
rpc StateChange(StateChangeEvent) returns (Empty);
|
||||||
|
|
||||||
|
// ValidateContainerAdjustment relays a container adjustment validation request
|
||||||
|
// to the plugin. Container creation will fail the plugin rejects the adjustments.
|
||||||
|
rpc ValidateContainerAdjustment(ValidateContainerAdjustmentRequest) returns (ValidateContainerAdjustmentResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
// go:plugin type=host
|
||||||
|
service HostFunctions {
|
||||||
|
// Log displays a log message
|
||||||
|
rpc Log(LogRequest) returns (Empty) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
message LogRequest {
|
||||||
|
string msg = 1;
|
||||||
|
|
||||||
|
enum Level {
|
||||||
|
LEVEL_UNSPECIFIED = 0;
|
||||||
|
LEVEL_DEBUG = 1;
|
||||||
|
LEVEL_INFO = 2;
|
||||||
|
LEVEL_WARN = 3;
|
||||||
|
LEVEL_ERROR = 4;
|
||||||
|
}
|
||||||
|
Level level = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message ConfigureRequest {
|
||||||
|
// Any plugin-specific data, if present among the NRI configuration.
|
||||||
|
string config = 1;
|
||||||
|
// Name of the runtime NRI is running in.
|
||||||
|
string runtime_name = 2;
|
||||||
|
// Version of the runtime NRI is running in.
|
||||||
|
string runtime_version = 3;
|
||||||
|
// Configured registration timeout in milliseconds.
|
||||||
|
int64 registration_timeout = 4;
|
||||||
|
// Configured request processing timeout in milliseconds.
|
||||||
|
int64 request_timeout = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
message ConfigureResponse {
|
||||||
|
// Events to subscribe the plugin for. Each bit set corresponds to an
|
||||||
|
// enumerated Event.
|
||||||
|
int32 events = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message SynchronizeRequest {
|
||||||
|
// Pods known to the runtime.
|
||||||
|
repeated PodSandbox pods = 1;
|
||||||
|
// Containers known to the runtime.
|
||||||
|
repeated Container containers = 2;
|
||||||
|
// Whether there are more pods and containers to follow.
|
||||||
|
bool more = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message SynchronizeResponse {
|
||||||
|
// Updates to containers requested by the plugin.
|
||||||
|
repeated ContainerUpdate update = 1;
|
||||||
|
// Whether the client is able to handle more advertised pods and containers.
|
||||||
|
bool more = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message CreateContainerRequest {
|
||||||
|
// Pod of container being created.
|
||||||
|
PodSandbox pod = 1;
|
||||||
|
// Container being created.
|
||||||
|
Container container = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message CreateContainerResponse {
|
||||||
|
// Requested adjustments to container being created.
|
||||||
|
ContainerAdjustment adjust = 1;
|
||||||
|
// Requested updates to other existing containers.
|
||||||
|
repeated ContainerUpdate update = 2;
|
||||||
|
// Requested eviction of existing containers.
|
||||||
|
repeated ContainerEviction evict = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message UpdateContainerRequest {
|
||||||
|
// Pod of container being updated.
|
||||||
|
PodSandbox pod = 1;
|
||||||
|
// Container being updated.
|
||||||
|
Container container = 2;
|
||||||
|
// Resources to update.
|
||||||
|
LinuxResources linux_resources = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message UpdateContainerResponse {
|
||||||
|
// Requested updates to containers.
|
||||||
|
repeated ContainerUpdate update = 1;
|
||||||
|
// Requested eviction of containers.
|
||||||
|
repeated ContainerEviction evict = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message StopContainerRequest {
|
||||||
|
// Pod of container being stopped.
|
||||||
|
PodSandbox pod = 1;
|
||||||
|
// Container being stopped.
|
||||||
|
Container container = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message StopContainerResponse {
|
||||||
|
// Requested updates to containers.
|
||||||
|
repeated ContainerUpdate update = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message UpdatePodSandboxRequest {
|
||||||
|
// Pod being updated.
|
||||||
|
PodSandbox pod = 1;
|
||||||
|
// Overhead associated with this pod.
|
||||||
|
LinuxResources overhead_linux_resources = 2;
|
||||||
|
// Sum of container resources for this pod.
|
||||||
|
LinuxResources linux_resources = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message UpdatePodSandboxResponse {}
|
||||||
|
|
||||||
|
message StateChangeEvent {
|
||||||
|
// Event type of notification.
|
||||||
|
Event event = 1;
|
||||||
|
// Pod this notification is sent for. If this event is related to a container,
|
||||||
|
// pod is set to the pod of the container.
|
||||||
|
PodSandbox pod = 2;
|
||||||
|
// Container this notification is sent for. If the event is related to a pod,
|
||||||
|
// container is nil.
|
||||||
|
Container container = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message ValidateContainerAdjustmentRequest {
|
||||||
|
// Pod of container being adjusted.
|
||||||
|
PodSandbox pod = 1;
|
||||||
|
// Container being adjusted in its pristine state.
|
||||||
|
Container container = 2;
|
||||||
|
// Pending container adjustments.
|
||||||
|
ContainerAdjustment adjust = 3;
|
||||||
|
// Pending updates to other containers.
|
||||||
|
repeated ContainerUpdate update = 4;
|
||||||
|
// Plugins that made the adjustments and updates.
|
||||||
|
OwningPlugins owners = 5;
|
||||||
|
// Plugins consulted for adjustments and updates.
|
||||||
|
repeated PluginInstance plugins = 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
message PluginInstance {
|
||||||
|
string name = 1;
|
||||||
|
string index = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message ValidateContainerAdjustmentResponse {
|
||||||
|
bool reject = 1;
|
||||||
|
string reason = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Empty response for those *Requests that are semantically events.
|
||||||
|
message Empty {}
|
||||||
|
|
||||||
|
// Events that plugins can subscribe to in ConfigureResponse.
|
||||||
|
enum Event {
|
||||||
|
UNKNOWN = 0;
|
||||||
|
RUN_POD_SANDBOX = 1;
|
||||||
|
STOP_POD_SANDBOX = 2;
|
||||||
|
REMOVE_POD_SANDBOX = 3;
|
||||||
|
CREATE_CONTAINER = 4;
|
||||||
|
POST_CREATE_CONTAINER = 5;
|
||||||
|
START_CONTAINER = 6;
|
||||||
|
POST_START_CONTAINER = 7;
|
||||||
|
UPDATE_CONTAINER = 8;
|
||||||
|
POST_UPDATE_CONTAINER = 9;
|
||||||
|
STOP_CONTAINER = 10;
|
||||||
|
REMOVE_CONTAINER = 11;
|
||||||
|
UPDATE_POD_SANDBOX = 12;
|
||||||
|
POST_UPDATE_POD_SANDBOX = 13;
|
||||||
|
VALIDATE_CONTAINER_ADJUSTMENT = 14;
|
||||||
|
LAST = 15;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pod metadata that is considered relevant for a plugin.
|
||||||
|
message PodSandbox {
|
||||||
|
string id = 1;
|
||||||
|
string name = 2;
|
||||||
|
string uid = 3;
|
||||||
|
string namespace = 4;
|
||||||
|
map<string, string> labels = 5;
|
||||||
|
map<string, string> annotations = 6;
|
||||||
|
string runtime_handler = 7;
|
||||||
|
LinuxPodSandbox linux = 8;
|
||||||
|
uint32 pid = 9; // for NRI v1 emulation
|
||||||
|
repeated string ips = 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
// PodSandbox linux-specific metadata
|
||||||
|
message LinuxPodSandbox {
|
||||||
|
LinuxResources pod_overhead = 1;
|
||||||
|
LinuxResources pod_resources = 2;
|
||||||
|
string cgroup_parent = 3;
|
||||||
|
string cgroups_path = 4; // for NRI v1 emulation
|
||||||
|
repeated LinuxNamespace namespaces = 5; // for NRI v1 emulation
|
||||||
|
LinuxResources resources = 6; // for NRI v1 emulation
|
||||||
|
}
|
||||||
|
|
||||||
|
// Container metadata that is considered relevant for a plugin.
|
||||||
|
message Container {
|
||||||
|
string id = 1;
|
||||||
|
string pod_sandbox_id = 2;
|
||||||
|
string name = 3;
|
||||||
|
ContainerState state = 4;
|
||||||
|
map<string, string> labels = 5;
|
||||||
|
map<string, string> annotations = 6;
|
||||||
|
repeated string args = 7;
|
||||||
|
repeated string env = 8;
|
||||||
|
repeated Mount mounts = 9;
|
||||||
|
Hooks hooks = 10;
|
||||||
|
LinuxContainer linux = 11;
|
||||||
|
uint32 pid = 12; // for NRI v1 emulation
|
||||||
|
repeated POSIXRlimit rlimits = 13;
|
||||||
|
int64 created_at = 14;
|
||||||
|
int64 started_at = 15;
|
||||||
|
int64 finished_at = 16;
|
||||||
|
int32 exit_code = 17;
|
||||||
|
string status_reason = 18;
|
||||||
|
string status_message = 19;
|
||||||
|
repeated CDIDevice CDI_devices = 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Possible container states.
|
||||||
|
enum ContainerState {
|
||||||
|
CONTAINER_UNKNOWN = 0;
|
||||||
|
CONTAINER_CREATED = 1;
|
||||||
|
CONTAINER_PAUSED = 2; // is this useful/necessary ?
|
||||||
|
CONTAINER_RUNNING = 3;
|
||||||
|
CONTAINER_STOPPED = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// A container mount.
|
||||||
|
message Mount {
|
||||||
|
string destination = 1;
|
||||||
|
string type = 2;
|
||||||
|
string source = 3;
|
||||||
|
repeated string options = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Container OCI hooks.
|
||||||
|
message Hooks {
|
||||||
|
repeated Hook prestart = 1;
|
||||||
|
repeated Hook create_runtime = 2;
|
||||||
|
repeated Hook create_container = 3;
|
||||||
|
repeated Hook start_container = 4;
|
||||||
|
repeated Hook poststart = 5;
|
||||||
|
repeated Hook poststop = 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
// One OCI hook.
|
||||||
|
message Hook {
|
||||||
|
string path = 1;
|
||||||
|
repeated string args = 2;
|
||||||
|
repeated string env = 3;
|
||||||
|
OptionalInt timeout = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Container (linux) metadata.
|
||||||
|
message LinuxContainer {
|
||||||
|
repeated LinuxNamespace namespaces = 1;
|
||||||
|
repeated LinuxDevice devices = 2;
|
||||||
|
LinuxResources resources = 3;
|
||||||
|
OptionalInt oom_score_adj = 4;
|
||||||
|
string cgroups_path = 5;
|
||||||
|
LinuxIOPriority io_priority = 6;
|
||||||
|
SecurityProfile seccomp_profile = 7;
|
||||||
|
LinuxSeccomp seccomp_policy = 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
// A linux namespace.
|
||||||
|
message LinuxNamespace {
|
||||||
|
string type = 1;
|
||||||
|
string path = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// A container (linux) device.
|
||||||
|
message LinuxDevice {
|
||||||
|
string path = 1;
|
||||||
|
string type = 2;
|
||||||
|
int64 major = 3;
|
||||||
|
int64 minor = 4;
|
||||||
|
OptionalFileMode file_mode = 5;
|
||||||
|
OptionalUInt32 uid = 6;
|
||||||
|
OptionalUInt32 gid = 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
// A linux device cgroup controller rule.
|
||||||
|
message LinuxDeviceCgroup {
|
||||||
|
bool allow = 1;
|
||||||
|
string type = 2;
|
||||||
|
OptionalInt64 major = 3;
|
||||||
|
OptionalInt64 minor = 4;
|
||||||
|
string access = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
// A CDI device reference.
|
||||||
|
message CDIDevice {
|
||||||
|
string name = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Container (linux) resources.
|
||||||
|
message LinuxResources {
|
||||||
|
LinuxMemory memory = 1;
|
||||||
|
LinuxCPU cpu = 2;
|
||||||
|
repeated HugepageLimit hugepage_limits = 3;
|
||||||
|
OptionalString blockio_class = 4;
|
||||||
|
OptionalString rdt_class = 5;
|
||||||
|
map<string, string> unified = 6;
|
||||||
|
repeated LinuxDeviceCgroup devices = 7; // for NRI v1 emulation
|
||||||
|
LinuxPids pids = 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Memory-related parts of (linux) resources.
|
||||||
|
message LinuxMemory {
|
||||||
|
OptionalInt64 limit = 1;
|
||||||
|
OptionalInt64 reservation = 2;
|
||||||
|
OptionalInt64 swap = 3;
|
||||||
|
OptionalInt64 kernel = 4;
|
||||||
|
OptionalInt64 kernel_tcp = 5;
|
||||||
|
OptionalUInt64 swappiness = 6;
|
||||||
|
OptionalBool disable_oom_killer = 7;
|
||||||
|
OptionalBool use_hierarchy = 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CPU-related parts of (linux) resources.
|
||||||
|
message LinuxCPU {
|
||||||
|
OptionalUInt64 shares = 1;
|
||||||
|
OptionalInt64 quota = 2;
|
||||||
|
OptionalUInt64 period = 3;
|
||||||
|
OptionalInt64 realtime_runtime = 4;
|
||||||
|
OptionalUInt64 realtime_period = 5;
|
||||||
|
string cpus = 6;
|
||||||
|
string mems = 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Container huge page limit.
|
||||||
|
message HugepageLimit {
|
||||||
|
string page_size = 1;
|
||||||
|
uint64 limit = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SecurityProfile for container.
|
||||||
|
message SecurityProfile {
|
||||||
|
enum ProfileType {
|
||||||
|
RUNTIME_DEFAULT = 0;
|
||||||
|
UNCONFINED = 1;
|
||||||
|
LOCALHOST = 2;
|
||||||
|
}
|
||||||
|
ProfileType profile_type = 1;
|
||||||
|
string localhost_ref = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Container rlimits
|
||||||
|
message POSIXRlimit {
|
||||||
|
string type = 1;
|
||||||
|
uint64 hard = 2;
|
||||||
|
uint64 soft = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pids-related parts of (linux) resources.
|
||||||
|
message LinuxPids {
|
||||||
|
int64 limit = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message LinuxIOPriority {
|
||||||
|
// Scheduling class of the IO priority.
|
||||||
|
IOPrioClass class = 1;
|
||||||
|
// The value of the IO priority.
|
||||||
|
int32 priority = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum IOPrioClass {
|
||||||
|
IOPRIO_CLASS_NONE = 0;
|
||||||
|
IOPRIO_CLASS_RT = 1;
|
||||||
|
IOPRIO_CLASS_BE = 2;
|
||||||
|
IOPRIO_CLASS_IDLE = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Requested adjustments to a container being created.
|
||||||
|
message ContainerAdjustment {
|
||||||
|
map<string, string> annotations = 2;
|
||||||
|
repeated Mount mounts = 3;
|
||||||
|
repeated KeyValue env = 4;
|
||||||
|
Hooks hooks = 5;
|
||||||
|
LinuxContainerAdjustment linux = 6;
|
||||||
|
repeated POSIXRlimit rlimits = 7;
|
||||||
|
repeated CDIDevice CDI_devices = 8;
|
||||||
|
repeated string args = 9;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adjustments to (linux) resources.
|
||||||
|
message LinuxContainerAdjustment {
|
||||||
|
repeated LinuxDevice devices = 1;
|
||||||
|
LinuxResources resources = 2;
|
||||||
|
string cgroups_path = 3;
|
||||||
|
OptionalInt oom_score_adj = 4;
|
||||||
|
LinuxIOPriority io_priority = 5;
|
||||||
|
LinuxSeccomp seccomp_policy = 6;
|
||||||
|
repeated LinuxNamespace namespaces = 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
message LinuxSeccomp {
|
||||||
|
string default_action = 1;
|
||||||
|
OptionalUInt32 default_errno = 2;
|
||||||
|
repeated string architectures = 3;
|
||||||
|
repeated string flags = 4;
|
||||||
|
string listener_path = 5;
|
||||||
|
string listener_metadata = 6;
|
||||||
|
repeated LinuxSyscall syscalls = 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
message LinuxSyscall {
|
||||||
|
repeated string names = 1;
|
||||||
|
string action = 2;
|
||||||
|
OptionalUInt32 errno_ret = 3;
|
||||||
|
repeated LinuxSeccompArg args = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
message LinuxSeccompArg {
|
||||||
|
uint32 index = 1;
|
||||||
|
uint64 value = 2;
|
||||||
|
uint64 value_two = 3;
|
||||||
|
string op = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Requested update to an already created container.
|
||||||
|
message ContainerUpdate {
|
||||||
|
string container_id = 1;
|
||||||
|
LinuxContainerUpdate linux = 2;
|
||||||
|
bool ignore_failure = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Updates to (linux) resources.
|
||||||
|
message LinuxContainerUpdate {
|
||||||
|
LinuxResources resources = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Request to evict (IOW unsolicitedly stop) a container.
|
||||||
|
message ContainerEviction {
|
||||||
|
// Container to evict.
|
||||||
|
string container_id = 1;
|
||||||
|
// Human-readable reason for eviction.
|
||||||
|
string reason = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// KeyValue represents an environment variable.
|
||||||
|
message KeyValue {
|
||||||
|
string key = 1;
|
||||||
|
string value = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// An optional string value.
|
||||||
|
message OptionalString {
|
||||||
|
string value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// An optional signed integer value.
|
||||||
|
message OptionalInt {
|
||||||
|
int64 value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// An optional 32-bit signed integer value.
|
||||||
|
message OptionalInt32 {
|
||||||
|
int32 value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// An optional 32-bit unsigned integer value.
|
||||||
|
message OptionalUInt32 {
|
||||||
|
uint32 value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// An optional 64-bit signed integer value.
|
||||||
|
message OptionalInt64 {
|
||||||
|
int64 value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// An optional 64-bit unsigned integer value.
|
||||||
|
message OptionalUInt64 {
|
||||||
|
uint64 value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// An optional boolean value.
|
||||||
|
message OptionalBool {
|
||||||
|
bool value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// An optional value of file permissions.
|
||||||
|
message OptionalFileMode {
|
||||||
|
uint32 value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CompoundFieldOwners tracks 'plugin ownership' of compound fields
|
||||||
|
// which can be adjusted entry by entry, typically maps or slices.
|
||||||
|
// It is used to track ownership for annotations, mounts, devices,
|
||||||
|
// environment variables, hugepage limits, etc. The key identifies
|
||||||
|
// the owned entry (annotation key, mount destination, device path,
|
||||||
|
// environment variable name, etc.). The value is the owning plugin.
|
||||||
|
message CompoundFieldOwners {
|
||||||
|
map<string, string> owners = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FieldOwners tracks field 'plugin ownership' for a single container.
|
||||||
|
// Keys represent adjustable fields of a container. For simple fields,
|
||||||
|
// the value is the plugin that last modified the field. For compound
|
||||||
|
// fields, the value is a CompoundFieldOwners which provides tracking
|
||||||
|
// 'plugin ownership' per field for compound data, typically maps and
|
||||||
|
// slices. Field enum values are used to index both maps, using Key()
|
||||||
|
// to get the int32 for the Field.
|
||||||
|
message FieldOwners {
|
||||||
|
map<int32, string> simple = 1;
|
||||||
|
map<int32, CompoundFieldOwners> compound = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// OwningPlugins tracks field 'plugin ownership' for multiple containers.
|
||||||
|
// The string keys are container IDs. The values are FieldOwners which
|
||||||
|
// track 'plugin ownership' per adjustable field for the container.
|
||||||
|
message OwningPlugins {
|
||||||
|
map<string, FieldOwners> owners = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Field enumerates all fields that can be adjusted by plugins.
|
||||||
|
enum Field {
|
||||||
|
None = 0;
|
||||||
|
Annotations = 1;
|
||||||
|
Mounts = 2;
|
||||||
|
OciHooks = 3;
|
||||||
|
Devices = 4;
|
||||||
|
CdiDevices = 5;
|
||||||
|
Env = 6;
|
||||||
|
Args = 7;
|
||||||
|
MemLimit = 8;
|
||||||
|
MemReservation = 9;
|
||||||
|
MemSwapLimit = 10;
|
||||||
|
MemKernelLimit = 11;
|
||||||
|
MemTCPLimit = 12;
|
||||||
|
MemSwappiness = 13;
|
||||||
|
MemDisableOomKiller = 14;
|
||||||
|
MemUseHierarchy = 15;
|
||||||
|
CPUShares = 16;
|
||||||
|
CPUQuota = 17;
|
||||||
|
CPUPeriod = 18;
|
||||||
|
CPURealtimeRuntime = 19;
|
||||||
|
CPURealtimePeriod = 20;
|
||||||
|
CPUSetCPUs = 21;
|
||||||
|
CPUSetMems = 22;
|
||||||
|
PidsLimit = 23;
|
||||||
|
HugepageLimits = 24;
|
||||||
|
BlockioClass = 25;
|
||||||
|
RdtClass = 26;
|
||||||
|
CgroupsUnified = 27;
|
||||||
|
CgroupsPath = 28;
|
||||||
|
OomScoreAdj = 29;
|
||||||
|
Rlimits = 30;
|
||||||
|
IoPriority = 31;
|
||||||
|
SeccompPolicy = 32;
|
||||||
|
Namespace = 33;
|
||||||
|
}
|
||||||
801
vendor/github.com/containerd/nri/pkg/api/api_host.pb.go
generated
vendored
Normal file
801
vendor/github.com/containerd/nri/pkg/api/api_host.pb.go
generated
vendored
Normal file
@@ -0,0 +1,801 @@
|
|||||||
|
//go:build !wasip1
|
||||||
|
|
||||||
|
//
|
||||||
|
//Copyright The containerd Authors.
|
||||||
|
//
|
||||||
|
//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.
|
||||||
|
|
||||||
|
// Code generated by protoc-gen-go-plugin. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// protoc-gen-go-plugin v0.1.0
|
||||||
|
// protoc v3.20.1
|
||||||
|
// source: pkg/api/api.proto
|
||||||
|
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
context "context"
|
||||||
|
errors "errors"
|
||||||
|
fmt "fmt"
|
||||||
|
wasm "github.com/knqyf263/go-plugin/wasm"
|
||||||
|
wazero "github.com/tetratelabs/wazero"
|
||||||
|
api "github.com/tetratelabs/wazero/api"
|
||||||
|
sys "github.com/tetratelabs/wazero/sys"
|
||||||
|
os "os"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
i32 = api.ValueTypeI32
|
||||||
|
i64 = api.ValueTypeI64
|
||||||
|
)
|
||||||
|
|
||||||
|
type _hostFunctions struct {
|
||||||
|
HostFunctions
|
||||||
|
}
|
||||||
|
|
||||||
|
// Instantiate a Go-defined module named "env" that exports host functions.
|
||||||
|
func (h _hostFunctions) Instantiate(ctx context.Context, r wazero.Runtime) error {
|
||||||
|
envBuilder := r.NewHostModuleBuilder("env")
|
||||||
|
|
||||||
|
envBuilder.NewFunctionBuilder().
|
||||||
|
WithGoModuleFunction(api.GoModuleFunc(h._Log), []api.ValueType{i32, i32}, []api.ValueType{i64}).
|
||||||
|
WithParameterNames("offset", "size").
|
||||||
|
Export("log")
|
||||||
|
|
||||||
|
_, err := envBuilder.Instantiate(ctx)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log displays a log message
|
||||||
|
|
||||||
|
func (h _hostFunctions) _Log(ctx context.Context, m api.Module, stack []uint64) {
|
||||||
|
offset, size := uint32(stack[0]), uint32(stack[1])
|
||||||
|
buf, err := wasm.ReadMemory(m.Memory(), offset, size)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
request := new(LogRequest)
|
||||||
|
err = request.UnmarshalVT(buf)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
resp, err := h.Log(ctx, request)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
buf, err = resp.MarshalVT()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
ptr, err := wasm.WriteMemory(ctx, m, buf)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
ptrLen := (ptr << uint64(32)) | uint64(len(buf))
|
||||||
|
stack[0] = ptrLen
|
||||||
|
}
|
||||||
|
|
||||||
|
const PluginPluginAPIVersion = 1
|
||||||
|
|
||||||
|
type PluginPlugin struct {
|
||||||
|
newRuntime func(context.Context) (wazero.Runtime, error)
|
||||||
|
moduleConfig wazero.ModuleConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPluginPlugin(ctx context.Context, opts ...wazeroConfigOption) (*PluginPlugin, error) {
|
||||||
|
o := &WazeroConfig{
|
||||||
|
newRuntime: DefaultWazeroRuntime(),
|
||||||
|
moduleConfig: wazero.NewModuleConfig().WithStartFunctions("_initialize"),
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(o)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &PluginPlugin{
|
||||||
|
newRuntime: o.newRuntime,
|
||||||
|
moduleConfig: o.moduleConfig,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type plugin interface {
|
||||||
|
Close(ctx context.Context) error
|
||||||
|
Plugin
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PluginPlugin) Load(ctx context.Context, pluginPath string, hostFunctions HostFunctions) (plugin, error) {
|
||||||
|
b, err := os.ReadFile(pluginPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new runtime so that multiple modules will not conflict
|
||||||
|
r, err := p.newRuntime(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
h := _hostFunctions{hostFunctions}
|
||||||
|
|
||||||
|
if err := h.Instantiate(ctx, r); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compile the WebAssembly module using the default configuration.
|
||||||
|
code, err := r.CompileModule(ctx, b)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// InstantiateModule runs the "_start" function, WASI's "main".
|
||||||
|
module, err := r.InstantiateModule(ctx, code, p.moduleConfig)
|
||||||
|
if err != nil {
|
||||||
|
// Note: Most compilers do not exit the module after running "_start",
|
||||||
|
// unless there was an Error. This allows you to call exported functions.
|
||||||
|
if exitErr, ok := err.(*sys.ExitError); ok && exitErr.ExitCode() != 0 {
|
||||||
|
return nil, fmt.Errorf("unexpected exit_code: %d", exitErr.ExitCode())
|
||||||
|
} else if !ok {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compare API versions with the loading plugin
|
||||||
|
apiVersion := module.ExportedFunction("plugin_api_version")
|
||||||
|
if apiVersion == nil {
|
||||||
|
return nil, errors.New("plugin_api_version is not exported")
|
||||||
|
}
|
||||||
|
results, err := apiVersion.Call(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if len(results) != 1 {
|
||||||
|
return nil, errors.New("invalid plugin_api_version signature")
|
||||||
|
}
|
||||||
|
if results[0] != PluginPluginAPIVersion {
|
||||||
|
return nil, fmt.Errorf("API version mismatch, host: %d, plugin: %d", PluginPluginAPIVersion, results[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
configure := module.ExportedFunction("plugin_configure")
|
||||||
|
if configure == nil {
|
||||||
|
return nil, errors.New("plugin_configure is not exported")
|
||||||
|
}
|
||||||
|
synchronize := module.ExportedFunction("plugin_synchronize")
|
||||||
|
if synchronize == nil {
|
||||||
|
return nil, errors.New("plugin_synchronize is not exported")
|
||||||
|
}
|
||||||
|
shutdown := module.ExportedFunction("plugin_shutdown")
|
||||||
|
if shutdown == nil {
|
||||||
|
return nil, errors.New("plugin_shutdown is not exported")
|
||||||
|
}
|
||||||
|
createcontainer := module.ExportedFunction("plugin_create_container")
|
||||||
|
if createcontainer == nil {
|
||||||
|
return nil, errors.New("plugin_create_container is not exported")
|
||||||
|
}
|
||||||
|
updatecontainer := module.ExportedFunction("plugin_update_container")
|
||||||
|
if updatecontainer == nil {
|
||||||
|
return nil, errors.New("plugin_update_container is not exported")
|
||||||
|
}
|
||||||
|
stopcontainer := module.ExportedFunction("plugin_stop_container")
|
||||||
|
if stopcontainer == nil {
|
||||||
|
return nil, errors.New("plugin_stop_container is not exported")
|
||||||
|
}
|
||||||
|
updatepodsandbox := module.ExportedFunction("plugin_update_pod_sandbox")
|
||||||
|
if updatepodsandbox == nil {
|
||||||
|
return nil, errors.New("plugin_update_pod_sandbox is not exported")
|
||||||
|
}
|
||||||
|
statechange := module.ExportedFunction("plugin_state_change")
|
||||||
|
if statechange == nil {
|
||||||
|
return nil, errors.New("plugin_state_change is not exported")
|
||||||
|
}
|
||||||
|
validatecontaineradjustment := module.ExportedFunction("plugin_validate_container_adjustment")
|
||||||
|
if validatecontaineradjustment == nil {
|
||||||
|
return nil, errors.New("plugin_validate_container_adjustment is not exported")
|
||||||
|
}
|
||||||
|
|
||||||
|
malloc := module.ExportedFunction("malloc")
|
||||||
|
if malloc == nil {
|
||||||
|
return nil, errors.New("malloc is not exported")
|
||||||
|
}
|
||||||
|
|
||||||
|
free := module.ExportedFunction("free")
|
||||||
|
if free == nil {
|
||||||
|
return nil, errors.New("free is not exported")
|
||||||
|
}
|
||||||
|
return &pluginPlugin{
|
||||||
|
runtime: r,
|
||||||
|
module: module,
|
||||||
|
malloc: malloc,
|
||||||
|
free: free,
|
||||||
|
configure: configure,
|
||||||
|
synchronize: synchronize,
|
||||||
|
shutdown: shutdown,
|
||||||
|
createcontainer: createcontainer,
|
||||||
|
updatecontainer: updatecontainer,
|
||||||
|
stopcontainer: stopcontainer,
|
||||||
|
updatepodsandbox: updatepodsandbox,
|
||||||
|
statechange: statechange,
|
||||||
|
validatecontaineradjustment: validatecontaineradjustment,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *pluginPlugin) Close(ctx context.Context) (err error) {
|
||||||
|
if r := p.runtime; r != nil {
|
||||||
|
r.Close(ctx)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
type pluginPlugin struct {
|
||||||
|
runtime wazero.Runtime
|
||||||
|
module api.Module
|
||||||
|
malloc api.Function
|
||||||
|
free api.Function
|
||||||
|
configure api.Function
|
||||||
|
synchronize api.Function
|
||||||
|
shutdown api.Function
|
||||||
|
createcontainer api.Function
|
||||||
|
updatecontainer api.Function
|
||||||
|
stopcontainer api.Function
|
||||||
|
updatepodsandbox api.Function
|
||||||
|
statechange api.Function
|
||||||
|
validatecontaineradjustment api.Function
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *pluginPlugin) Configure(ctx context.Context, request *ConfigureRequest) (*ConfigureResponse, error) {
|
||||||
|
data, err := request.MarshalVT()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
dataSize := uint64(len(data))
|
||||||
|
|
||||||
|
var dataPtr uint64
|
||||||
|
// If the input data is not empty, we must allocate the in-Wasm memory to store it, and pass to the plugin.
|
||||||
|
if dataSize != 0 {
|
||||||
|
results, err := p.malloc.Call(ctx, dataSize)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
dataPtr = results[0]
|
||||||
|
// This pointer is managed by the Wasm module, which is unaware of external usage.
|
||||||
|
// So, we have to free it when finished
|
||||||
|
defer p.free.Call(ctx, dataPtr)
|
||||||
|
|
||||||
|
// The pointer is a linear memory offset, which is where we write the name.
|
||||||
|
if !p.module.Memory().Write(uint32(dataPtr), data) {
|
||||||
|
return nil, fmt.Errorf("Memory.Write(%d, %d) out of range of memory size %d", dataPtr, dataSize, p.module.Memory().Size())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ptrSize, err := p.configure.Call(ctx, dataPtr, dataSize)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resPtr := uint32(ptrSize[0] >> 32)
|
||||||
|
resSize := uint32(ptrSize[0])
|
||||||
|
var isErrResponse bool
|
||||||
|
if (resSize & (1 << 31)) > 0 {
|
||||||
|
isErrResponse = true
|
||||||
|
resSize &^= (1 << 31)
|
||||||
|
}
|
||||||
|
|
||||||
|
// We don't need the memory after deserialization: make sure it is freed.
|
||||||
|
if resPtr != 0 {
|
||||||
|
defer p.free.Call(ctx, uint64(resPtr))
|
||||||
|
}
|
||||||
|
|
||||||
|
// The pointer is a linear memory offset, which is where we write the name.
|
||||||
|
bytes, ok := p.module.Memory().Read(resPtr, resSize)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("Memory.Read(%d, %d) out of range of memory size %d",
|
||||||
|
resPtr, resSize, p.module.Memory().Size())
|
||||||
|
}
|
||||||
|
|
||||||
|
if isErrResponse {
|
||||||
|
return nil, errors.New(string(bytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
response := new(ConfigureResponse)
|
||||||
|
if err = response.UnmarshalVT(bytes); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return response, nil
|
||||||
|
}
|
||||||
|
func (p *pluginPlugin) Synchronize(ctx context.Context, request *SynchronizeRequest) (*SynchronizeResponse, error) {
|
||||||
|
data, err := request.MarshalVT()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
dataSize := uint64(len(data))
|
||||||
|
|
||||||
|
var dataPtr uint64
|
||||||
|
// If the input data is not empty, we must allocate the in-Wasm memory to store it, and pass to the plugin.
|
||||||
|
if dataSize != 0 {
|
||||||
|
results, err := p.malloc.Call(ctx, dataSize)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
dataPtr = results[0]
|
||||||
|
// This pointer is managed by the Wasm module, which is unaware of external usage.
|
||||||
|
// So, we have to free it when finished
|
||||||
|
defer p.free.Call(ctx, dataPtr)
|
||||||
|
|
||||||
|
// The pointer is a linear memory offset, which is where we write the name.
|
||||||
|
if !p.module.Memory().Write(uint32(dataPtr), data) {
|
||||||
|
return nil, fmt.Errorf("Memory.Write(%d, %d) out of range of memory size %d", dataPtr, dataSize, p.module.Memory().Size())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ptrSize, err := p.synchronize.Call(ctx, dataPtr, dataSize)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resPtr := uint32(ptrSize[0] >> 32)
|
||||||
|
resSize := uint32(ptrSize[0])
|
||||||
|
var isErrResponse bool
|
||||||
|
if (resSize & (1 << 31)) > 0 {
|
||||||
|
isErrResponse = true
|
||||||
|
resSize &^= (1 << 31)
|
||||||
|
}
|
||||||
|
|
||||||
|
// We don't need the memory after deserialization: make sure it is freed.
|
||||||
|
if resPtr != 0 {
|
||||||
|
defer p.free.Call(ctx, uint64(resPtr))
|
||||||
|
}
|
||||||
|
|
||||||
|
// The pointer is a linear memory offset, which is where we write the name.
|
||||||
|
bytes, ok := p.module.Memory().Read(resPtr, resSize)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("Memory.Read(%d, %d) out of range of memory size %d",
|
||||||
|
resPtr, resSize, p.module.Memory().Size())
|
||||||
|
}
|
||||||
|
|
||||||
|
if isErrResponse {
|
||||||
|
return nil, errors.New(string(bytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
response := new(SynchronizeResponse)
|
||||||
|
if err = response.UnmarshalVT(bytes); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return response, nil
|
||||||
|
}
|
||||||
|
func (p *pluginPlugin) Shutdown(ctx context.Context, request *Empty) (*Empty, error) {
|
||||||
|
data, err := request.MarshalVT()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
dataSize := uint64(len(data))
|
||||||
|
|
||||||
|
var dataPtr uint64
|
||||||
|
// If the input data is not empty, we must allocate the in-Wasm memory to store it, and pass to the plugin.
|
||||||
|
if dataSize != 0 {
|
||||||
|
results, err := p.malloc.Call(ctx, dataSize)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
dataPtr = results[0]
|
||||||
|
// This pointer is managed by the Wasm module, which is unaware of external usage.
|
||||||
|
// So, we have to free it when finished
|
||||||
|
defer p.free.Call(ctx, dataPtr)
|
||||||
|
|
||||||
|
// The pointer is a linear memory offset, which is where we write the name.
|
||||||
|
if !p.module.Memory().Write(uint32(dataPtr), data) {
|
||||||
|
return nil, fmt.Errorf("Memory.Write(%d, %d) out of range of memory size %d", dataPtr, dataSize, p.module.Memory().Size())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ptrSize, err := p.shutdown.Call(ctx, dataPtr, dataSize)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resPtr := uint32(ptrSize[0] >> 32)
|
||||||
|
resSize := uint32(ptrSize[0])
|
||||||
|
var isErrResponse bool
|
||||||
|
if (resSize & (1 << 31)) > 0 {
|
||||||
|
isErrResponse = true
|
||||||
|
resSize &^= (1 << 31)
|
||||||
|
}
|
||||||
|
|
||||||
|
// We don't need the memory after deserialization: make sure it is freed.
|
||||||
|
if resPtr != 0 {
|
||||||
|
defer p.free.Call(ctx, uint64(resPtr))
|
||||||
|
}
|
||||||
|
|
||||||
|
// The pointer is a linear memory offset, which is where we write the name.
|
||||||
|
bytes, ok := p.module.Memory().Read(resPtr, resSize)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("Memory.Read(%d, %d) out of range of memory size %d",
|
||||||
|
resPtr, resSize, p.module.Memory().Size())
|
||||||
|
}
|
||||||
|
|
||||||
|
if isErrResponse {
|
||||||
|
return nil, errors.New(string(bytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
response := new(Empty)
|
||||||
|
if err = response.UnmarshalVT(bytes); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return response, nil
|
||||||
|
}
|
||||||
|
func (p *pluginPlugin) CreateContainer(ctx context.Context, request *CreateContainerRequest) (*CreateContainerResponse, error) {
|
||||||
|
data, err := request.MarshalVT()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
dataSize := uint64(len(data))
|
||||||
|
|
||||||
|
var dataPtr uint64
|
||||||
|
// If the input data is not empty, we must allocate the in-Wasm memory to store it, and pass to the plugin.
|
||||||
|
if dataSize != 0 {
|
||||||
|
results, err := p.malloc.Call(ctx, dataSize)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
dataPtr = results[0]
|
||||||
|
// This pointer is managed by the Wasm module, which is unaware of external usage.
|
||||||
|
// So, we have to free it when finished
|
||||||
|
defer p.free.Call(ctx, dataPtr)
|
||||||
|
|
||||||
|
// The pointer is a linear memory offset, which is where we write the name.
|
||||||
|
if !p.module.Memory().Write(uint32(dataPtr), data) {
|
||||||
|
return nil, fmt.Errorf("Memory.Write(%d, %d) out of range of memory size %d", dataPtr, dataSize, p.module.Memory().Size())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ptrSize, err := p.createcontainer.Call(ctx, dataPtr, dataSize)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resPtr := uint32(ptrSize[0] >> 32)
|
||||||
|
resSize := uint32(ptrSize[0])
|
||||||
|
var isErrResponse bool
|
||||||
|
if (resSize & (1 << 31)) > 0 {
|
||||||
|
isErrResponse = true
|
||||||
|
resSize &^= (1 << 31)
|
||||||
|
}
|
||||||
|
|
||||||
|
// We don't need the memory after deserialization: make sure it is freed.
|
||||||
|
if resPtr != 0 {
|
||||||
|
defer p.free.Call(ctx, uint64(resPtr))
|
||||||
|
}
|
||||||
|
|
||||||
|
// The pointer is a linear memory offset, which is where we write the name.
|
||||||
|
bytes, ok := p.module.Memory().Read(resPtr, resSize)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("Memory.Read(%d, %d) out of range of memory size %d",
|
||||||
|
resPtr, resSize, p.module.Memory().Size())
|
||||||
|
}
|
||||||
|
|
||||||
|
if isErrResponse {
|
||||||
|
return nil, errors.New(string(bytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
response := new(CreateContainerResponse)
|
||||||
|
if err = response.UnmarshalVT(bytes); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return response, nil
|
||||||
|
}
|
||||||
|
func (p *pluginPlugin) UpdateContainer(ctx context.Context, request *UpdateContainerRequest) (*UpdateContainerResponse, error) {
|
||||||
|
data, err := request.MarshalVT()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
dataSize := uint64(len(data))
|
||||||
|
|
||||||
|
var dataPtr uint64
|
||||||
|
// If the input data is not empty, we must allocate the in-Wasm memory to store it, and pass to the plugin.
|
||||||
|
if dataSize != 0 {
|
||||||
|
results, err := p.malloc.Call(ctx, dataSize)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
dataPtr = results[0]
|
||||||
|
// This pointer is managed by the Wasm module, which is unaware of external usage.
|
||||||
|
// So, we have to free it when finished
|
||||||
|
defer p.free.Call(ctx, dataPtr)
|
||||||
|
|
||||||
|
// The pointer is a linear memory offset, which is where we write the name.
|
||||||
|
if !p.module.Memory().Write(uint32(dataPtr), data) {
|
||||||
|
return nil, fmt.Errorf("Memory.Write(%d, %d) out of range of memory size %d", dataPtr, dataSize, p.module.Memory().Size())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ptrSize, err := p.updatecontainer.Call(ctx, dataPtr, dataSize)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resPtr := uint32(ptrSize[0] >> 32)
|
||||||
|
resSize := uint32(ptrSize[0])
|
||||||
|
var isErrResponse bool
|
||||||
|
if (resSize & (1 << 31)) > 0 {
|
||||||
|
isErrResponse = true
|
||||||
|
resSize &^= (1 << 31)
|
||||||
|
}
|
||||||
|
|
||||||
|
// We don't need the memory after deserialization: make sure it is freed.
|
||||||
|
if resPtr != 0 {
|
||||||
|
defer p.free.Call(ctx, uint64(resPtr))
|
||||||
|
}
|
||||||
|
|
||||||
|
// The pointer is a linear memory offset, which is where we write the name.
|
||||||
|
bytes, ok := p.module.Memory().Read(resPtr, resSize)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("Memory.Read(%d, %d) out of range of memory size %d",
|
||||||
|
resPtr, resSize, p.module.Memory().Size())
|
||||||
|
}
|
||||||
|
|
||||||
|
if isErrResponse {
|
||||||
|
return nil, errors.New(string(bytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
response := new(UpdateContainerResponse)
|
||||||
|
if err = response.UnmarshalVT(bytes); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return response, nil
|
||||||
|
}
|
||||||
|
func (p *pluginPlugin) StopContainer(ctx context.Context, request *StopContainerRequest) (*StopContainerResponse, error) {
|
||||||
|
data, err := request.MarshalVT()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
dataSize := uint64(len(data))
|
||||||
|
|
||||||
|
var dataPtr uint64
|
||||||
|
// If the input data is not empty, we must allocate the in-Wasm memory to store it, and pass to the plugin.
|
||||||
|
if dataSize != 0 {
|
||||||
|
results, err := p.malloc.Call(ctx, dataSize)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
dataPtr = results[0]
|
||||||
|
// This pointer is managed by the Wasm module, which is unaware of external usage.
|
||||||
|
// So, we have to free it when finished
|
||||||
|
defer p.free.Call(ctx, dataPtr)
|
||||||
|
|
||||||
|
// The pointer is a linear memory offset, which is where we write the name.
|
||||||
|
if !p.module.Memory().Write(uint32(dataPtr), data) {
|
||||||
|
return nil, fmt.Errorf("Memory.Write(%d, %d) out of range of memory size %d", dataPtr, dataSize, p.module.Memory().Size())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ptrSize, err := p.stopcontainer.Call(ctx, dataPtr, dataSize)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resPtr := uint32(ptrSize[0] >> 32)
|
||||||
|
resSize := uint32(ptrSize[0])
|
||||||
|
var isErrResponse bool
|
||||||
|
if (resSize & (1 << 31)) > 0 {
|
||||||
|
isErrResponse = true
|
||||||
|
resSize &^= (1 << 31)
|
||||||
|
}
|
||||||
|
|
||||||
|
// We don't need the memory after deserialization: make sure it is freed.
|
||||||
|
if resPtr != 0 {
|
||||||
|
defer p.free.Call(ctx, uint64(resPtr))
|
||||||
|
}
|
||||||
|
|
||||||
|
// The pointer is a linear memory offset, which is where we write the name.
|
||||||
|
bytes, ok := p.module.Memory().Read(resPtr, resSize)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("Memory.Read(%d, %d) out of range of memory size %d",
|
||||||
|
resPtr, resSize, p.module.Memory().Size())
|
||||||
|
}
|
||||||
|
|
||||||
|
if isErrResponse {
|
||||||
|
return nil, errors.New(string(bytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
response := new(StopContainerResponse)
|
||||||
|
if err = response.UnmarshalVT(bytes); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return response, nil
|
||||||
|
}
|
||||||
|
func (p *pluginPlugin) UpdatePodSandbox(ctx context.Context, request *UpdatePodSandboxRequest) (*UpdatePodSandboxResponse, error) {
|
||||||
|
data, err := request.MarshalVT()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
dataSize := uint64(len(data))
|
||||||
|
|
||||||
|
var dataPtr uint64
|
||||||
|
// If the input data is not empty, we must allocate the in-Wasm memory to store it, and pass to the plugin.
|
||||||
|
if dataSize != 0 {
|
||||||
|
results, err := p.malloc.Call(ctx, dataSize)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
dataPtr = results[0]
|
||||||
|
// This pointer is managed by the Wasm module, which is unaware of external usage.
|
||||||
|
// So, we have to free it when finished
|
||||||
|
defer p.free.Call(ctx, dataPtr)
|
||||||
|
|
||||||
|
// The pointer is a linear memory offset, which is where we write the name.
|
||||||
|
if !p.module.Memory().Write(uint32(dataPtr), data) {
|
||||||
|
return nil, fmt.Errorf("Memory.Write(%d, %d) out of range of memory size %d", dataPtr, dataSize, p.module.Memory().Size())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ptrSize, err := p.updatepodsandbox.Call(ctx, dataPtr, dataSize)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resPtr := uint32(ptrSize[0] >> 32)
|
||||||
|
resSize := uint32(ptrSize[0])
|
||||||
|
var isErrResponse bool
|
||||||
|
if (resSize & (1 << 31)) > 0 {
|
||||||
|
isErrResponse = true
|
||||||
|
resSize &^= (1 << 31)
|
||||||
|
}
|
||||||
|
|
||||||
|
// We don't need the memory after deserialization: make sure it is freed.
|
||||||
|
if resPtr != 0 {
|
||||||
|
defer p.free.Call(ctx, uint64(resPtr))
|
||||||
|
}
|
||||||
|
|
||||||
|
// The pointer is a linear memory offset, which is where we write the name.
|
||||||
|
bytes, ok := p.module.Memory().Read(resPtr, resSize)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("Memory.Read(%d, %d) out of range of memory size %d",
|
||||||
|
resPtr, resSize, p.module.Memory().Size())
|
||||||
|
}
|
||||||
|
|
||||||
|
if isErrResponse {
|
||||||
|
return nil, errors.New(string(bytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
response := new(UpdatePodSandboxResponse)
|
||||||
|
if err = response.UnmarshalVT(bytes); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return response, nil
|
||||||
|
}
|
||||||
|
func (p *pluginPlugin) StateChange(ctx context.Context, request *StateChangeEvent) (*Empty, error) {
|
||||||
|
data, err := request.MarshalVT()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
dataSize := uint64(len(data))
|
||||||
|
|
||||||
|
var dataPtr uint64
|
||||||
|
// If the input data is not empty, we must allocate the in-Wasm memory to store it, and pass to the plugin.
|
||||||
|
if dataSize != 0 {
|
||||||
|
results, err := p.malloc.Call(ctx, dataSize)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
dataPtr = results[0]
|
||||||
|
// This pointer is managed by the Wasm module, which is unaware of external usage.
|
||||||
|
// So, we have to free it when finished
|
||||||
|
defer p.free.Call(ctx, dataPtr)
|
||||||
|
|
||||||
|
// The pointer is a linear memory offset, which is where we write the name.
|
||||||
|
if !p.module.Memory().Write(uint32(dataPtr), data) {
|
||||||
|
return nil, fmt.Errorf("Memory.Write(%d, %d) out of range of memory size %d", dataPtr, dataSize, p.module.Memory().Size())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ptrSize, err := p.statechange.Call(ctx, dataPtr, dataSize)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resPtr := uint32(ptrSize[0] >> 32)
|
||||||
|
resSize := uint32(ptrSize[0])
|
||||||
|
var isErrResponse bool
|
||||||
|
if (resSize & (1 << 31)) > 0 {
|
||||||
|
isErrResponse = true
|
||||||
|
resSize &^= (1 << 31)
|
||||||
|
}
|
||||||
|
|
||||||
|
// We don't need the memory after deserialization: make sure it is freed.
|
||||||
|
if resPtr != 0 {
|
||||||
|
defer p.free.Call(ctx, uint64(resPtr))
|
||||||
|
}
|
||||||
|
|
||||||
|
// The pointer is a linear memory offset, which is where we write the name.
|
||||||
|
bytes, ok := p.module.Memory().Read(resPtr, resSize)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("Memory.Read(%d, %d) out of range of memory size %d",
|
||||||
|
resPtr, resSize, p.module.Memory().Size())
|
||||||
|
}
|
||||||
|
|
||||||
|
if isErrResponse {
|
||||||
|
return nil, errors.New(string(bytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
response := new(Empty)
|
||||||
|
if err = response.UnmarshalVT(bytes); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return response, nil
|
||||||
|
}
|
||||||
|
func (p *pluginPlugin) ValidateContainerAdjustment(ctx context.Context, request *ValidateContainerAdjustmentRequest) (*ValidateContainerAdjustmentResponse, error) {
|
||||||
|
data, err := request.MarshalVT()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
dataSize := uint64(len(data))
|
||||||
|
|
||||||
|
var dataPtr uint64
|
||||||
|
// If the input data is not empty, we must allocate the in-Wasm memory to store it, and pass to the plugin.
|
||||||
|
if dataSize != 0 {
|
||||||
|
results, err := p.malloc.Call(ctx, dataSize)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
dataPtr = results[0]
|
||||||
|
// This pointer is managed by the Wasm module, which is unaware of external usage.
|
||||||
|
// So, we have to free it when finished
|
||||||
|
defer p.free.Call(ctx, dataPtr)
|
||||||
|
|
||||||
|
// The pointer is a linear memory offset, which is where we write the name.
|
||||||
|
if !p.module.Memory().Write(uint32(dataPtr), data) {
|
||||||
|
return nil, fmt.Errorf("Memory.Write(%d, %d) out of range of memory size %d", dataPtr, dataSize, p.module.Memory().Size())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ptrSize, err := p.validatecontaineradjustment.Call(ctx, dataPtr, dataSize)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resPtr := uint32(ptrSize[0] >> 32)
|
||||||
|
resSize := uint32(ptrSize[0])
|
||||||
|
var isErrResponse bool
|
||||||
|
if (resSize & (1 << 31)) > 0 {
|
||||||
|
isErrResponse = true
|
||||||
|
resSize &^= (1 << 31)
|
||||||
|
}
|
||||||
|
|
||||||
|
// We don't need the memory after deserialization: make sure it is freed.
|
||||||
|
if resPtr != 0 {
|
||||||
|
defer p.free.Call(ctx, uint64(resPtr))
|
||||||
|
}
|
||||||
|
|
||||||
|
// The pointer is a linear memory offset, which is where we write the name.
|
||||||
|
bytes, ok := p.module.Memory().Read(resPtr, resSize)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("Memory.Read(%d, %d) out of range of memory size %d",
|
||||||
|
resPtr, resSize, p.module.Memory().Size())
|
||||||
|
}
|
||||||
|
|
||||||
|
if isErrResponse {
|
||||||
|
return nil, errors.New(string(bytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
response := new(ValidateContainerAdjustmentResponse)
|
||||||
|
if err = response.UnmarshalVT(bytes); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return response, nil
|
||||||
|
}
|
||||||
62
vendor/github.com/containerd/nri/pkg/api/api_options.pb.go
generated
vendored
Normal file
62
vendor/github.com/containerd/nri/pkg/api/api_options.pb.go
generated
vendored
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
//go:build !wasip1
|
||||||
|
|
||||||
|
//
|
||||||
|
//Copyright The containerd Authors.
|
||||||
|
//
|
||||||
|
//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.
|
||||||
|
|
||||||
|
// Code generated by protoc-gen-go-plugin. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// protoc-gen-go-plugin v0.1.0
|
||||||
|
// protoc v3.20.1
|
||||||
|
// source: pkg/api/api.proto
|
||||||
|
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
context "context"
|
||||||
|
wazero "github.com/tetratelabs/wazero"
|
||||||
|
wasi_snapshot_preview1 "github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1"
|
||||||
|
)
|
||||||
|
|
||||||
|
type wazeroConfigOption func(plugin *WazeroConfig)
|
||||||
|
|
||||||
|
type WazeroNewRuntime func(context.Context) (wazero.Runtime, error)
|
||||||
|
|
||||||
|
type WazeroConfig struct {
|
||||||
|
newRuntime func(context.Context) (wazero.Runtime, error)
|
||||||
|
moduleConfig wazero.ModuleConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
func WazeroRuntime(newRuntime WazeroNewRuntime) wazeroConfigOption {
|
||||||
|
return func(h *WazeroConfig) {
|
||||||
|
h.newRuntime = newRuntime
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func DefaultWazeroRuntime() WazeroNewRuntime {
|
||||||
|
return func(ctx context.Context) (wazero.Runtime, error) {
|
||||||
|
r := wazero.NewRuntime(ctx)
|
||||||
|
if _, err := wasi_snapshot_preview1.Instantiate(ctx, r); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return r, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func WazeroModuleConfig(moduleConfig wazero.ModuleConfig) wazeroConfigOption {
|
||||||
|
return func(h *WazeroConfig) {
|
||||||
|
h.moduleConfig = moduleConfig
|
||||||
|
}
|
||||||
|
}
|
||||||
288
vendor/github.com/containerd/nri/pkg/api/api_plugin.pb.go
generated
vendored
Normal file
288
vendor/github.com/containerd/nri/pkg/api/api_plugin.pb.go
generated
vendored
Normal file
@@ -0,0 +1,288 @@
|
|||||||
|
//go:build wasip1
|
||||||
|
|
||||||
|
//
|
||||||
|
//Copyright The containerd Authors.
|
||||||
|
//
|
||||||
|
//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.
|
||||||
|
|
||||||
|
// Code generated by protoc-gen-go-plugin. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// protoc-gen-go-plugin v0.1.0
|
||||||
|
// protoc v3.20.1
|
||||||
|
// source: pkg/api/api.proto
|
||||||
|
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
context "context"
|
||||||
|
wasm "github.com/knqyf263/go-plugin/wasm"
|
||||||
|
_ "unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
const PluginPluginAPIVersion = 1
|
||||||
|
|
||||||
|
//go:wasmexport plugin_api_version
|
||||||
|
func _plugin_api_version() uint64 {
|
||||||
|
return PluginPluginAPIVersion
|
||||||
|
}
|
||||||
|
|
||||||
|
var plugin Plugin
|
||||||
|
|
||||||
|
func RegisterPlugin(p Plugin) {
|
||||||
|
plugin = p
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:wasmexport plugin_configure
|
||||||
|
func _plugin_configure(ptr, size uint32) uint64 {
|
||||||
|
b := wasm.PtrToByte(ptr, size)
|
||||||
|
req := new(ConfigureRequest)
|
||||||
|
if err := req.UnmarshalVT(b); err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
response, err := plugin.Configure(context.Background(), req)
|
||||||
|
if err != nil {
|
||||||
|
ptr, size = wasm.ByteToPtr([]byte(err.Error()))
|
||||||
|
return (uint64(ptr) << uint64(32)) | uint64(size) |
|
||||||
|
// Indicate that this is the error string by setting the 32-th bit, assuming that
|
||||||
|
// no data exceeds 31-bit size (2 GiB).
|
||||||
|
(1 << 31)
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err = response.MarshalVT()
|
||||||
|
if err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
ptr, size = wasm.ByteToPtr(b)
|
||||||
|
return (uint64(ptr) << uint64(32)) | uint64(size)
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:wasmexport plugin_synchronize
|
||||||
|
func _plugin_synchronize(ptr, size uint32) uint64 {
|
||||||
|
b := wasm.PtrToByte(ptr, size)
|
||||||
|
req := new(SynchronizeRequest)
|
||||||
|
if err := req.UnmarshalVT(b); err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
response, err := plugin.Synchronize(context.Background(), req)
|
||||||
|
if err != nil {
|
||||||
|
ptr, size = wasm.ByteToPtr([]byte(err.Error()))
|
||||||
|
return (uint64(ptr) << uint64(32)) | uint64(size) |
|
||||||
|
// Indicate that this is the error string by setting the 32-th bit, assuming that
|
||||||
|
// no data exceeds 31-bit size (2 GiB).
|
||||||
|
(1 << 31)
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err = response.MarshalVT()
|
||||||
|
if err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
ptr, size = wasm.ByteToPtr(b)
|
||||||
|
return (uint64(ptr) << uint64(32)) | uint64(size)
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:wasmexport plugin_shutdown
|
||||||
|
func _plugin_shutdown(ptr, size uint32) uint64 {
|
||||||
|
b := wasm.PtrToByte(ptr, size)
|
||||||
|
req := new(Empty)
|
||||||
|
if err := req.UnmarshalVT(b); err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
response, err := plugin.Shutdown(context.Background(), req)
|
||||||
|
if err != nil {
|
||||||
|
ptr, size = wasm.ByteToPtr([]byte(err.Error()))
|
||||||
|
return (uint64(ptr) << uint64(32)) | uint64(size) |
|
||||||
|
// Indicate that this is the error string by setting the 32-th bit, assuming that
|
||||||
|
// no data exceeds 31-bit size (2 GiB).
|
||||||
|
(1 << 31)
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err = response.MarshalVT()
|
||||||
|
if err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
ptr, size = wasm.ByteToPtr(b)
|
||||||
|
return (uint64(ptr) << uint64(32)) | uint64(size)
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:wasmexport plugin_create_container
|
||||||
|
func _plugin_create_container(ptr, size uint32) uint64 {
|
||||||
|
b := wasm.PtrToByte(ptr, size)
|
||||||
|
req := new(CreateContainerRequest)
|
||||||
|
if err := req.UnmarshalVT(b); err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
response, err := plugin.CreateContainer(context.Background(), req)
|
||||||
|
if err != nil {
|
||||||
|
ptr, size = wasm.ByteToPtr([]byte(err.Error()))
|
||||||
|
return (uint64(ptr) << uint64(32)) | uint64(size) |
|
||||||
|
// Indicate that this is the error string by setting the 32-th bit, assuming that
|
||||||
|
// no data exceeds 31-bit size (2 GiB).
|
||||||
|
(1 << 31)
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err = response.MarshalVT()
|
||||||
|
if err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
ptr, size = wasm.ByteToPtr(b)
|
||||||
|
return (uint64(ptr) << uint64(32)) | uint64(size)
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:wasmexport plugin_update_container
|
||||||
|
func _plugin_update_container(ptr, size uint32) uint64 {
|
||||||
|
b := wasm.PtrToByte(ptr, size)
|
||||||
|
req := new(UpdateContainerRequest)
|
||||||
|
if err := req.UnmarshalVT(b); err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
response, err := plugin.UpdateContainer(context.Background(), req)
|
||||||
|
if err != nil {
|
||||||
|
ptr, size = wasm.ByteToPtr([]byte(err.Error()))
|
||||||
|
return (uint64(ptr) << uint64(32)) | uint64(size) |
|
||||||
|
// Indicate that this is the error string by setting the 32-th bit, assuming that
|
||||||
|
// no data exceeds 31-bit size (2 GiB).
|
||||||
|
(1 << 31)
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err = response.MarshalVT()
|
||||||
|
if err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
ptr, size = wasm.ByteToPtr(b)
|
||||||
|
return (uint64(ptr) << uint64(32)) | uint64(size)
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:wasmexport plugin_stop_container
|
||||||
|
func _plugin_stop_container(ptr, size uint32) uint64 {
|
||||||
|
b := wasm.PtrToByte(ptr, size)
|
||||||
|
req := new(StopContainerRequest)
|
||||||
|
if err := req.UnmarshalVT(b); err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
response, err := plugin.StopContainer(context.Background(), req)
|
||||||
|
if err != nil {
|
||||||
|
ptr, size = wasm.ByteToPtr([]byte(err.Error()))
|
||||||
|
return (uint64(ptr) << uint64(32)) | uint64(size) |
|
||||||
|
// Indicate that this is the error string by setting the 32-th bit, assuming that
|
||||||
|
// no data exceeds 31-bit size (2 GiB).
|
||||||
|
(1 << 31)
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err = response.MarshalVT()
|
||||||
|
if err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
ptr, size = wasm.ByteToPtr(b)
|
||||||
|
return (uint64(ptr) << uint64(32)) | uint64(size)
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:wasmexport plugin_update_pod_sandbox
|
||||||
|
func _plugin_update_pod_sandbox(ptr, size uint32) uint64 {
|
||||||
|
b := wasm.PtrToByte(ptr, size)
|
||||||
|
req := new(UpdatePodSandboxRequest)
|
||||||
|
if err := req.UnmarshalVT(b); err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
response, err := plugin.UpdatePodSandbox(context.Background(), req)
|
||||||
|
if err != nil {
|
||||||
|
ptr, size = wasm.ByteToPtr([]byte(err.Error()))
|
||||||
|
return (uint64(ptr) << uint64(32)) | uint64(size) |
|
||||||
|
// Indicate that this is the error string by setting the 32-th bit, assuming that
|
||||||
|
// no data exceeds 31-bit size (2 GiB).
|
||||||
|
(1 << 31)
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err = response.MarshalVT()
|
||||||
|
if err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
ptr, size = wasm.ByteToPtr(b)
|
||||||
|
return (uint64(ptr) << uint64(32)) | uint64(size)
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:wasmexport plugin_state_change
|
||||||
|
func _plugin_state_change(ptr, size uint32) uint64 {
|
||||||
|
b := wasm.PtrToByte(ptr, size)
|
||||||
|
req := new(StateChangeEvent)
|
||||||
|
if err := req.UnmarshalVT(b); err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
response, err := plugin.StateChange(context.Background(), req)
|
||||||
|
if err != nil {
|
||||||
|
ptr, size = wasm.ByteToPtr([]byte(err.Error()))
|
||||||
|
return (uint64(ptr) << uint64(32)) | uint64(size) |
|
||||||
|
// Indicate that this is the error string by setting the 32-th bit, assuming that
|
||||||
|
// no data exceeds 31-bit size (2 GiB).
|
||||||
|
(1 << 31)
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err = response.MarshalVT()
|
||||||
|
if err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
ptr, size = wasm.ByteToPtr(b)
|
||||||
|
return (uint64(ptr) << uint64(32)) | uint64(size)
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:wasmexport plugin_validate_container_adjustment
|
||||||
|
func _plugin_validate_container_adjustment(ptr, size uint32) uint64 {
|
||||||
|
b := wasm.PtrToByte(ptr, size)
|
||||||
|
req := new(ValidateContainerAdjustmentRequest)
|
||||||
|
if err := req.UnmarshalVT(b); err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
response, err := plugin.ValidateContainerAdjustment(context.Background(), req)
|
||||||
|
if err != nil {
|
||||||
|
ptr, size = wasm.ByteToPtr([]byte(err.Error()))
|
||||||
|
return (uint64(ptr) << uint64(32)) | uint64(size) |
|
||||||
|
// Indicate that this is the error string by setting the 32-th bit, assuming that
|
||||||
|
// no data exceeds 31-bit size (2 GiB).
|
||||||
|
(1 << 31)
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err = response.MarshalVT()
|
||||||
|
if err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
ptr, size = wasm.ByteToPtr(b)
|
||||||
|
return (uint64(ptr) << uint64(32)) | uint64(size)
|
||||||
|
}
|
||||||
|
|
||||||
|
type hostFunctions struct{}
|
||||||
|
|
||||||
|
func NewHostFunctions() HostFunctions {
|
||||||
|
return hostFunctions{}
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:wasmimport env log
|
||||||
|
func _log(ptr uint32, size uint32) uint64
|
||||||
|
|
||||||
|
func (h hostFunctions) Log(ctx context.Context, request *LogRequest) (*Empty, error) {
|
||||||
|
buf, err := request.MarshalVT()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ptr, size := wasm.ByteToPtr(buf)
|
||||||
|
ptrSize := _log(ptr, size)
|
||||||
|
wasm.Free(ptr)
|
||||||
|
|
||||||
|
ptr = uint32(ptrSize >> 32)
|
||||||
|
size = uint32(ptrSize)
|
||||||
|
buf = wasm.PtrToByte(ptr, size)
|
||||||
|
|
||||||
|
response := new(Empty)
|
||||||
|
if err = response.UnmarshalVT(buf); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return response, nil
|
||||||
|
}
|
||||||
95
vendor/github.com/containerd/nri/pkg/api/api_service.pb.go
generated
vendored
Normal file
95
vendor/github.com/containerd/nri/pkg/api/api_service.pb.go
generated
vendored
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
//
|
||||||
|
//Copyright The containerd Authors.
|
||||||
|
//
|
||||||
|
//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.
|
||||||
|
|
||||||
|
// Code generated by protoc-gen-go-plugin. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// protoc-gen-go-plugin v0.1.0
|
||||||
|
// protoc v3.20.1
|
||||||
|
// source: pkg/api/api.proto
|
||||||
|
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
context "context"
|
||||||
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Verify that this generated code is sufficiently up-to-date.
|
||||||
|
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||||
|
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||||
|
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Plugin is the API NRI uses to interact with plugins. It is used to
|
||||||
|
// - configure a plugin and subscribe it for lifecycle events
|
||||||
|
// - synchronize the state of a plugin with that of the runtime
|
||||||
|
// - hook a plugin into the lifecycle events of its interest
|
||||||
|
//
|
||||||
|
// During configuration the plugin tells the runtime which lifecycle events
|
||||||
|
// it wishes to get hooked into. Once configured, the plugin is synchronized
|
||||||
|
// with the runtime by receiving the list of pods and containers known to
|
||||||
|
// the runtime. The plugin can request changes to any of the containers in
|
||||||
|
// response. After initial synchronization the plugin starts receiving the
|
||||||
|
// events it subscribed for as they occur in the runtime. For container
|
||||||
|
// creation, update, and stop events, the plugin can request changes, both
|
||||||
|
// to the container that triggered the event or any other existing container
|
||||||
|
// in the runtime.
|
||||||
|
//
|
||||||
|
// For a subset of the container lifecycle events, NRI defines an additional
|
||||||
|
// Post-variant of the event. These variants are defined for CreateContainer,
|
||||||
|
// StartContainer, and UpdateContainer. For creation and update, these events
|
||||||
|
// can be used by plugins to discover the full extent of changes applied to
|
||||||
|
// the container, including any changes made by other active plugins.
|
||||||
|
//
|
||||||
|
// go:plugin type=plugin version=1
|
||||||
|
type Plugin interface {
|
||||||
|
// Configure the plugin and get its event subscription.
|
||||||
|
Configure(context.Context, *ConfigureRequest) (*ConfigureResponse, error)
|
||||||
|
// Synchronize the plugin with the state of the runtime.
|
||||||
|
Synchronize(context.Context, *SynchronizeRequest) (*SynchronizeResponse, error)
|
||||||
|
// Shutdown a plugin (let it know the runtime is going down).
|
||||||
|
Shutdown(context.Context, *Empty) (*Empty, error)
|
||||||
|
// CreateContainer relays the corresponding request to the plugin. In
|
||||||
|
// response, the plugin can adjust the container being created, and
|
||||||
|
// update other containers in the runtime. Container adjustment can
|
||||||
|
// alter labels, annotations, mounts, devices, environment variables,
|
||||||
|
// OCI hooks, and assigned container resources. Updates can alter
|
||||||
|
// assigned container resources.
|
||||||
|
CreateContainer(context.Context, *CreateContainerRequest) (*CreateContainerResponse, error)
|
||||||
|
// UpdateContainer relays the corresponding request to the plugin.
|
||||||
|
// The plugin can alter how the container is updated and request updates
|
||||||
|
// to additional containers in the runtime.
|
||||||
|
UpdateContainer(context.Context, *UpdateContainerRequest) (*UpdateContainerResponse, error)
|
||||||
|
// StopContainer relays the corresponding request to the plugin. The plugin
|
||||||
|
// can update any of the remaining containers in the runtime in response.
|
||||||
|
StopContainer(context.Context, *StopContainerRequest) (*StopContainerResponse, error)
|
||||||
|
// UpdatePodSandbox relays the corresponding request to the plugin.
|
||||||
|
UpdatePodSandbox(context.Context, *UpdatePodSandboxRequest) (*UpdatePodSandboxResponse, error)
|
||||||
|
// StateChange relays any remaining pod or container lifecycle/state change
|
||||||
|
// events the plugin has subscribed for. These can be used to trigger any
|
||||||
|
// plugin-specific processing which needs to occur in connection with any of
|
||||||
|
// these events.
|
||||||
|
StateChange(context.Context, *StateChangeEvent) (*Empty, error)
|
||||||
|
// ValidateContainerAdjustment relays a container adjustment validation request
|
||||||
|
// to the plugin. Container creation will fail the plugin rejects the adjustments.
|
||||||
|
ValidateContainerAdjustment(context.Context, *ValidateContainerAdjustmentRequest) (*ValidateContainerAdjustmentResponse, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// go:plugin type=host
|
||||||
|
type HostFunctions interface {
|
||||||
|
// Log displays a log message
|
||||||
|
Log(context.Context, *LogRequest) (*Empty, error)
|
||||||
|
}
|
||||||
262
vendor/github.com/containerd/nri/pkg/api/api_ttrpc.pb.go
generated
vendored
Normal file
262
vendor/github.com/containerd/nri/pkg/api/api_ttrpc.pb.go
generated
vendored
Normal file
@@ -0,0 +1,262 @@
|
|||||||
|
//go:build !wasip1
|
||||||
|
|
||||||
|
// Code generated by protoc-gen-go-ttrpc. DO NOT EDIT.
|
||||||
|
// source: pkg/api/api.proto
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
context "context"
|
||||||
|
ttrpc "github.com/containerd/ttrpc"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RuntimeService interface {
|
||||||
|
RegisterPlugin(context.Context, *RegisterPluginRequest) (*Empty, error)
|
||||||
|
UpdateContainers(context.Context, *UpdateContainersRequest) (*UpdateContainersResponse, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func RegisterRuntimeService(srv *ttrpc.Server, svc RuntimeService) {
|
||||||
|
srv.RegisterService("nri.pkg.api.v1alpha1.Runtime", &ttrpc.ServiceDesc{
|
||||||
|
Methods: map[string]ttrpc.Method{
|
||||||
|
"RegisterPlugin": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) {
|
||||||
|
var req RegisterPluginRequest
|
||||||
|
if err := unmarshal(&req); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return svc.RegisterPlugin(ctx, &req)
|
||||||
|
},
|
||||||
|
"UpdateContainers": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) {
|
||||||
|
var req UpdateContainersRequest
|
||||||
|
if err := unmarshal(&req); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return svc.UpdateContainers(ctx, &req)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type runtimeClient struct {
|
||||||
|
client *ttrpc.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRuntimeClient(client *ttrpc.Client) RuntimeService {
|
||||||
|
return &runtimeClient{
|
||||||
|
client: client,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *runtimeClient) RegisterPlugin(ctx context.Context, req *RegisterPluginRequest) (*Empty, error) {
|
||||||
|
var resp Empty
|
||||||
|
if err := c.client.Call(ctx, "nri.pkg.api.v1alpha1.Runtime", "RegisterPlugin", req, &resp); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *runtimeClient) UpdateContainers(ctx context.Context, req *UpdateContainersRequest) (*UpdateContainersResponse, error) {
|
||||||
|
var resp UpdateContainersResponse
|
||||||
|
if err := c.client.Call(ctx, "nri.pkg.api.v1alpha1.Runtime", "UpdateContainers", req, &resp); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type PluginService interface {
|
||||||
|
Configure(context.Context, *ConfigureRequest) (*ConfigureResponse, error)
|
||||||
|
Synchronize(context.Context, *SynchronizeRequest) (*SynchronizeResponse, error)
|
||||||
|
Shutdown(context.Context, *Empty) (*Empty, error)
|
||||||
|
CreateContainer(context.Context, *CreateContainerRequest) (*CreateContainerResponse, error)
|
||||||
|
UpdateContainer(context.Context, *UpdateContainerRequest) (*UpdateContainerResponse, error)
|
||||||
|
StopContainer(context.Context, *StopContainerRequest) (*StopContainerResponse, error)
|
||||||
|
UpdatePodSandbox(context.Context, *UpdatePodSandboxRequest) (*UpdatePodSandboxResponse, error)
|
||||||
|
StateChange(context.Context, *StateChangeEvent) (*Empty, error)
|
||||||
|
ValidateContainerAdjustment(context.Context, *ValidateContainerAdjustmentRequest) (*ValidateContainerAdjustmentResponse, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func RegisterPluginService(srv *ttrpc.Server, svc PluginService) {
|
||||||
|
srv.RegisterService("nri.pkg.api.v1alpha1.Plugin", &ttrpc.ServiceDesc{
|
||||||
|
Methods: map[string]ttrpc.Method{
|
||||||
|
"Configure": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) {
|
||||||
|
var req ConfigureRequest
|
||||||
|
if err := unmarshal(&req); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return svc.Configure(ctx, &req)
|
||||||
|
},
|
||||||
|
"Synchronize": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) {
|
||||||
|
var req SynchronizeRequest
|
||||||
|
if err := unmarshal(&req); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return svc.Synchronize(ctx, &req)
|
||||||
|
},
|
||||||
|
"Shutdown": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) {
|
||||||
|
var req Empty
|
||||||
|
if err := unmarshal(&req); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return svc.Shutdown(ctx, &req)
|
||||||
|
},
|
||||||
|
"CreateContainer": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) {
|
||||||
|
var req CreateContainerRequest
|
||||||
|
if err := unmarshal(&req); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return svc.CreateContainer(ctx, &req)
|
||||||
|
},
|
||||||
|
"UpdateContainer": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) {
|
||||||
|
var req UpdateContainerRequest
|
||||||
|
if err := unmarshal(&req); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return svc.UpdateContainer(ctx, &req)
|
||||||
|
},
|
||||||
|
"StopContainer": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) {
|
||||||
|
var req StopContainerRequest
|
||||||
|
if err := unmarshal(&req); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return svc.StopContainer(ctx, &req)
|
||||||
|
},
|
||||||
|
"UpdatePodSandbox": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) {
|
||||||
|
var req UpdatePodSandboxRequest
|
||||||
|
if err := unmarshal(&req); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return svc.UpdatePodSandbox(ctx, &req)
|
||||||
|
},
|
||||||
|
"StateChange": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) {
|
||||||
|
var req StateChangeEvent
|
||||||
|
if err := unmarshal(&req); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return svc.StateChange(ctx, &req)
|
||||||
|
},
|
||||||
|
"ValidateContainerAdjustment": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) {
|
||||||
|
var req ValidateContainerAdjustmentRequest
|
||||||
|
if err := unmarshal(&req); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return svc.ValidateContainerAdjustment(ctx, &req)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type pluginClient struct {
|
||||||
|
client *ttrpc.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPluginClient(client *ttrpc.Client) PluginService {
|
||||||
|
return &pluginClient{
|
||||||
|
client: client,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *pluginClient) Configure(ctx context.Context, req *ConfigureRequest) (*ConfigureResponse, error) {
|
||||||
|
var resp ConfigureResponse
|
||||||
|
if err := c.client.Call(ctx, "nri.pkg.api.v1alpha1.Plugin", "Configure", req, &resp); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *pluginClient) Synchronize(ctx context.Context, req *SynchronizeRequest) (*SynchronizeResponse, error) {
|
||||||
|
var resp SynchronizeResponse
|
||||||
|
if err := c.client.Call(ctx, "nri.pkg.api.v1alpha1.Plugin", "Synchronize", req, &resp); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *pluginClient) Shutdown(ctx context.Context, req *Empty) (*Empty, error) {
|
||||||
|
var resp Empty
|
||||||
|
if err := c.client.Call(ctx, "nri.pkg.api.v1alpha1.Plugin", "Shutdown", req, &resp); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *pluginClient) CreateContainer(ctx context.Context, req *CreateContainerRequest) (*CreateContainerResponse, error) {
|
||||||
|
var resp CreateContainerResponse
|
||||||
|
if err := c.client.Call(ctx, "nri.pkg.api.v1alpha1.Plugin", "CreateContainer", req, &resp); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *pluginClient) UpdateContainer(ctx context.Context, req *UpdateContainerRequest) (*UpdateContainerResponse, error) {
|
||||||
|
var resp UpdateContainerResponse
|
||||||
|
if err := c.client.Call(ctx, "nri.pkg.api.v1alpha1.Plugin", "UpdateContainer", req, &resp); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *pluginClient) StopContainer(ctx context.Context, req *StopContainerRequest) (*StopContainerResponse, error) {
|
||||||
|
var resp StopContainerResponse
|
||||||
|
if err := c.client.Call(ctx, "nri.pkg.api.v1alpha1.Plugin", "StopContainer", req, &resp); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *pluginClient) UpdatePodSandbox(ctx context.Context, req *UpdatePodSandboxRequest) (*UpdatePodSandboxResponse, error) {
|
||||||
|
var resp UpdatePodSandboxResponse
|
||||||
|
if err := c.client.Call(ctx, "nri.pkg.api.v1alpha1.Plugin", "UpdatePodSandbox", req, &resp); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *pluginClient) StateChange(ctx context.Context, req *StateChangeEvent) (*Empty, error) {
|
||||||
|
var resp Empty
|
||||||
|
if err := c.client.Call(ctx, "nri.pkg.api.v1alpha1.Plugin", "StateChange", req, &resp); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *pluginClient) ValidateContainerAdjustment(ctx context.Context, req *ValidateContainerAdjustmentRequest) (*ValidateContainerAdjustmentResponse, error) {
|
||||||
|
var resp ValidateContainerAdjustmentResponse
|
||||||
|
if err := c.client.Call(ctx, "nri.pkg.api.v1alpha1.Plugin", "ValidateContainerAdjustment", req, &resp); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type HostFunctionsService interface {
|
||||||
|
Log(context.Context, *LogRequest) (*Empty, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func RegisterHostFunctionsService(srv *ttrpc.Server, svc HostFunctionsService) {
|
||||||
|
srv.RegisterService("nri.pkg.api.v1alpha1.HostFunctions", &ttrpc.ServiceDesc{
|
||||||
|
Methods: map[string]ttrpc.Method{
|
||||||
|
"Log": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) {
|
||||||
|
var req LogRequest
|
||||||
|
if err := unmarshal(&req); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return svc.Log(ctx, &req)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type hostFunctionsClient struct {
|
||||||
|
client *ttrpc.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewHostFunctionsClient(client *ttrpc.Client) HostFunctionsService {
|
||||||
|
return &hostFunctionsClient{
|
||||||
|
client: client,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *hostFunctionsClient) Log(ctx context.Context, req *LogRequest) (*Empty, error) {
|
||||||
|
var resp Empty
|
||||||
|
if err := c.client.Call(ctx, "nri.pkg.api.v1alpha1.HostFunctions", "Log", req, &resp); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &resp, nil
|
||||||
|
}
|
||||||
15865
vendor/github.com/containerd/nri/pkg/api/api_vtproto.pb.go
generated
vendored
Normal file
15865
vendor/github.com/containerd/nri/pkg/api/api_vtproto.pb.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
43
vendor/github.com/containerd/nri/pkg/api/container.go
generated
vendored
Normal file
43
vendor/github.com/containerd/nri/pkg/api/container.go
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
Copyright The containerd Authors.
|
||||||
|
|
||||||
|
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 api
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
func (x *Container) GetCreatedAtTime() time.Time {
|
||||||
|
t := time.Time{}
|
||||||
|
if x != nil {
|
||||||
|
return t.Add(time.Duration(x.CreatedAt) * time.Nanosecond)
|
||||||
|
}
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Container) GetStartedAtTime() time.Time {
|
||||||
|
t := time.Time{}
|
||||||
|
if x != nil {
|
||||||
|
return t.Add(time.Duration(x.StartedAt) * time.Nanosecond)
|
||||||
|
}
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Container) GetFinishedAtTime() time.Time {
|
||||||
|
t := time.Time{}
|
||||||
|
if x != nil {
|
||||||
|
return t.Add(time.Duration(x.FinishedAt) * time.Nanosecond)
|
||||||
|
}
|
||||||
|
return t
|
||||||
|
}
|
||||||
89
vendor/github.com/containerd/nri/pkg/api/device.go
generated
vendored
Normal file
89
vendor/github.com/containerd/nri/pkg/api/device.go
generated
vendored
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
/*
|
||||||
|
Copyright The containerd Authors.
|
||||||
|
|
||||||
|
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 api
|
||||||
|
|
||||||
|
import (
|
||||||
|
rspec "github.com/opencontainers/runtime-spec/specs-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
// FromOCILinuxDevices returns a device slice from an OCI runtime Spec.
|
||||||
|
func FromOCILinuxDevices(o []rspec.LinuxDevice) []*LinuxDevice {
|
||||||
|
var devices []*LinuxDevice
|
||||||
|
for _, d := range o {
|
||||||
|
devices = append(devices, &LinuxDevice{
|
||||||
|
Path: d.Path,
|
||||||
|
Type: d.Type,
|
||||||
|
Major: d.Major,
|
||||||
|
Minor: d.Minor,
|
||||||
|
FileMode: FileMode(d.FileMode),
|
||||||
|
Uid: UInt32(d.UID),
|
||||||
|
Gid: UInt32(d.GID),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return devices
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToOCI returns the linux devices for an OCI runtime Spec.
|
||||||
|
func (d *LinuxDevice) ToOCI() rspec.LinuxDevice {
|
||||||
|
if d == nil {
|
||||||
|
return rspec.LinuxDevice{}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rspec.LinuxDevice{
|
||||||
|
Path: d.Path,
|
||||||
|
Type: d.Type,
|
||||||
|
Major: d.Major,
|
||||||
|
Minor: d.Minor,
|
||||||
|
FileMode: d.FileMode.Get(),
|
||||||
|
UID: d.Uid.Get(),
|
||||||
|
GID: d.Gid.Get(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AccessString returns an OCI access string for the device.
|
||||||
|
func (d *LinuxDevice) AccessString() string {
|
||||||
|
r, w, m := "r", "w", ""
|
||||||
|
|
||||||
|
if mode := d.FileMode.Get(); mode != nil {
|
||||||
|
perm := mode.Perm()
|
||||||
|
if (perm & 0444) != 0 {
|
||||||
|
r = "r"
|
||||||
|
}
|
||||||
|
if (perm & 0222) != 0 {
|
||||||
|
w = "w"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if d.Type == "b" {
|
||||||
|
m = "m"
|
||||||
|
}
|
||||||
|
|
||||||
|
return r + w + m
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cmp returns true if the devices are equal.
|
||||||
|
func (d *LinuxDevice) Cmp(v *LinuxDevice) bool {
|
||||||
|
if v == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return d.Major != v.Major || d.Minor != v.Minor
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsMarkedForRemoval checks if a LinuxDevice is marked for removal.
|
||||||
|
func (d *LinuxDevice) IsMarkedForRemoval() (string, bool) {
|
||||||
|
key, marked := IsMarkedForRemoval(d.Path)
|
||||||
|
return key, marked
|
||||||
|
}
|
||||||
17
vendor/github.com/containerd/nri/pkg/api/doc.go
generated
vendored
Normal file
17
vendor/github.com/containerd/nri/pkg/api/doc.go
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
/*
|
||||||
|
Copyright The containerd Authors.
|
||||||
|
|
||||||
|
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 api
|
||||||
60
vendor/github.com/containerd/nri/pkg/api/env.go
generated
vendored
Normal file
60
vendor/github.com/containerd/nri/pkg/api/env.go
generated
vendored
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
Copyright The containerd Authors.
|
||||||
|
|
||||||
|
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 api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ToOCI returns an OCI Env entry for the KeyValue.
|
||||||
|
func (e *KeyValue) ToOCI() string {
|
||||||
|
return e.Key + "=" + e.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromOCIEnv returns KeyValues from an OCI runtime Spec environment.
|
||||||
|
func FromOCIEnv(in []string) []*KeyValue {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := []*KeyValue{}
|
||||||
|
for _, keyval := range in {
|
||||||
|
var key, val string
|
||||||
|
split := strings.SplitN(keyval, "=", 2)
|
||||||
|
switch len(split) {
|
||||||
|
case 0:
|
||||||
|
continue
|
||||||
|
case 1:
|
||||||
|
key = split[0]
|
||||||
|
case 2:
|
||||||
|
key = split[0]
|
||||||
|
val = split[1]
|
||||||
|
default:
|
||||||
|
val = strings.Join(split[1:], "=")
|
||||||
|
}
|
||||||
|
out = append(out, &KeyValue{
|
||||||
|
Key: key,
|
||||||
|
Value: val,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsMarkedForRemoval checks if an environment variable is marked for removal.
|
||||||
|
func (e *KeyValue) IsMarkedForRemoval() (string, bool) {
|
||||||
|
key, marked := IsMarkedForRemoval(e.Key)
|
||||||
|
return key, marked
|
||||||
|
}
|
||||||
180
vendor/github.com/containerd/nri/pkg/api/event.go
generated
vendored
Normal file
180
vendor/github.com/containerd/nri/pkg/api/event.go
generated
vendored
Normal file
@@ -0,0 +1,180 @@
|
|||||||
|
/*
|
||||||
|
Copyright The containerd Authors.
|
||||||
|
|
||||||
|
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 api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// ValidEvents is the event mask of all valid events.
|
||||||
|
ValidEvents = EventMask((1 << (Event_LAST - 1)) - 1)
|
||||||
|
)
|
||||||
|
|
||||||
|
// nolint
|
||||||
|
type (
|
||||||
|
// Define *Request/*Response type aliases for *Event/Empty pairs.
|
||||||
|
|
||||||
|
StateChangeResponse = Empty
|
||||||
|
RunPodSandboxRequest = StateChangeEvent
|
||||||
|
RunPodSandboxResponse = Empty
|
||||||
|
StopPodSandboxRequest = StateChangeEvent
|
||||||
|
StopPodSandboxResponse = Empty
|
||||||
|
RemovePodSandboxRequest = StateChangeEvent
|
||||||
|
RemovePodSandboxResponse = Empty
|
||||||
|
PostUpdatePodSandboxRequest = StateChangeEvent
|
||||||
|
PostUpdatePodSandboxResponse = Empty
|
||||||
|
StartContainerRequest = StateChangeEvent
|
||||||
|
StartContainerResponse = Empty
|
||||||
|
RemoveContainerRequest = StateChangeEvent
|
||||||
|
RemoveContainerResponse = Empty
|
||||||
|
PostCreateContainerRequest = StateChangeEvent
|
||||||
|
PostCreateContainerResponse = Empty
|
||||||
|
PostStartContainerRequest = StateChangeEvent
|
||||||
|
PostStartContainerResponse = Empty
|
||||||
|
PostUpdateContainerRequest = StateChangeEvent
|
||||||
|
PostUpdateContainerResponse = Empty
|
||||||
|
|
||||||
|
ShutdownRequest = Empty
|
||||||
|
ShutdownResponse = Empty
|
||||||
|
)
|
||||||
|
|
||||||
|
// EventMask corresponds to a set of enumerated Events.
|
||||||
|
type EventMask int32
|
||||||
|
|
||||||
|
// ParseEventMask parses a string representation into an EventMask.
|
||||||
|
func ParseEventMask(events ...string) (EventMask, error) {
|
||||||
|
var mask EventMask
|
||||||
|
|
||||||
|
bits := map[string]Event{
|
||||||
|
"runpodsandbox": Event_RUN_POD_SANDBOX,
|
||||||
|
"updatepodsandbox": Event_UPDATE_POD_SANDBOX,
|
||||||
|
"postupdatepodsandbox": Event_POST_UPDATE_POD_SANDBOX,
|
||||||
|
"stoppodsandbox": Event_STOP_POD_SANDBOX,
|
||||||
|
"removepodsandbox": Event_REMOVE_POD_SANDBOX,
|
||||||
|
"createcontainer": Event_CREATE_CONTAINER,
|
||||||
|
"postcreatecontainer": Event_POST_CREATE_CONTAINER,
|
||||||
|
"startcontainer": Event_START_CONTAINER,
|
||||||
|
"poststartcontainer": Event_POST_START_CONTAINER,
|
||||||
|
"updatecontainer": Event_UPDATE_CONTAINER,
|
||||||
|
"postupdatecontainer": Event_POST_UPDATE_CONTAINER,
|
||||||
|
"stopcontainer": Event_STOP_CONTAINER,
|
||||||
|
"removecontainer": Event_REMOVE_CONTAINER,
|
||||||
|
"validatecontaineradjustment": Event_VALIDATE_CONTAINER_ADJUSTMENT,
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, event := range events {
|
||||||
|
lcEvents := strings.ToLower(event)
|
||||||
|
for _, name := range strings.Split(lcEvents, ",") {
|
||||||
|
switch name {
|
||||||
|
case "all":
|
||||||
|
mask |= ValidEvents
|
||||||
|
continue
|
||||||
|
case "pod", "podsandbox":
|
||||||
|
for name, bit := range bits {
|
||||||
|
if strings.Contains(name, "pod") {
|
||||||
|
mask.Set(bit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
case "container":
|
||||||
|
for name, bit := range bits {
|
||||||
|
if strings.Contains(name, "container") {
|
||||||
|
mask.Set(bit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
bit, ok := bits[strings.TrimSpace(name)]
|
||||||
|
if !ok {
|
||||||
|
return 0, fmt.Errorf("unknown event %q", name)
|
||||||
|
}
|
||||||
|
mask.Set(bit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return mask, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MustParseEventMask parses the given events, panic()ing on errors.
|
||||||
|
func MustParseEventMask(events ...string) EventMask {
|
||||||
|
mask, err := ParseEventMask(events...)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Sprintf("failed to parse events %s", strings.Join(events, " ")))
|
||||||
|
}
|
||||||
|
return mask
|
||||||
|
}
|
||||||
|
|
||||||
|
// PrettyString returns a human-readable string representation of an EventMask.
|
||||||
|
func (m *EventMask) PrettyString() string {
|
||||||
|
names := map[Event]string{
|
||||||
|
Event_RUN_POD_SANDBOX: "RunPodSandbox",
|
||||||
|
Event_UPDATE_POD_SANDBOX: "UpdatePodSandbox",
|
||||||
|
Event_POST_UPDATE_POD_SANDBOX: "PostUpdatePodSandbox",
|
||||||
|
Event_STOP_POD_SANDBOX: "StopPodSandbox",
|
||||||
|
Event_REMOVE_POD_SANDBOX: "RemovePodSandbox",
|
||||||
|
Event_CREATE_CONTAINER: "CreateContainer",
|
||||||
|
Event_POST_CREATE_CONTAINER: "PostCreateContainer",
|
||||||
|
Event_START_CONTAINER: "StartContainer",
|
||||||
|
Event_POST_START_CONTAINER: "PostStartContainer",
|
||||||
|
Event_UPDATE_CONTAINER: "UpdateContainer",
|
||||||
|
Event_POST_UPDATE_CONTAINER: "PostUpdateContainer",
|
||||||
|
Event_STOP_CONTAINER: "StopContainer",
|
||||||
|
Event_REMOVE_CONTAINER: "RemoveContainer",
|
||||||
|
Event_VALIDATE_CONTAINER_ADJUSTMENT: "ValidateContainerAdjustment",
|
||||||
|
}
|
||||||
|
|
||||||
|
mask := *m
|
||||||
|
events, sep := "", ""
|
||||||
|
|
||||||
|
for bit := Event_UNKNOWN + 1; bit <= Event_LAST; bit++ {
|
||||||
|
if mask.IsSet(bit) {
|
||||||
|
events += sep + names[bit]
|
||||||
|
sep = ","
|
||||||
|
mask.Clear(bit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if mask != 0 {
|
||||||
|
events += sep + fmt.Sprintf("unknown(0x%x)", mask)
|
||||||
|
}
|
||||||
|
|
||||||
|
return events
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set sets the given Events in the mask.
|
||||||
|
func (m *EventMask) Set(events ...Event) *EventMask {
|
||||||
|
for _, e := range events {
|
||||||
|
*m |= (1 << (e - 1))
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear clears the given Events in the mask.
|
||||||
|
func (m *EventMask) Clear(events ...Event) *EventMask {
|
||||||
|
for _, e := range events {
|
||||||
|
*m &^= (1 << (e - 1))
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsSet check if the given Event is set in the mask.
|
||||||
|
func (m *EventMask) IsSet(e Event) bool {
|
||||||
|
return *m&(1<<(e-1)) != 0
|
||||||
|
}
|
||||||
71
vendor/github.com/containerd/nri/pkg/api/helpers.go
generated
vendored
Normal file
71
vendor/github.com/containerd/nri/pkg/api/helpers.go
generated
vendored
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
Copyright The containerd Authors.
|
||||||
|
|
||||||
|
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 api
|
||||||
|
|
||||||
|
// DupStringSlice creates a copy of a string slice.
|
||||||
|
func DupStringSlice(in []string) []string {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := make([]string, len(in))
|
||||||
|
copy(out, in)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DupStringMap creates a copy of a map with string keys and values.
|
||||||
|
func DupStringMap(in map[string]string) map[string]string {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := map[string]string{}
|
||||||
|
for k, v := range in {
|
||||||
|
out[k] = v
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsMarkedForRemoval checks if a key is marked for removal.
|
||||||
|
//
|
||||||
|
// The key can be an annotation name, a mount container path, a device path,
|
||||||
|
// a namespace type, or an environment variable name.
|
||||||
|
// These are all marked for removal in adjustments by preceding
|
||||||
|
// their corresponding key with a '-'.
|
||||||
|
func IsMarkedForRemoval(key string) (string, bool) {
|
||||||
|
if key == "" {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
if key[0] != '-' {
|
||||||
|
return key, false
|
||||||
|
}
|
||||||
|
return key[1:], true
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarkForRemoval returns a key marked for removal.
|
||||||
|
func MarkForRemoval(key string) string {
|
||||||
|
return "-" + key
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClearRemovalMarker returns a key cleared from any removal marker.
|
||||||
|
func ClearRemovalMarker(key string) string {
|
||||||
|
if key == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
if key[0] == '-' {
|
||||||
|
return key[1:]
|
||||||
|
}
|
||||||
|
return key
|
||||||
|
}
|
||||||
103
vendor/github.com/containerd/nri/pkg/api/hooks.go
generated
vendored
Normal file
103
vendor/github.com/containerd/nri/pkg/api/hooks.go
generated
vendored
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
/*
|
||||||
|
Copyright The containerd Authors.
|
||||||
|
|
||||||
|
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 api
|
||||||
|
|
||||||
|
import (
|
||||||
|
rspec "github.com/opencontainers/runtime-spec/specs-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Append appends the given hooks to the existing ones.
|
||||||
|
func (hooks *Hooks) Append(h *Hooks) *Hooks {
|
||||||
|
if h == nil {
|
||||||
|
return hooks
|
||||||
|
}
|
||||||
|
hooks.Prestart = append(hooks.Prestart, h.Prestart...)
|
||||||
|
hooks.CreateRuntime = append(hooks.CreateRuntime, h.CreateRuntime...)
|
||||||
|
hooks.CreateContainer = append(hooks.CreateContainer, h.CreateContainer...)
|
||||||
|
hooks.StartContainer = append(hooks.StartContainer, h.StartContainer...)
|
||||||
|
hooks.Poststart = append(hooks.Poststart, h.Poststart...)
|
||||||
|
hooks.Poststop = append(hooks.Poststop, h.Poststop...)
|
||||||
|
|
||||||
|
return hooks
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hooks returns itself it any of its hooks is set. Otherwise it returns nil.
|
||||||
|
func (hooks *Hooks) Hooks() *Hooks {
|
||||||
|
if hooks == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(hooks.Prestart) > 0 {
|
||||||
|
return hooks
|
||||||
|
}
|
||||||
|
if len(hooks.CreateRuntime) > 0 {
|
||||||
|
return hooks
|
||||||
|
}
|
||||||
|
if len(hooks.CreateContainer) > 0 {
|
||||||
|
return hooks
|
||||||
|
}
|
||||||
|
if len(hooks.StartContainer) > 0 {
|
||||||
|
return hooks
|
||||||
|
}
|
||||||
|
if len(hooks.Poststart) > 0 {
|
||||||
|
return hooks
|
||||||
|
}
|
||||||
|
if len(hooks.Poststop) > 0 {
|
||||||
|
return hooks
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToOCI returns the hook for an OCI runtime Spec.
|
||||||
|
func (h *Hook) ToOCI() rspec.Hook {
|
||||||
|
return rspec.Hook{
|
||||||
|
Path: h.Path,
|
||||||
|
Args: DupStringSlice(h.Args),
|
||||||
|
Env: DupStringSlice(h.Env),
|
||||||
|
Timeout: h.Timeout.Get(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromOCIHooks returns hooks from an OCI runtime Spec.
|
||||||
|
func FromOCIHooks(o *rspec.Hooks) *Hooks {
|
||||||
|
if o == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &Hooks{
|
||||||
|
Prestart: FromOCIHookSlice(o.Prestart),
|
||||||
|
CreateRuntime: FromOCIHookSlice(o.CreateRuntime),
|
||||||
|
CreateContainer: FromOCIHookSlice(o.CreateContainer),
|
||||||
|
StartContainer: FromOCIHookSlice(o.StartContainer),
|
||||||
|
Poststart: FromOCIHookSlice(o.Poststart),
|
||||||
|
Poststop: FromOCIHookSlice(o.Poststop),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromOCIHookSlice returns a hook slice from an OCI runtime Spec.
|
||||||
|
func FromOCIHookSlice(o []rspec.Hook) []*Hook {
|
||||||
|
var hooks []*Hook
|
||||||
|
for _, h := range o {
|
||||||
|
hooks = append(hooks, &Hook{
|
||||||
|
Path: h.Path,
|
||||||
|
Args: DupStringSlice(h.Args),
|
||||||
|
Env: DupStringSlice(h.Env),
|
||||||
|
Timeout: Int(h.Timeout),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return hooks
|
||||||
|
}
|
||||||
63
vendor/github.com/containerd/nri/pkg/api/ioprio.go
generated
vendored
Normal file
63
vendor/github.com/containerd/nri/pkg/api/ioprio.go
generated
vendored
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
Copyright The containerd Authors.
|
||||||
|
|
||||||
|
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 api
|
||||||
|
|
||||||
|
import (
|
||||||
|
rspec "github.com/opencontainers/runtime-spec/specs-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
// FromOCILinuxIOPriority returns a LinuxIOPriority corresponding to the
|
||||||
|
// OCI LinuxIOPriority.
|
||||||
|
func FromOCILinuxIOPriority(o *rspec.LinuxIOPriority) *LinuxIOPriority {
|
||||||
|
if o == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ioprio := &LinuxIOPriority{
|
||||||
|
Class: FromOCIIOPriorityClass(o.Class),
|
||||||
|
Priority: int32(o.Priority),
|
||||||
|
}
|
||||||
|
|
||||||
|
return ioprio
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToOCI returns the OCI LinuxIOPriority corresponding to the LinuxIOPriority.
|
||||||
|
func (ioprio *LinuxIOPriority) ToOCI() *rspec.LinuxIOPriority {
|
||||||
|
if ioprio == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &rspec.LinuxIOPriority{
|
||||||
|
Class: ioprio.Class.ToOCI(),
|
||||||
|
Priority: int(ioprio.Priority),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromOCIIOPrioClass returns the IOPrioClass corresponding the the given
|
||||||
|
// OCI IOPriorityClass.
|
||||||
|
func FromOCIIOPriorityClass(o rspec.IOPriorityClass) IOPrioClass {
|
||||||
|
return IOPrioClass(IOPrioClass_value[string(o)])
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToOCI returns the OCI IOPriorityClass corresponding to the given
|
||||||
|
// IOPrioClass.
|
||||||
|
func (c IOPrioClass) ToOCI() rspec.IOPriorityClass {
|
||||||
|
if c == IOPrioClass_IOPRIO_CLASS_NONE {
|
||||||
|
return rspec.IOPriorityClass("")
|
||||||
|
}
|
||||||
|
return rspec.IOPriorityClass(IOPrioClass_name[int32(c)])
|
||||||
|
}
|
||||||
88
vendor/github.com/containerd/nri/pkg/api/mount.go
generated
vendored
Normal file
88
vendor/github.com/containerd/nri/pkg/api/mount.go
generated
vendored
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
Copyright The containerd Authors.
|
||||||
|
|
||||||
|
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 api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sort"
|
||||||
|
|
||||||
|
rspec "github.com/opencontainers/runtime-spec/specs-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// SELinuxRelabel is a Mount pseudo-option to request relabeling.
|
||||||
|
SELinuxRelabel = "relabel"
|
||||||
|
)
|
||||||
|
|
||||||
|
// FromOCIMounts returns a Mount slice for an OCI runtime Spec.
|
||||||
|
func FromOCIMounts(o []rspec.Mount) []*Mount {
|
||||||
|
var mounts []*Mount
|
||||||
|
for _, m := range o {
|
||||||
|
mounts = append(mounts, &Mount{
|
||||||
|
Destination: m.Destination,
|
||||||
|
Type: m.Type,
|
||||||
|
Source: m.Source,
|
||||||
|
Options: DupStringSlice(m.Options),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return mounts
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToOCI returns a Mount for an OCI runtime Spec.
|
||||||
|
func (m *Mount) ToOCI(propagationQuery *string) rspec.Mount {
|
||||||
|
o := rspec.Mount{
|
||||||
|
Destination: m.Destination,
|
||||||
|
Type: m.Type,
|
||||||
|
Source: m.Source,
|
||||||
|
}
|
||||||
|
for _, opt := range m.Options {
|
||||||
|
o.Options = append(o.Options, opt)
|
||||||
|
if propagationQuery != nil && (opt == "rprivate" || opt == "rshared" || opt == "rslave") {
|
||||||
|
*propagationQuery = opt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cmp returns true if the mounts are equal.
|
||||||
|
func (m *Mount) Cmp(v *Mount) bool {
|
||||||
|
if v == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if m.Destination != v.Destination || m.Type != v.Type || m.Source != v.Source ||
|
||||||
|
len(m.Options) != len(v.Options) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
mOpts := make([]string, len(m.Options))
|
||||||
|
vOpts := make([]string, len(m.Options))
|
||||||
|
sort.Strings(mOpts)
|
||||||
|
sort.Strings(vOpts)
|
||||||
|
|
||||||
|
for i, o := range mOpts {
|
||||||
|
if vOpts[i] != o {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsMarkedForRemoval checks if a Mount is marked for removal.
|
||||||
|
func (m *Mount) IsMarkedForRemoval() (string, bool) {
|
||||||
|
key, marked := IsMarkedForRemoval(m.Destination)
|
||||||
|
return key, marked
|
||||||
|
}
|
||||||
38
vendor/github.com/containerd/nri/pkg/api/namespace.go
generated
vendored
Normal file
38
vendor/github.com/containerd/nri/pkg/api/namespace.go
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
Copyright The containerd Authors.
|
||||||
|
|
||||||
|
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 api
|
||||||
|
|
||||||
|
import (
|
||||||
|
rspec "github.com/opencontainers/runtime-spec/specs-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
// FromOCILinuxNamespaces returns a namespace slice from an OCI runtime Spec.
|
||||||
|
func FromOCILinuxNamespaces(o []rspec.LinuxNamespace) []*LinuxNamespace {
|
||||||
|
var namespaces []*LinuxNamespace
|
||||||
|
for _, ns := range o {
|
||||||
|
namespaces = append(namespaces, &LinuxNamespace{
|
||||||
|
Type: string(ns.Type),
|
||||||
|
Path: ns.Path,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return namespaces
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsMarkedForRemoval checks if a LinuxNamespace is marked for removal.
|
||||||
|
func (n *LinuxNamespace) IsMarkedForRemoval() (string, bool) {
|
||||||
|
return IsMarkedForRemoval(n.Type)
|
||||||
|
}
|
||||||
341
vendor/github.com/containerd/nri/pkg/api/optional.go
generated
vendored
Normal file
341
vendor/github.com/containerd/nri/pkg/api/optional.go
generated
vendored
Normal file
@@ -0,0 +1,341 @@
|
|||||||
|
/*
|
||||||
|
Copyright The containerd Authors.
|
||||||
|
|
||||||
|
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 api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
//
|
||||||
|
// XXX FIXME:
|
||||||
|
//
|
||||||
|
// The optional interface constructor should be updated/split up
|
||||||
|
// to avoid having to take an interface{} argument. Instead The
|
||||||
|
// optional types should have a
|
||||||
|
// - constructor taking the underlying native type
|
||||||
|
// - a Copy() function for copying them
|
||||||
|
// - a FromPointer constructor to create them from an optionally nil
|
||||||
|
// pointer to the underlying native type (to help constructing from
|
||||||
|
// structures that use a pointer to the native underlying type to
|
||||||
|
// denote optionality (OCI Spec mostly))
|
||||||
|
// Creating from any other type should use one of these with any explicit
|
||||||
|
// cast for the argument as necessary.
|
||||||
|
//
|
||||||
|
|
||||||
|
// String creates an Optional wrapper from its argument.
|
||||||
|
func String(v interface{}) *OptionalString {
|
||||||
|
var value string
|
||||||
|
|
||||||
|
switch o := v.(type) {
|
||||||
|
case string:
|
||||||
|
value = o
|
||||||
|
case *string:
|
||||||
|
if o == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
value = *o
|
||||||
|
case *OptionalString:
|
||||||
|
if o == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
value = o.Value
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &OptionalString{
|
||||||
|
Value: value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns nil if its value is unset or a pointer to the value itself.
|
||||||
|
func (o *OptionalString) Get() *string {
|
||||||
|
if o == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
v := o.Value
|
||||||
|
return &v
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int creates an Optional wrapper from its argument.
|
||||||
|
func Int(v interface{}) *OptionalInt {
|
||||||
|
var value int64
|
||||||
|
|
||||||
|
switch o := v.(type) {
|
||||||
|
case int:
|
||||||
|
value = int64(o)
|
||||||
|
case *int:
|
||||||
|
if o == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
value = int64(*o)
|
||||||
|
case *OptionalInt:
|
||||||
|
if o == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
value = o.Value
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &OptionalInt{
|
||||||
|
Value: value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns nil if its value is unset or a pointer to the value itself.
|
||||||
|
func (o *OptionalInt) Get() *int {
|
||||||
|
if o == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
v := int(o.Value)
|
||||||
|
return &v
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int32 creates an Optional wrapper from its argument.
|
||||||
|
func Int32(v interface{}) *OptionalInt32 {
|
||||||
|
var value int32
|
||||||
|
|
||||||
|
switch o := v.(type) {
|
||||||
|
case int32:
|
||||||
|
value = o
|
||||||
|
case *int32:
|
||||||
|
if o == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
value = *o
|
||||||
|
case *OptionalInt32:
|
||||||
|
if o == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
value = o.Value
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &OptionalInt32{
|
||||||
|
Value: value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns nil if its value is unset or a pointer to the value itself.
|
||||||
|
func (o *OptionalInt32) Get() *int32 {
|
||||||
|
if o == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
v := o.Value
|
||||||
|
return &v
|
||||||
|
}
|
||||||
|
|
||||||
|
// UInt32 creates an Optional wrapper from its argument.
|
||||||
|
func UInt32(v interface{}) *OptionalUInt32 {
|
||||||
|
var value uint32
|
||||||
|
|
||||||
|
switch o := v.(type) {
|
||||||
|
case uint32:
|
||||||
|
value = o
|
||||||
|
case *uint32:
|
||||||
|
if o == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
value = *o
|
||||||
|
case *OptionalUInt32:
|
||||||
|
if o == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
value = o.Value
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &OptionalUInt32{
|
||||||
|
Value: value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns nil if its value is unset or a pointer to the value itself.
|
||||||
|
func (o *OptionalUInt32) Get() *uint32 {
|
||||||
|
if o == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
v := o.Value
|
||||||
|
return &v
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int64 creates an Optional wrapper from its argument.
|
||||||
|
func Int64(v interface{}) *OptionalInt64 {
|
||||||
|
var value int64
|
||||||
|
|
||||||
|
switch o := v.(type) {
|
||||||
|
case int:
|
||||||
|
value = int64(o)
|
||||||
|
case uint:
|
||||||
|
value = int64(o)
|
||||||
|
case uint64:
|
||||||
|
value = int64(o)
|
||||||
|
case int64:
|
||||||
|
value = o
|
||||||
|
case *int64:
|
||||||
|
if o == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
value = *o
|
||||||
|
case *uint64:
|
||||||
|
if o == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
value = int64(*o)
|
||||||
|
case *OptionalInt64:
|
||||||
|
if o == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
value = o.Value
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &OptionalInt64{
|
||||||
|
Value: value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns nil if its value is unset or a pointer to the value itself.
|
||||||
|
func (o *OptionalInt64) Get() *int64 {
|
||||||
|
if o == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
v := o.Value
|
||||||
|
return &v
|
||||||
|
}
|
||||||
|
|
||||||
|
// UInt64 creates an Optional wrapper from its argument.
|
||||||
|
func UInt64(v interface{}) *OptionalUInt64 {
|
||||||
|
var value uint64
|
||||||
|
|
||||||
|
switch o := v.(type) {
|
||||||
|
case int:
|
||||||
|
value = uint64(o)
|
||||||
|
case uint:
|
||||||
|
value = uint64(o)
|
||||||
|
case int64:
|
||||||
|
value = uint64(o)
|
||||||
|
case uint64:
|
||||||
|
value = o
|
||||||
|
case *int64:
|
||||||
|
if o == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
value = uint64(*o)
|
||||||
|
case *uint64:
|
||||||
|
if o == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
value = *o
|
||||||
|
case *OptionalUInt64:
|
||||||
|
if o == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
value = o.Value
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &OptionalUInt64{
|
||||||
|
Value: value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns nil if its value is unset or a pointer to the value itself.
|
||||||
|
func (o *OptionalUInt64) Get() *uint64 {
|
||||||
|
if o == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
v := o.Value
|
||||||
|
return &v
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bool creates an Optional wrapper from its argument.
|
||||||
|
func Bool(v interface{}) *OptionalBool {
|
||||||
|
var value bool
|
||||||
|
|
||||||
|
switch o := v.(type) {
|
||||||
|
case bool:
|
||||||
|
value = o
|
||||||
|
case *bool:
|
||||||
|
if o == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
value = *o
|
||||||
|
case *OptionalBool:
|
||||||
|
if o == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
value = o.Value
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &OptionalBool{
|
||||||
|
Value: value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns nil if its value is unset or a pointer to the value itself.
|
||||||
|
func (o *OptionalBool) Get() *bool {
|
||||||
|
if o == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
v := o.Value
|
||||||
|
return &v
|
||||||
|
}
|
||||||
|
|
||||||
|
// FileMode creates an Optional wrapper from its argument.
|
||||||
|
func FileMode(v interface{}) *OptionalFileMode {
|
||||||
|
var value os.FileMode
|
||||||
|
|
||||||
|
switch o := v.(type) {
|
||||||
|
case *os.FileMode:
|
||||||
|
if o == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
value = *o
|
||||||
|
case os.FileMode:
|
||||||
|
value = o
|
||||||
|
case *OptionalFileMode:
|
||||||
|
if o == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
value = os.FileMode(o.Value)
|
||||||
|
case uint32:
|
||||||
|
value = os.FileMode(o)
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &OptionalFileMode{
|
||||||
|
Value: uint32(value),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns nil if its value is unset or a pointer to the value itself.
|
||||||
|
func (o *OptionalFileMode) Get() *os.FileMode {
|
||||||
|
if o == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
v := os.FileMode(o.Value)
|
||||||
|
return &v
|
||||||
|
}
|
||||||
749
vendor/github.com/containerd/nri/pkg/api/owners.go
generated
vendored
Normal file
749
vendor/github.com/containerd/nri/pkg/api/owners.go
generated
vendored
Normal file
@@ -0,0 +1,749 @@
|
|||||||
|
/*
|
||||||
|
Copyright The containerd Authors.
|
||||||
|
|
||||||
|
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 api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
//
|
||||||
|
// Notes:
|
||||||
|
// OwningPlugins, FieldOwners and CompoundFieldOwners are not protected
|
||||||
|
// against concurrent access and therefore not goroutine safe.
|
||||||
|
//
|
||||||
|
// None of these functions are used by plugins directly. These are used by
|
||||||
|
// the runtime adaptation code to track container adjustments and updates
|
||||||
|
// requested by plugins, and to detect conflicting requests.
|
||||||
|
//
|
||||||
|
|
||||||
|
func NewOwningPlugins() *OwningPlugins {
|
||||||
|
return &OwningPlugins{
|
||||||
|
Owners: make(map[string]*FieldOwners),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) ClaimAnnotation(id, key, plugin string) error {
|
||||||
|
return o.mustOwnersFor(id).ClaimAnnotation(key, plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) ClaimMount(id, destination, plugin string) error {
|
||||||
|
return o.mustOwnersFor(id).ClaimMount(destination, plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) ClaimHooks(id, plugin string) error {
|
||||||
|
return o.mustOwnersFor(id).ClaimHooks(plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) ClaimDevice(id, path, plugin string) error {
|
||||||
|
return o.mustOwnersFor(id).ClaimDevice(path, plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) ClaimNamespace(id, typ, plugin string) error {
|
||||||
|
return o.mustOwnersFor(id).ClaimNamespace(typ, plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) ClaimCdiDevice(id, name, plugin string) error {
|
||||||
|
return o.mustOwnersFor(id).ClaimCdiDevice(name, plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) ClaimEnv(id, name, plugin string) error {
|
||||||
|
return o.mustOwnersFor(id).ClaimEnv(name, plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) ClaimArgs(id, plugin string) error {
|
||||||
|
return o.mustOwnersFor(id).ClaimArgs(plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) ClaimMemLimit(id, plugin string) error {
|
||||||
|
return o.mustOwnersFor(id).ClaimMemLimit(plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) ClaimMemReservation(id, plugin string) error {
|
||||||
|
return o.mustOwnersFor(id).ClaimMemReservation(plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) ClaimMemSwapLimit(id, plugin string) error {
|
||||||
|
return o.mustOwnersFor(id).ClaimMemSwapLimit(plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) ClaimMemKernelLimit(id, plugin string) error {
|
||||||
|
return o.mustOwnersFor(id).ClaimMemKernelLimit(plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) ClaimMemTCPLimit(id, plugin string) error {
|
||||||
|
return o.mustOwnersFor(id).ClaimMemTCPLimit(plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) ClaimMemSwappiness(id, plugin string) error {
|
||||||
|
return o.mustOwnersFor(id).ClaimMemSwappiness(plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) ClaimMemDisableOomKiller(id, plugin string) error {
|
||||||
|
return o.mustOwnersFor(id).ClaimMemDisableOomKiller(plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) ClaimMemUseHierarchy(id, plugin string) error {
|
||||||
|
return o.mustOwnersFor(id).ClaimMemUseHierarchy(plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) ClaimCPUShares(id, plugin string) error {
|
||||||
|
return o.mustOwnersFor(id).ClaimCPUShares(plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) ClaimCPUQuota(id, plugin string) error {
|
||||||
|
return o.mustOwnersFor(id).ClaimCPUQuota(plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) ClaimCPUPeriod(id, plugin string) error {
|
||||||
|
return o.mustOwnersFor(id).ClaimCPUPeriod(plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) ClaimCPURealtimeRuntime(id, plugin string) error {
|
||||||
|
return o.mustOwnersFor(id).ClaimCPURealtimeRuntime(plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) ClaimCPURealtimePeriod(id, plugin string) error {
|
||||||
|
return o.mustOwnersFor(id).ClaimCPURealtimePeriod(plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) ClaimCPUSetCPUs(id, plugin string) error {
|
||||||
|
return o.mustOwnersFor(id).ClaimCPUSetCPUs(plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) ClaimCPUSetMems(id, plugin string) error {
|
||||||
|
return o.mustOwnersFor(id).ClaimCPUSetMems(plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) ClaimPidsLimit(id, plugin string) error {
|
||||||
|
return o.mustOwnersFor(id).ClaimPidsLimit(plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) ClaimHugepageLimit(id, size, plugin string) error {
|
||||||
|
return o.mustOwnersFor(id).ClaimHugepageLimit(size, plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) ClaimBlockioClass(id, plugin string) error {
|
||||||
|
return o.mustOwnersFor(id).ClaimBlockioClass(plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) ClaimRdtClass(id, plugin string) error {
|
||||||
|
return o.mustOwnersFor(id).ClaimRdtClass(plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) ClaimCgroupsUnified(id, key, plugin string) error {
|
||||||
|
return o.mustOwnersFor(id).ClaimCgroupsUnified(key, plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) ClaimCgroupsPath(id, plugin string) error {
|
||||||
|
return o.mustOwnersFor(id).ClaimCgroupsPath(plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) ClaimOomScoreAdj(id, plugin string) error {
|
||||||
|
return o.mustOwnersFor(id).ClaimOomScoreAdj(plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) ClaimRlimit(id, typ, plugin string) error {
|
||||||
|
return o.mustOwnersFor(id).ClaimRlimit(typ, plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) ClaimIOPriority(id, plugin string) error {
|
||||||
|
return o.mustOwnersFor(id).ClaimIOPriority(plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) ClaimSeccompPolicy(id, plugin string) error {
|
||||||
|
return o.mustOwnersFor(id).ClaimSeccompPolicy(plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) ClearAnnotation(id, key, plugin string) {
|
||||||
|
o.mustOwnersFor(id).ClearAnnotation(key, plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) ClearMount(id, key, plugin string) {
|
||||||
|
o.mustOwnersFor(id).ClearMount(key, plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) ClearDevice(id, key, plugin string) {
|
||||||
|
o.mustOwnersFor(id).ClearDevice(key, plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) ClearEnv(id, key, plugin string) {
|
||||||
|
o.mustOwnersFor(id).ClearEnv(key, plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) ClearArgs(id, plugin string) {
|
||||||
|
o.mustOwnersFor(id).ClearArgs(plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) AnnotationOwner(id, key string) (string, bool) {
|
||||||
|
return o.ownersFor(id).compoundOwner(Field_Annotations.Key(), key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) MountOwner(id, destination string) (string, bool) {
|
||||||
|
return o.ownersFor(id).compoundOwner(Field_Mounts.Key(), destination)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) HooksOwner(id string) (string, bool) {
|
||||||
|
return o.ownersFor(id).simpleOwner(Field_OciHooks.Key())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) DeviceOwner(id, path string) (string, bool) {
|
||||||
|
return o.ownersFor(id).compoundOwner(Field_Devices.Key(), path)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) NamespaceOwner(id, path string) (string, bool) {
|
||||||
|
return o.ownersFor(id).compoundOwner(Field_Namespace.Key(), path)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) NamespaceOwners(id string) (map[string]string, bool) {
|
||||||
|
return o.ownersFor(id).compoundOwnerMap(Field_Namespace.Key())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) EnvOwner(id, name string) (string, bool) {
|
||||||
|
return o.ownersFor(id).compoundOwner(Field_Env.Key(), name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) ArgsOwner(id string) (string, bool) {
|
||||||
|
return o.ownersFor(id).simpleOwner(Field_Args.Key())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) MemLimitOwner(id string) (string, bool) {
|
||||||
|
return o.ownersFor(id).simpleOwner(Field_MemLimit.Key())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) MemReservationOwner(id string) (string, bool) {
|
||||||
|
return o.ownersFor(id).simpleOwner(Field_MemReservation.Key())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) MemSwapLimitOwner(id string) (string, bool) {
|
||||||
|
return o.ownersFor(id).simpleOwner(Field_MemSwapLimit.Key())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) MemKernelLimitOwner(id string) (string, bool) {
|
||||||
|
return o.ownersFor(id).simpleOwner(Field_MemKernelLimit.Key())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) MemTCPLimitOwner(id string) (string, bool) {
|
||||||
|
return o.ownersFor(id).simpleOwner(Field_MemTCPLimit.Key())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) MemSwappinessOwner(id string) (string, bool) {
|
||||||
|
return o.ownersFor(id).simpleOwner(Field_MemSwappiness.Key())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) MemDisableOomKillerOwner(id string) (string, bool) {
|
||||||
|
return o.ownersFor(id).simpleOwner(Field_MemDisableOomKiller.Key())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) MemUseHierarchyOwner(id string) (string, bool) {
|
||||||
|
return o.ownersFor(id).simpleOwner(Field_MemUseHierarchy.Key())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) CPUSharesOwner(id string) (string, bool) {
|
||||||
|
return o.ownersFor(id).simpleOwner(Field_CPUShares.Key())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) CPUQuotaOwner(id string) (string, bool) {
|
||||||
|
return o.ownersFor(id).simpleOwner(Field_CPUQuota.Key())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) CPUPeriodOwner(id string) (string, bool) {
|
||||||
|
return o.ownersFor(id).simpleOwner(Field_CPUPeriod.Key())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) CPURealtimeRuntimeOwner(id string) (string, bool) {
|
||||||
|
return o.ownersFor(id).simpleOwner(Field_CPURealtimeRuntime.Key())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) CPURealtimePeriodOwner(id string) (string, bool) {
|
||||||
|
return o.ownersFor(id).simpleOwner(Field_CPURealtimePeriod.Key())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) CPUSetCPUsOwner(id string) (string, bool) {
|
||||||
|
return o.ownersFor(id).simpleOwner(Field_CPUSetCPUs.Key())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) CPUSetMemsOwner(id string) (string, bool) {
|
||||||
|
return o.ownersFor(id).simpleOwner(Field_CPUSetMems.Key())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) PidsLimitOwner(id string) (string, bool) {
|
||||||
|
return o.ownersFor(id).simpleOwner(Field_PidsLimit.Key())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) HugepageLimitOwner(id, size string) (string, bool) {
|
||||||
|
return o.ownersFor(id).compoundOwner(Field_HugepageLimits.Key(), size)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) BlockioClassOwner(id string) (string, bool) {
|
||||||
|
return o.ownersFor(id).simpleOwner(Field_BlockioClass.Key())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) RdtClassOwner(id string) (string, bool) {
|
||||||
|
return o.ownersFor(id).simpleOwner(Field_RdtClass.Key())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) CgroupsUnifiedOwner(id, key string) (string, bool) {
|
||||||
|
return o.ownersFor(id).compoundOwner(Field_CgroupsUnified.Key(), key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) CgroupsPathOwner(id string) (string, bool) {
|
||||||
|
return o.ownersFor(id).simpleOwner(Field_CgroupsPath.Key())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) OomScoreAdjOwner(id string) (string, bool) {
|
||||||
|
return o.ownersFor(id).simpleOwner(Field_OomScoreAdj.Key())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) RlimitOwner(id, typ string) (string, bool) {
|
||||||
|
return o.ownersFor(id).compoundOwner(Field_Rlimits.Key(), typ)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) IOPriorityOwner(id string) (string, bool) {
|
||||||
|
return o.ownersFor(id).simpleOwner(Field_IoPriority.Key())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) SeccompPolicyOwner(id string) (string, bool) {
|
||||||
|
return o.ownersFor(id).simpleOwner(Field_SeccompPolicy.Key())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) mustOwnersFor(id string) *FieldOwners {
|
||||||
|
f, ok := o.Owners[id]
|
||||||
|
if !ok {
|
||||||
|
f = NewFieldOwners()
|
||||||
|
o.Owners[id] = f
|
||||||
|
}
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OwningPlugins) ownersFor(id string) *FieldOwners {
|
||||||
|
f, ok := o.Owners[id]
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewFieldOwners() *FieldOwners {
|
||||||
|
return &FieldOwners{
|
||||||
|
Simple: make(map[int32]string),
|
||||||
|
Compound: make(map[int32]*CompoundFieldOwners),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) IsCompoundConflict(field int32, key, plugin string) error {
|
||||||
|
m, ok := f.Compound[field]
|
||||||
|
if !ok {
|
||||||
|
f.Compound[field] = NewCompoundFieldOwners()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
other, claimed := m.Owners[key]
|
||||||
|
if !claimed {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
clearer, ok := IsMarkedForRemoval(other)
|
||||||
|
if ok {
|
||||||
|
if clearer == plugin {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
other = clearer
|
||||||
|
}
|
||||||
|
|
||||||
|
return f.Conflict(field, plugin, other, key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) IsSimpleConflict(field int32, plugin string) error {
|
||||||
|
other, claimed := f.Simple[field]
|
||||||
|
if !claimed {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
clearer, ok := IsMarkedForRemoval(other)
|
||||||
|
if ok {
|
||||||
|
if clearer == plugin {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
other = clearer
|
||||||
|
}
|
||||||
|
|
||||||
|
return f.Conflict(field, plugin, other)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) claimCompound(field int32, entry, plugin string) error {
|
||||||
|
if err := f.IsCompoundConflict(field, entry, plugin); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
f.Compound[field].Owners[entry] = plugin
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) claimSimple(field int32, plugin string) error {
|
||||||
|
if err := f.IsSimpleConflict(field, plugin); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
f.Simple[field] = plugin
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) ClaimAnnotation(key, plugin string) error {
|
||||||
|
return f.claimCompound(Field_Annotations.Key(), key, plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) ClaimMount(destination, plugin string) error {
|
||||||
|
return f.claimCompound(Field_Mounts.Key(), destination, plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) ClaimHooks(plugin string) error {
|
||||||
|
plugins := plugin
|
||||||
|
|
||||||
|
if current, ok := f.simpleOwner(Field_OciHooks.Key()); ok {
|
||||||
|
f.clearSimple(Field_OciHooks.Key(), plugin)
|
||||||
|
plugins = current + "," + plugin
|
||||||
|
}
|
||||||
|
|
||||||
|
f.claimSimple(Field_OciHooks.Key(), plugins)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) ClaimDevice(path, plugin string) error {
|
||||||
|
return f.claimCompound(Field_Devices.Key(), path, plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) ClaimCdiDevice(name, plugin string) error {
|
||||||
|
return f.claimCompound(Field_CdiDevices.Key(), name, plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) ClaimNamespace(typ, plugin string) error {
|
||||||
|
return f.claimCompound(Field_Namespace.Key(), typ, plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) ClaimEnv(name, plugin string) error {
|
||||||
|
return f.claimCompound(Field_Env.Key(), name, plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) ClaimArgs(plugin string) error {
|
||||||
|
return f.claimSimple(Field_Args.Key(), plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) ClaimMemLimit(plugin string) error {
|
||||||
|
return f.claimSimple(Field_MemLimit.Key(), plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) ClaimMemReservation(plugin string) error {
|
||||||
|
return f.claimSimple(Field_MemReservation.Key(), plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) ClaimMemSwapLimit(plugin string) error {
|
||||||
|
return f.claimSimple(Field_MemSwapLimit.Key(), plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) ClaimMemKernelLimit(plugin string) error {
|
||||||
|
return f.claimSimple(Field_MemKernelLimit.Key(), plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) ClaimMemTCPLimit(plugin string) error {
|
||||||
|
return f.claimSimple(Field_MemTCPLimit.Key(), plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) ClaimMemSwappiness(plugin string) error {
|
||||||
|
return f.claimSimple(Field_MemSwappiness.Key(), plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) ClaimMemDisableOomKiller(plugin string) error {
|
||||||
|
return f.claimSimple(Field_MemDisableOomKiller.Key(), plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) ClaimMemUseHierarchy(plugin string) error {
|
||||||
|
return f.claimSimple(Field_MemUseHierarchy.Key(), plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) ClaimCPUShares(plugin string) error {
|
||||||
|
return f.claimSimple(Field_CPUShares.Key(), plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) ClaimCPUQuota(plugin string) error {
|
||||||
|
return f.claimSimple(Field_CPUQuota.Key(), plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) ClaimCPUPeriod(plugin string) error {
|
||||||
|
return f.claimSimple(Field_CPUPeriod.Key(), plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) ClaimCPURealtimeRuntime(plugin string) error {
|
||||||
|
return f.claimSimple(Field_CPURealtimeRuntime.Key(), plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) ClaimCPURealtimePeriod(plugin string) error {
|
||||||
|
return f.claimSimple(Field_CPURealtimePeriod.Key(), plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) ClaimCPUSetCPUs(plugin string) error {
|
||||||
|
return f.claimSimple(Field_CPUSetCPUs.Key(), plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) ClaimCPUSetMems(plugin string) error {
|
||||||
|
return f.claimSimple(Field_CPUSetMems.Key(), plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) ClaimPidsLimit(plugin string) error {
|
||||||
|
return f.claimSimple(Field_PidsLimit.Key(), plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) ClaimHugepageLimit(size, plugin string) error {
|
||||||
|
return f.claimCompound(Field_HugepageLimits.Key(), size, plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) ClaimBlockioClass(plugin string) error {
|
||||||
|
return f.claimSimple(Field_BlockioClass.Key(), plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) ClaimRdtClass(plugin string) error {
|
||||||
|
return f.claimSimple(Field_RdtClass.Key(), plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) ClaimCgroupsUnified(key, plugin string) error {
|
||||||
|
return f.claimCompound(Field_CgroupsUnified.Key(), key, plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) ClaimCgroupsPath(plugin string) error {
|
||||||
|
return f.claimSimple(Field_CgroupsPath.Key(), plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) ClaimOomScoreAdj(plugin string) error {
|
||||||
|
return f.claimSimple(Field_OomScoreAdj.Key(), plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) ClaimRlimit(typ, plugin string) error {
|
||||||
|
return f.claimCompound(Field_Rlimits.Key(), typ, plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) ClaimIOPriority(plugin string) error {
|
||||||
|
return f.claimSimple(Field_IoPriority.Key(), plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) ClaimSeccompPolicy(plugin string) error {
|
||||||
|
return f.claimSimple(Field_SeccompPolicy.Key(), plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) clearCompound(field int32, key, plugin string) {
|
||||||
|
m, ok := f.Compound[field]
|
||||||
|
if !ok {
|
||||||
|
m = NewCompoundFieldOwners()
|
||||||
|
f.Compound[field] = m
|
||||||
|
}
|
||||||
|
|
||||||
|
m.Owners[key] = MarkForRemoval(plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) clearSimple(field int32, plugin string) {
|
||||||
|
f.Simple[field] = MarkForRemoval(plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) ClearAnnotation(key, plugin string) {
|
||||||
|
f.clearCompound(Field_Annotations.Key(), key, plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) ClearMount(destination, plugin string) {
|
||||||
|
f.clearCompound(Field_Mounts.Key(), destination, plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) ClearDevice(path, plugin string) {
|
||||||
|
f.clearCompound(Field_Devices.Key(), path, plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) ClearEnv(name, plugin string) {
|
||||||
|
f.clearCompound(Field_Env.Key(), name, plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) ClearArgs(plugin string) {
|
||||||
|
f.clearSimple(Field_Args.Key(), plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) Conflict(field int32, plugin, other string, qualifiers ...string) error {
|
||||||
|
return fmt.Errorf("plugins %q and %q both tried to set %s",
|
||||||
|
plugin, other, qualify(field, qualifiers...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) compoundOwnerMap(field int32) (map[string]string, bool) {
|
||||||
|
if f == nil {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
m, ok := f.Compound[field]
|
||||||
|
if !ok {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
return m.Owners, true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) compoundOwner(field int32, key string) (string, bool) {
|
||||||
|
if f == nil {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
m, ok := f.Compound[field]
|
||||||
|
if !ok {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
plugin, ok := m.Owners[key]
|
||||||
|
return plugin, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) simpleOwner(field int32) (string, bool) {
|
||||||
|
if f == nil {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
plugin, ok := f.Simple[field]
|
||||||
|
return plugin, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) AnnotationOwner(key string) (string, bool) {
|
||||||
|
return f.compoundOwner(Field_Annotations.Key(), key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) MountOwner(destination string) (string, bool) {
|
||||||
|
return f.compoundOwner(Field_Mounts.Key(), destination)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) DeviceOwner(path string) (string, bool) {
|
||||||
|
return f.compoundOwner(Field_Devices.Key(), path)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) NamespaceOwner(typ string) (string, bool) {
|
||||||
|
return f.compoundOwner(Field_Devices.Key(), typ)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) EnvOwner(name string) (string, bool) {
|
||||||
|
return f.compoundOwner(Field_Env.Key(), name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) ArgsOwner() (string, bool) {
|
||||||
|
return f.simpleOwner(Field_Args.Key())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) MemLimitOwner() (string, bool) {
|
||||||
|
return f.simpleOwner(Field_MemLimit.Key())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) MemReservationOwner() (string, bool) {
|
||||||
|
return f.simpleOwner(Field_MemReservation.Key())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) MemSwapLimitOwner() (string, bool) {
|
||||||
|
return f.simpleOwner(Field_MemSwapLimit.Key())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) MemKernelLimitOwner() (string, bool) {
|
||||||
|
return f.simpleOwner(Field_MemKernelLimit.Key())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) MemTCPLimitOwner() (string, bool) {
|
||||||
|
return f.simpleOwner(Field_MemTCPLimit.Key())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) MemSwappinessOwner() (string, bool) {
|
||||||
|
return f.simpleOwner(Field_MemSwappiness.Key())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) MemDisableOomKillerOwner() (string, bool) {
|
||||||
|
return f.simpleOwner(Field_MemDisableOomKiller.Key())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) MemUseHierarchyOwner() (string, bool) {
|
||||||
|
return f.simpleOwner(Field_MemUseHierarchy.Key())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) CPUSharesOwner() (string, bool) {
|
||||||
|
return f.simpleOwner(Field_CPUShares.Key())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) CPUQuotaOwner() (string, bool) {
|
||||||
|
return f.simpleOwner(Field_CPUQuota.Key())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) CPUPeriodOwner() (string, bool) {
|
||||||
|
return f.simpleOwner(Field_CPUPeriod.Key())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) CPURealtimeRuntimeOwner() (string, bool) {
|
||||||
|
return f.simpleOwner(Field_CPURealtimeRuntime.Key())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) CPURealtimePeriodOwner() (string, bool) {
|
||||||
|
return f.simpleOwner(Field_CPURealtimePeriod.Key())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) CPUSetCPUsOwner() (string, bool) {
|
||||||
|
return f.simpleOwner(Field_CPUSetCPUs.Key())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) CPUSetMemsOwner() (string, bool) {
|
||||||
|
return f.simpleOwner(Field_CPUSetMems.Key())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) PidsLimitOwner() (string, bool) {
|
||||||
|
return f.simpleOwner(Field_PidsLimit.Key())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) HugepageLimitOwner(size string) (string, bool) {
|
||||||
|
return f.compoundOwner(Field_HugepageLimits.Key(), size)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) BlockioClassOwner() (string, bool) {
|
||||||
|
return f.simpleOwner(Field_BlockioClass.Key())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) RdtClassOwner() (string, bool) {
|
||||||
|
return f.simpleOwner(Field_RdtClass.Key())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) CgroupsUnifiedOwner(key string) (string, bool) {
|
||||||
|
return f.compoundOwner(Field_CgroupsUnified.Key(), key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) CgroupsPathOwner() (string, bool) {
|
||||||
|
return f.simpleOwner(Field_CgroupsPath.Key())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) OomScoreAdjOwner() (string, bool) {
|
||||||
|
return f.simpleOwner(Field_OomScoreAdj.Key())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldOwners) RlimitOwner(typ string) (string, bool) {
|
||||||
|
return f.compoundOwner(Field_Rlimits.Key(), typ)
|
||||||
|
}
|
||||||
|
|
||||||
|
func qualify(field int32, qualifiers ...string) string {
|
||||||
|
return Field(field).String() + " " + strings.Join(append([]string{}, qualifiers...), " ")
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCompoundFieldOwners() *CompoundFieldOwners {
|
||||||
|
return &CompoundFieldOwners{
|
||||||
|
Owners: make(map[string]string),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f Field) Key() int32 {
|
||||||
|
return int32(f)
|
||||||
|
}
|
||||||
58
vendor/github.com/containerd/nri/pkg/api/plugin.go
generated
vendored
Normal file
58
vendor/github.com/containerd/nri/pkg/api/plugin.go
generated
vendored
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
Copyright The containerd Authors.
|
||||||
|
|
||||||
|
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 api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// DefaultSocketPath is the default socket path for external plugins.
|
||||||
|
DefaultSocketPath = "/var/run/nri/nri.sock"
|
||||||
|
// PluginSocketEnvVar is used to inform plugins about pre-connected sockets.
|
||||||
|
PluginSocketEnvVar = "NRI_PLUGIN_SOCKET"
|
||||||
|
// PluginNameEnvVar is used to inform NRI-launched plugins about their name.
|
||||||
|
PluginNameEnvVar = "NRI_PLUGIN_NAME"
|
||||||
|
// PluginIdxEnvVar is used to inform NRI-launched plugins about their ID.
|
||||||
|
PluginIdxEnvVar = "NRI_PLUGIN_IDX"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ParsePluginName parses the (file)name of a plugin into an index and a base.
|
||||||
|
func ParsePluginName(name string) (string, string, error) {
|
||||||
|
split := strings.SplitN(name, "-", 2)
|
||||||
|
if len(split) < 2 {
|
||||||
|
return "", "", fmt.Errorf("invalid plugin name %q, idx-pluginname expected", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := CheckPluginIndex(split[0]); err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return split[0], split[1], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckPluginIndex checks the validity of a plugin index.
|
||||||
|
func CheckPluginIndex(idx string) error {
|
||||||
|
if len(idx) != 2 {
|
||||||
|
return fmt.Errorf("invalid plugin index %q, must be 2 digits", idx)
|
||||||
|
}
|
||||||
|
if !('0' <= idx[0] && idx[0] <= '9') || !('0' <= idx[1] && idx[1] <= '9') {
|
||||||
|
return fmt.Errorf("invalid plugin index %q (not [0-9][0-9])", idx)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
203
vendor/github.com/containerd/nri/pkg/api/resources.go
generated
vendored
Normal file
203
vendor/github.com/containerd/nri/pkg/api/resources.go
generated
vendored
Normal file
@@ -0,0 +1,203 @@
|
|||||||
|
//go:build !tinygo.wasm
|
||||||
|
|
||||||
|
/*
|
||||||
|
Copyright The containerd Authors.
|
||||||
|
|
||||||
|
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 api
|
||||||
|
|
||||||
|
import (
|
||||||
|
rspec "github.com/opencontainers/runtime-spec/specs-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
// FromOCILinuxResources returns resources from an OCI runtime Spec.
|
||||||
|
func FromOCILinuxResources(o *rspec.LinuxResources, _ map[string]string) *LinuxResources {
|
||||||
|
if o == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
l := &LinuxResources{}
|
||||||
|
if m := o.Memory; m != nil {
|
||||||
|
l.Memory = &LinuxMemory{
|
||||||
|
Limit: Int64(m.Limit),
|
||||||
|
Reservation: Int64(m.Reservation),
|
||||||
|
Swap: Int64(m.Swap),
|
||||||
|
Kernel: Int64(m.Kernel),
|
||||||
|
KernelTcp: Int64(m.KernelTCP),
|
||||||
|
Swappiness: UInt64(m.Swappiness),
|
||||||
|
DisableOomKiller: Bool(m.DisableOOMKiller),
|
||||||
|
UseHierarchy: Bool(m.UseHierarchy),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if c := o.CPU; c != nil {
|
||||||
|
l.Cpu = &LinuxCPU{
|
||||||
|
Shares: UInt64(c.Shares),
|
||||||
|
Quota: Int64(c.Quota),
|
||||||
|
Period: UInt64(c.Period),
|
||||||
|
RealtimeRuntime: Int64(c.RealtimeRuntime),
|
||||||
|
RealtimePeriod: UInt64(c.RealtimePeriod),
|
||||||
|
Cpus: c.Cpus,
|
||||||
|
Mems: c.Mems,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, h := range o.HugepageLimits {
|
||||||
|
l.HugepageLimits = append(l.HugepageLimits, &HugepageLimit{
|
||||||
|
PageSize: h.Pagesize,
|
||||||
|
Limit: h.Limit,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
for _, d := range o.Devices {
|
||||||
|
l.Devices = append(l.Devices, &LinuxDeviceCgroup{
|
||||||
|
Allow: d.Allow,
|
||||||
|
Type: d.Type,
|
||||||
|
Major: Int64(d.Major),
|
||||||
|
Minor: Int64(d.Minor),
|
||||||
|
Access: d.Access,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if p := o.Pids; p != nil {
|
||||||
|
l.Pids = &LinuxPids{
|
||||||
|
Limit: p.Limit,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(o.Unified) != 0 {
|
||||||
|
l.Unified = make(map[string]string)
|
||||||
|
for k, v := range o.Unified {
|
||||||
|
l.Unified[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToOCI returns resources for an OCI runtime Spec.
|
||||||
|
func (r *LinuxResources) ToOCI() *rspec.LinuxResources {
|
||||||
|
if r == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
o := &rspec.LinuxResources{
|
||||||
|
CPU: &rspec.LinuxCPU{},
|
||||||
|
Memory: &rspec.LinuxMemory{},
|
||||||
|
}
|
||||||
|
if r.Memory != nil {
|
||||||
|
o.Memory = &rspec.LinuxMemory{
|
||||||
|
Limit: r.Memory.Limit.Get(),
|
||||||
|
Reservation: r.Memory.Reservation.Get(),
|
||||||
|
Swap: r.Memory.Swap.Get(),
|
||||||
|
Kernel: r.Memory.Kernel.Get(),
|
||||||
|
KernelTCP: r.Memory.KernelTcp.Get(),
|
||||||
|
Swappiness: r.Memory.Swappiness.Get(),
|
||||||
|
DisableOOMKiller: r.Memory.DisableOomKiller.Get(),
|
||||||
|
UseHierarchy: r.Memory.UseHierarchy.Get(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if r.Cpu != nil {
|
||||||
|
o.CPU = &rspec.LinuxCPU{
|
||||||
|
Shares: r.Cpu.Shares.Get(),
|
||||||
|
Quota: r.Cpu.Quota.Get(),
|
||||||
|
Period: r.Cpu.Period.Get(),
|
||||||
|
RealtimeRuntime: r.Cpu.RealtimeRuntime.Get(),
|
||||||
|
RealtimePeriod: r.Cpu.RealtimePeriod.Get(),
|
||||||
|
Cpus: r.Cpu.Cpus,
|
||||||
|
Mems: r.Cpu.Mems,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, l := range r.HugepageLimits {
|
||||||
|
o.HugepageLimits = append(o.HugepageLimits, rspec.LinuxHugepageLimit{
|
||||||
|
Pagesize: l.PageSize,
|
||||||
|
Limit: l.Limit,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if len(r.Unified) != 0 {
|
||||||
|
o.Unified = make(map[string]string)
|
||||||
|
for k, v := range r.Unified {
|
||||||
|
o.Unified[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, d := range r.Devices {
|
||||||
|
o.Devices = append(o.Devices, rspec.LinuxDeviceCgroup{
|
||||||
|
Allow: d.Allow,
|
||||||
|
Type: d.Type,
|
||||||
|
Major: d.Major.Get(),
|
||||||
|
Minor: d.Minor.Get(),
|
||||||
|
Access: d.Access,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if r.Pids != nil {
|
||||||
|
o.Pids = &rspec.LinuxPids{
|
||||||
|
Limit: r.Pids.Limit,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy creates a copy of the resources.
|
||||||
|
func (r *LinuxResources) Copy() *LinuxResources {
|
||||||
|
if r == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
o := &LinuxResources{}
|
||||||
|
if r.Memory != nil {
|
||||||
|
o.Memory = &LinuxMemory{
|
||||||
|
Limit: Int64(r.Memory.GetLimit()),
|
||||||
|
Reservation: Int64(r.Memory.GetReservation()),
|
||||||
|
Swap: Int64(r.Memory.GetSwap()),
|
||||||
|
Kernel: Int64(r.Memory.GetKernel()),
|
||||||
|
KernelTcp: Int64(r.Memory.GetKernelTcp()),
|
||||||
|
Swappiness: UInt64(r.Memory.GetSwappiness()),
|
||||||
|
DisableOomKiller: Bool(r.Memory.GetDisableOomKiller()),
|
||||||
|
UseHierarchy: Bool(r.Memory.GetUseHierarchy()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if r.Cpu != nil {
|
||||||
|
o.Cpu = &LinuxCPU{
|
||||||
|
Shares: UInt64(r.Cpu.GetShares()),
|
||||||
|
Quota: Int64(r.Cpu.GetQuota()),
|
||||||
|
Period: UInt64(r.Cpu.GetPeriod()),
|
||||||
|
RealtimeRuntime: Int64(r.Cpu.GetRealtimeRuntime()),
|
||||||
|
RealtimePeriod: UInt64(r.Cpu.GetRealtimePeriod()),
|
||||||
|
Cpus: r.Cpu.GetCpus(),
|
||||||
|
Mems: r.Cpu.GetMems(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, l := range r.HugepageLimits {
|
||||||
|
o.HugepageLimits = append(o.HugepageLimits, &HugepageLimit{
|
||||||
|
PageSize: l.PageSize,
|
||||||
|
Limit: l.Limit,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if len(r.Unified) != 0 {
|
||||||
|
o.Unified = make(map[string]string)
|
||||||
|
for k, v := range r.Unified {
|
||||||
|
o.Unified[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if r.Pids != nil {
|
||||||
|
o.Pids = &LinuxPids{
|
||||||
|
Limit: r.Pids.Limit,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
o.BlockioClass = String(r.BlockioClass)
|
||||||
|
o.RdtClass = String(r.RdtClass)
|
||||||
|
for _, d := range r.Devices {
|
||||||
|
o.Devices = append(o.Devices, &LinuxDeviceCgroup{
|
||||||
|
Allow: d.Allow,
|
||||||
|
Type: d.Type,
|
||||||
|
Access: d.Access,
|
||||||
|
Major: Int64(d.Major),
|
||||||
|
Minor: Int64(d.Minor),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return o
|
||||||
|
}
|
||||||
119
vendor/github.com/containerd/nri/pkg/api/seccomp.go
generated
vendored
Normal file
119
vendor/github.com/containerd/nri/pkg/api/seccomp.go
generated
vendored
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
/*
|
||||||
|
Copyright The containerd Authors.
|
||||||
|
|
||||||
|
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 api
|
||||||
|
|
||||||
|
import (
|
||||||
|
rspec "github.com/opencontainers/runtime-spec/specs-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
func FromOCILinuxSeccomp(o *rspec.LinuxSeccomp) *LinuxSeccomp {
|
||||||
|
var errno *OptionalUInt32
|
||||||
|
if o.DefaultErrnoRet != nil {
|
||||||
|
errno = &OptionalUInt32{Value: uint32(*o.DefaultErrnoRet)}
|
||||||
|
}
|
||||||
|
|
||||||
|
arches := make([]string, len(o.Architectures))
|
||||||
|
for i, arch := range o.Architectures {
|
||||||
|
arches[i] = string(arch)
|
||||||
|
}
|
||||||
|
|
||||||
|
flags := make([]string, len(o.Flags))
|
||||||
|
for i, flag := range o.Flags {
|
||||||
|
flags[i] = string(flag)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &LinuxSeccomp{
|
||||||
|
DefaultAction: string(o.DefaultAction),
|
||||||
|
DefaultErrno: errno,
|
||||||
|
Architectures: arches,
|
||||||
|
Flags: flags,
|
||||||
|
ListenerPath: o.ListenerPath,
|
||||||
|
ListenerMetadata: o.ListenerMetadata,
|
||||||
|
Syscalls: FromOCILinuxSyscalls(o.Syscalls),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func FromOCILinuxSyscalls(o []rspec.LinuxSyscall) []*LinuxSyscall {
|
||||||
|
syscalls := make([]*LinuxSyscall, len(o))
|
||||||
|
|
||||||
|
for i, syscall := range o {
|
||||||
|
var errno *OptionalUInt32
|
||||||
|
if syscall.ErrnoRet != nil {
|
||||||
|
errno = &OptionalUInt32{Value: uint32(*syscall.ErrnoRet)}
|
||||||
|
}
|
||||||
|
|
||||||
|
syscalls[i] = &LinuxSyscall{
|
||||||
|
Names: syscall.Names,
|
||||||
|
Action: string(syscall.Action),
|
||||||
|
ErrnoRet: errno,
|
||||||
|
Args: FromOCILinuxSeccompArgs(syscall.Args),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return syscalls
|
||||||
|
}
|
||||||
|
|
||||||
|
func FromOCILinuxSeccompArgs(o []rspec.LinuxSeccompArg) []*LinuxSeccompArg {
|
||||||
|
args := make([]*LinuxSeccompArg, len(o))
|
||||||
|
|
||||||
|
for i, arg := range o {
|
||||||
|
args[i] = &LinuxSeccompArg{
|
||||||
|
Index: uint32(arg.Index),
|
||||||
|
Value: arg.Value,
|
||||||
|
ValueTwo: arg.ValueTwo,
|
||||||
|
Op: string(arg.Op),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return args
|
||||||
|
}
|
||||||
|
|
||||||
|
func ToOCILinuxSyscalls(o []*LinuxSyscall) []rspec.LinuxSyscall {
|
||||||
|
syscalls := make([]rspec.LinuxSyscall, len(o))
|
||||||
|
|
||||||
|
for i, syscall := range o {
|
||||||
|
var errnoRet *uint
|
||||||
|
|
||||||
|
if syscall.ErrnoRet != nil {
|
||||||
|
*errnoRet = uint(syscall.ErrnoRet.Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
syscalls[i] = rspec.LinuxSyscall{
|
||||||
|
Names: syscall.Names,
|
||||||
|
Action: rspec.LinuxSeccompAction(syscall.Action),
|
||||||
|
ErrnoRet: errnoRet,
|
||||||
|
Args: ToOCILinuxSeccompArgs(syscall.Args),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return syscalls
|
||||||
|
}
|
||||||
|
|
||||||
|
func ToOCILinuxSeccompArgs(o []*LinuxSeccompArg) []rspec.LinuxSeccompArg {
|
||||||
|
args := make([]rspec.LinuxSeccompArg, len(o))
|
||||||
|
|
||||||
|
for i, arg := range o {
|
||||||
|
args[i] = rspec.LinuxSeccompArg{
|
||||||
|
Index: uint(arg.Index),
|
||||||
|
Value: arg.Value,
|
||||||
|
ValueTwo: arg.ValueTwo,
|
||||||
|
Op: rspec.LinuxSeccompOperator(arg.Op),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return args
|
||||||
|
}
|
||||||
343
vendor/github.com/containerd/nri/pkg/api/strip.go
generated
vendored
Normal file
343
vendor/github.com/containerd/nri/pkg/api/strip.go
generated
vendored
Normal file
@@ -0,0 +1,343 @@
|
|||||||
|
/*
|
||||||
|
Copyright The containerd Authors.
|
||||||
|
|
||||||
|
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 api
|
||||||
|
|
||||||
|
//
|
||||||
|
// Notes:
|
||||||
|
// These stripping functions are used in tests to compare values for
|
||||||
|
// semantic equality using go-cmp. They reduce their receiver to a
|
||||||
|
// unique canonical representation by replacing empty slices, maps,
|
||||||
|
// and struct type fields by nil. These are destructive (IOW might
|
||||||
|
// alter the receiver) and should only be used for testing.
|
||||||
|
//
|
||||||
|
// TODO(klihub):
|
||||||
|
// Starting with 1.36.6, we could use protobuf/proto.CloneOf() to
|
||||||
|
// create a deep copy before stripping. However, we can't update
|
||||||
|
// beyond 1.35.2 yet, before all supported release branches of our
|
||||||
|
// downstream dependencies have bumped their direct dependencies.
|
||||||
|
|
||||||
|
// Strip empty fields from a container adjustment, reducing a fully empty
|
||||||
|
// one to nil. Strip allows comparison of two adjustments for semantic
|
||||||
|
// equality using go-cmp.
|
||||||
|
func (a *ContainerAdjustment) Strip() *ContainerAdjustment {
|
||||||
|
if a == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
empty := true
|
||||||
|
|
||||||
|
if len(a.Annotations) == 0 {
|
||||||
|
a.Annotations = nil
|
||||||
|
} else {
|
||||||
|
empty = false
|
||||||
|
}
|
||||||
|
if len(a.Mounts) == 0 {
|
||||||
|
a.Mounts = nil
|
||||||
|
} else {
|
||||||
|
empty = false
|
||||||
|
}
|
||||||
|
if len(a.Env) == 0 {
|
||||||
|
a.Env = nil
|
||||||
|
} else {
|
||||||
|
empty = false
|
||||||
|
}
|
||||||
|
if len(a.Rlimits) == 0 {
|
||||||
|
a.Rlimits = nil
|
||||||
|
} else {
|
||||||
|
empty = false
|
||||||
|
}
|
||||||
|
if len(a.CDIDevices) == 0 {
|
||||||
|
a.CDIDevices = nil
|
||||||
|
} else {
|
||||||
|
empty = false
|
||||||
|
}
|
||||||
|
if len(a.Args) == 0 {
|
||||||
|
a.Args = nil
|
||||||
|
} else {
|
||||||
|
empty = false
|
||||||
|
}
|
||||||
|
|
||||||
|
if a.Hooks = a.Hooks.Strip(); a.Hooks != nil {
|
||||||
|
empty = false
|
||||||
|
}
|
||||||
|
if a.Linux = a.Linux.Strip(); a.Linux != nil {
|
||||||
|
empty = false
|
||||||
|
}
|
||||||
|
|
||||||
|
if empty {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
// Strip empty fields from a linux container adjustment, reducing a fully
|
||||||
|
// empty one to nil. Strip allows comparison of two adjustments for semantic
|
||||||
|
// equality using go-cmp.
|
||||||
|
func (l *LinuxContainerAdjustment) Strip() *LinuxContainerAdjustment {
|
||||||
|
if l == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
empty := true
|
||||||
|
|
||||||
|
if len(l.Devices) == 0 {
|
||||||
|
l.Devices = nil
|
||||||
|
} else {
|
||||||
|
empty = false
|
||||||
|
}
|
||||||
|
|
||||||
|
if l.Resources = l.Resources.Strip(); l.Resources != nil {
|
||||||
|
empty = false
|
||||||
|
}
|
||||||
|
|
||||||
|
if l.CgroupsPath != "" {
|
||||||
|
empty = false
|
||||||
|
}
|
||||||
|
if l.OomScoreAdj != nil {
|
||||||
|
empty = false
|
||||||
|
}
|
||||||
|
|
||||||
|
if empty {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
|
||||||
|
// Strip empty fields from Hooks, reducing a fully empty one to nil. Strip
|
||||||
|
// allows comparison of two Hooks for semantic equality using go-cmp.
|
||||||
|
func (h *Hooks) Strip() *Hooks {
|
||||||
|
if h == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
empty := true
|
||||||
|
|
||||||
|
if len(h.Prestart) == 0 {
|
||||||
|
h.Prestart = nil
|
||||||
|
} else {
|
||||||
|
empty = false
|
||||||
|
}
|
||||||
|
if len(h.CreateRuntime) == 0 {
|
||||||
|
h.CreateRuntime = nil
|
||||||
|
} else {
|
||||||
|
empty = false
|
||||||
|
}
|
||||||
|
if len(h.CreateContainer) == 0 {
|
||||||
|
h.CreateContainer = nil
|
||||||
|
} else {
|
||||||
|
empty = false
|
||||||
|
}
|
||||||
|
if len(h.StartContainer) == 0 {
|
||||||
|
h.StartContainer = nil
|
||||||
|
} else {
|
||||||
|
empty = false
|
||||||
|
}
|
||||||
|
if len(h.Poststart) == 0 {
|
||||||
|
h.Poststart = nil
|
||||||
|
} else {
|
||||||
|
empty = false
|
||||||
|
}
|
||||||
|
if len(h.Poststop) == 0 {
|
||||||
|
h.Poststop = nil
|
||||||
|
} else {
|
||||||
|
empty = false
|
||||||
|
}
|
||||||
|
|
||||||
|
if empty {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
|
||||||
|
// Strip empty fields from a linux resources, reducing a fully empty one
|
||||||
|
// to nil. Strip allows comparison of two sets of resources for semantic
|
||||||
|
// equality using go-cmp.
|
||||||
|
func (r *LinuxResources) Strip() *LinuxResources {
|
||||||
|
if r == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
empty := true
|
||||||
|
|
||||||
|
if r.Memory = r.Memory.Strip(); r.Memory != nil {
|
||||||
|
empty = false
|
||||||
|
}
|
||||||
|
if r.Cpu = r.Cpu.Strip(); r.Cpu != nil {
|
||||||
|
empty = false
|
||||||
|
}
|
||||||
|
if len(r.HugepageLimits) == 0 {
|
||||||
|
r.HugepageLimits = nil
|
||||||
|
} else {
|
||||||
|
empty = false
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.BlockioClass != nil {
|
||||||
|
empty = false
|
||||||
|
}
|
||||||
|
if r.RdtClass != nil {
|
||||||
|
empty = false
|
||||||
|
}
|
||||||
|
if len(r.Unified) == 0 {
|
||||||
|
r.Unified = nil
|
||||||
|
} else {
|
||||||
|
empty = false
|
||||||
|
}
|
||||||
|
if len(r.Devices) == 0 {
|
||||||
|
r.Devices = nil
|
||||||
|
} else {
|
||||||
|
empty = false
|
||||||
|
}
|
||||||
|
if r.Pids != nil {
|
||||||
|
empty = false
|
||||||
|
}
|
||||||
|
|
||||||
|
if empty {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
// Strip empty fields from linux CPU attributes, reducing a fully empty one
|
||||||
|
// to nil. Strip allows comparison of two sets of attributes for semantic
|
||||||
|
// equality using go-cmp.
|
||||||
|
func (c *LinuxCPU) Strip() *LinuxCPU {
|
||||||
|
if c == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
empty := true
|
||||||
|
|
||||||
|
if c.Shares != nil {
|
||||||
|
empty = false
|
||||||
|
}
|
||||||
|
if c.Quota != nil {
|
||||||
|
empty = false
|
||||||
|
}
|
||||||
|
if c.Period != nil {
|
||||||
|
empty = false
|
||||||
|
}
|
||||||
|
if c.RealtimeRuntime != nil {
|
||||||
|
empty = false
|
||||||
|
}
|
||||||
|
if c.RealtimePeriod != nil {
|
||||||
|
empty = false
|
||||||
|
}
|
||||||
|
if c.Cpus != "" {
|
||||||
|
empty = false
|
||||||
|
}
|
||||||
|
if c.Mems != "" {
|
||||||
|
empty = false
|
||||||
|
}
|
||||||
|
|
||||||
|
if empty {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// Strip empty fields from linux memory attributes, reducing a fully empty
|
||||||
|
// one to nil. Strip allows comparison of two sets of attributes for semantic
|
||||||
|
// equality using go-cmp.
|
||||||
|
func (m *LinuxMemory) Strip() *LinuxMemory {
|
||||||
|
if m == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
empty := true
|
||||||
|
|
||||||
|
if m.Limit != nil {
|
||||||
|
empty = false
|
||||||
|
}
|
||||||
|
if m.Reservation != nil {
|
||||||
|
empty = false
|
||||||
|
}
|
||||||
|
if m.Swap != nil {
|
||||||
|
empty = false
|
||||||
|
}
|
||||||
|
if m.Kernel != nil {
|
||||||
|
empty = false
|
||||||
|
}
|
||||||
|
if m.KernelTcp != nil {
|
||||||
|
empty = false
|
||||||
|
}
|
||||||
|
if m.Swappiness != nil {
|
||||||
|
empty = false
|
||||||
|
}
|
||||||
|
if m.DisableOomKiller != nil {
|
||||||
|
empty = false
|
||||||
|
}
|
||||||
|
if m.UseHierarchy != nil {
|
||||||
|
empty = false
|
||||||
|
}
|
||||||
|
|
||||||
|
if empty {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
// Strip empty fields from a container update, reducing a fully empty one
|
||||||
|
// to nil. Strip allows comparison of two updates for semantic equality
|
||||||
|
// using go-cmp.
|
||||||
|
func (u *ContainerUpdate) Strip() *ContainerUpdate {
|
||||||
|
if u == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
empty := true
|
||||||
|
|
||||||
|
if u.Linux = u.Linux.Strip(); u.Linux != nil {
|
||||||
|
empty = false
|
||||||
|
}
|
||||||
|
|
||||||
|
if u.IgnoreFailure {
|
||||||
|
empty = false
|
||||||
|
}
|
||||||
|
|
||||||
|
if empty {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return u
|
||||||
|
}
|
||||||
|
|
||||||
|
// Strip empty fields from a linux container update, reducing a fully empty
|
||||||
|
// one to nil. Strip allows comparison of two updates for semantic equality
|
||||||
|
// using go-cmp.
|
||||||
|
func (l *LinuxContainerUpdate) Strip() *LinuxContainerUpdate {
|
||||||
|
if l == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
empty := true
|
||||||
|
|
||||||
|
if l.Resources = l.Resources.Strip(); l.Resources != nil {
|
||||||
|
empty = false
|
||||||
|
}
|
||||||
|
|
||||||
|
if empty {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return l
|
||||||
|
}
|
||||||
28
vendor/github.com/containerd/nri/pkg/api/timeouts.go
generated
vendored
Normal file
28
vendor/github.com/containerd/nri/pkg/api/timeouts.go
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
Copyright The containerd Authors.
|
||||||
|
|
||||||
|
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 api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// DefaultPluginRegistrationTimeout is the default timeout for plugin registration.
|
||||||
|
DefaultPluginRegistrationTimeout = 5 * time.Second
|
||||||
|
// DefaultPluginRequestTimeout is the default timeout for plugins to handle a request.
|
||||||
|
DefaultPluginRequestTimeout = 2 * time.Second
|
||||||
|
)
|
||||||
199
vendor/github.com/containerd/nri/pkg/api/update.go
generated
vendored
Normal file
199
vendor/github.com/containerd/nri/pkg/api/update.go
generated
vendored
Normal file
@@ -0,0 +1,199 @@
|
|||||||
|
/*
|
||||||
|
Copyright The containerd Authors.
|
||||||
|
|
||||||
|
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 api
|
||||||
|
|
||||||
|
//nolint
|
||||||
|
// SetContainerId sets the id of the container to update.
|
||||||
|
func (u *ContainerUpdate) SetContainerId(id string) {
|
||||||
|
u.ContainerId = id
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLinuxMemoryLimit records setting the memory limit for a container.
|
||||||
|
func (u *ContainerUpdate) SetLinuxMemoryLimit(value int64) {
|
||||||
|
u.initLinuxResourcesMemory()
|
||||||
|
u.Linux.Resources.Memory.Limit = Int64(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLinuxMemoryReservation records setting the memory reservation for a container.
|
||||||
|
func (u *ContainerUpdate) SetLinuxMemoryReservation(value int64) {
|
||||||
|
u.initLinuxResourcesMemory()
|
||||||
|
u.Linux.Resources.Memory.Reservation = Int64(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLinuxMemorySwap records records setting the memory swap limit for a container.
|
||||||
|
func (u *ContainerUpdate) SetLinuxMemorySwap(value int64) {
|
||||||
|
u.initLinuxResourcesMemory()
|
||||||
|
u.Linux.Resources.Memory.Swap = Int64(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLinuxMemoryKernel records setting the memory kernel limit for a container.
|
||||||
|
func (u *ContainerUpdate) SetLinuxMemoryKernel(value int64) {
|
||||||
|
u.initLinuxResourcesMemory()
|
||||||
|
u.Linux.Resources.Memory.Kernel = Int64(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLinuxMemoryKernelTCP records setting the memory kernel TCP limit for a container.
|
||||||
|
func (u *ContainerUpdate) SetLinuxMemoryKernelTCP(value int64) {
|
||||||
|
u.initLinuxResourcesMemory()
|
||||||
|
u.Linux.Resources.Memory.KernelTcp = Int64(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLinuxMemorySwappiness records setting the memory swappiness for a container.
|
||||||
|
func (u *ContainerUpdate) SetLinuxMemorySwappiness(value uint64) {
|
||||||
|
u.initLinuxResourcesMemory()
|
||||||
|
u.Linux.Resources.Memory.Swappiness = UInt64(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLinuxMemoryDisableOomKiller records disabling the OOM killer for a container.
|
||||||
|
func (u *ContainerUpdate) SetLinuxMemoryDisableOomKiller() {
|
||||||
|
u.initLinuxResourcesMemory()
|
||||||
|
u.Linux.Resources.Memory.DisableOomKiller = Bool(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLinuxMemoryUseHierarchy records enabling hierarchical memory accounting for a container.
|
||||||
|
func (u *ContainerUpdate) SetLinuxMemoryUseHierarchy() {
|
||||||
|
u.initLinuxResourcesMemory()
|
||||||
|
u.Linux.Resources.Memory.UseHierarchy = Bool(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLinuxCPUShares records setting the scheduler's CPU shares for a container.
|
||||||
|
func (u *ContainerUpdate) SetLinuxCPUShares(value uint64) {
|
||||||
|
u.initLinuxResourcesCPU()
|
||||||
|
u.Linux.Resources.Cpu.Shares = UInt64(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLinuxCPUQuota records setting the scheduler's CPU quota for a container.
|
||||||
|
func (u *ContainerUpdate) SetLinuxCPUQuota(value int64) {
|
||||||
|
u.initLinuxResourcesCPU()
|
||||||
|
u.Linux.Resources.Cpu.Quota = Int64(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLinuxCPUPeriod records setting the scheduler's CPU period for a container.
|
||||||
|
func (u *ContainerUpdate) SetLinuxCPUPeriod(value int64) {
|
||||||
|
u.initLinuxResourcesCPU()
|
||||||
|
u.Linux.Resources.Cpu.Period = UInt64(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLinuxCPURealtimeRuntime records setting the scheduler's realtime runtime for a container.
|
||||||
|
func (u *ContainerUpdate) SetLinuxCPURealtimeRuntime(value int64) {
|
||||||
|
u.initLinuxResourcesCPU()
|
||||||
|
u.Linux.Resources.Cpu.RealtimeRuntime = Int64(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLinuxCPURealtimePeriod records setting the scheduler's realtime period for a container.
|
||||||
|
func (u *ContainerUpdate) SetLinuxCPURealtimePeriod(value uint64) {
|
||||||
|
u.initLinuxResourcesCPU()
|
||||||
|
u.Linux.Resources.Cpu.RealtimePeriod = UInt64(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLinuxCPUSetCPUs records setting the cpuset CPUs for a container.
|
||||||
|
func (u *ContainerUpdate) SetLinuxCPUSetCPUs(value string) {
|
||||||
|
u.initLinuxResourcesCPU()
|
||||||
|
u.Linux.Resources.Cpu.Cpus = value
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLinuxCPUSetMems records setting the cpuset memory for a container.
|
||||||
|
func (u *ContainerUpdate) SetLinuxCPUSetMems(value string) {
|
||||||
|
u.initLinuxResourcesCPU()
|
||||||
|
u.Linux.Resources.Cpu.Mems = value
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLinuxPidLimits records setting the pid max number for a container.
|
||||||
|
func (u *ContainerUpdate) SetLinuxPidLimits(value int64) {
|
||||||
|
u.initLinuxResourcesPids()
|
||||||
|
u.Linux.Resources.Pids.Limit = value
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddLinuxHugepageLimit records adding a hugepage limit for a container.
|
||||||
|
func (u *ContainerUpdate) AddLinuxHugepageLimit(pageSize string, value uint64) {
|
||||||
|
u.initLinuxResources()
|
||||||
|
u.Linux.Resources.HugepageLimits = append(u.Linux.Resources.HugepageLimits,
|
||||||
|
&HugepageLimit{
|
||||||
|
PageSize: pageSize,
|
||||||
|
Limit: value,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLinuxBlockIOClass records setting the Block I/O class for a container.
|
||||||
|
func (u *ContainerUpdate) SetLinuxBlockIOClass(value string) {
|
||||||
|
u.initLinuxResources()
|
||||||
|
u.Linux.Resources.BlockioClass = String(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLinuxRDTClass records setting the RDT class for a container.
|
||||||
|
func (u *ContainerUpdate) SetLinuxRDTClass(value string) {
|
||||||
|
u.initLinuxResources()
|
||||||
|
u.Linux.Resources.RdtClass = String(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddLinuxUnified sets a cgroupv2 unified resource.
|
||||||
|
func (u *ContainerUpdate) AddLinuxUnified(key, value string) {
|
||||||
|
u.initLinuxResourcesUnified()
|
||||||
|
u.Linux.Resources.Unified[key] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetIgnoreFailure marks an Update as ignored for failures.
|
||||||
|
// Such updates will not prevent the related container operation
|
||||||
|
// from succeeding if the update fails.
|
||||||
|
func (u *ContainerUpdate) SetIgnoreFailure() {
|
||||||
|
u.IgnoreFailure = true
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Initializing a container update.
|
||||||
|
//
|
||||||
|
|
||||||
|
func (u *ContainerUpdate) initLinux() {
|
||||||
|
if u.Linux == nil {
|
||||||
|
u.Linux = &LinuxContainerUpdate{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *ContainerUpdate) initLinuxResources() {
|
||||||
|
u.initLinux()
|
||||||
|
if u.Linux.Resources == nil {
|
||||||
|
u.Linux.Resources = &LinuxResources{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *ContainerUpdate) initLinuxResourcesMemory() {
|
||||||
|
u.initLinuxResources()
|
||||||
|
if u.Linux.Resources.Memory == nil {
|
||||||
|
u.Linux.Resources.Memory = &LinuxMemory{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *ContainerUpdate) initLinuxResourcesCPU() {
|
||||||
|
u.initLinuxResources()
|
||||||
|
if u.Linux.Resources.Cpu == nil {
|
||||||
|
u.Linux.Resources.Cpu = &LinuxCPU{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *ContainerUpdate) initLinuxResourcesUnified() {
|
||||||
|
u.initLinuxResources()
|
||||||
|
if u.Linux.Resources.Unified == nil {
|
||||||
|
u.Linux.Resources.Unified = make(map[string]string)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *ContainerUpdate) initLinuxResourcesPids() {
|
||||||
|
u.initLinuxResources()
|
||||||
|
if u.Linux.Resources.Pids == nil {
|
||||||
|
u.Linux.Resources.Pids = &LinuxPids{}
|
||||||
|
}
|
||||||
|
}
|
||||||
64
vendor/github.com/containerd/nri/pkg/api/validate.go
generated
vendored
Normal file
64
vendor/github.com/containerd/nri/pkg/api/validate.go
generated
vendored
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
Copyright The containerd Authors.
|
||||||
|
|
||||||
|
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 api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (v *ValidateContainerAdjustmentRequest) AddPlugin(name, index string) {
|
||||||
|
v.Plugins = append(v.Plugins, &PluginInstance{
|
||||||
|
Name: name,
|
||||||
|
Index: index,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *ValidateContainerAdjustmentRequest) AddResponse(rpl *CreateContainerResponse) {
|
||||||
|
v.Adjust = rpl.Adjust
|
||||||
|
v.Update = rpl.Update
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *ValidateContainerAdjustmentRequest) AddOwners(owners *OwningPlugins) {
|
||||||
|
v.Owners = owners
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *ValidateContainerAdjustmentResponse) ValidationResult(plugin string) error {
|
||||||
|
if !v.Reject {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
reason := v.Reason
|
||||||
|
if reason == "" {
|
||||||
|
reason = "unknown rejection reason"
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("validator %q rejected container adjustment, reason: %s", plugin, reason)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *ValidateContainerAdjustmentRequest) GetPluginMap() map[string]*PluginInstance {
|
||||||
|
if v == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
plugins := make(map[string]*PluginInstance)
|
||||||
|
for _, p := range v.Plugins {
|
||||||
|
plugins[p.Name] = &PluginInstance{Name: p.Name}
|
||||||
|
plugins[p.Index+"-"+p.Name] = p
|
||||||
|
}
|
||||||
|
|
||||||
|
return plugins
|
||||||
|
}
|
||||||
87
vendor/github.com/containerd/nri/pkg/log/log.go
generated
vendored
Normal file
87
vendor/github.com/containerd/nri/pkg/log/log.go
generated
vendored
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
/*
|
||||||
|
Copyright The containerd Authors.
|
||||||
|
|
||||||
|
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 log
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
log Logger = &fallbackLogger{}
|
||||||
|
)
|
||||||
|
|
||||||
|
// Logger is the interface NRI uses for logging.
|
||||||
|
type Logger interface {
|
||||||
|
Debugf(ctx context.Context, format string, args ...interface{})
|
||||||
|
Infof(ctx context.Context, format string, args ...interface{})
|
||||||
|
Warnf(ctx context.Context, format string, args ...interface{})
|
||||||
|
Errorf(ctx context.Context, format string, args ...interface{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the logger used by NRI.
|
||||||
|
func Set(l Logger) {
|
||||||
|
log = l
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the logger used by NRI.
|
||||||
|
func Get() Logger {
|
||||||
|
return log
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debugf logs a formatted debug message.
|
||||||
|
func Debugf(ctx context.Context, format string, args ...interface{}) {
|
||||||
|
log.Debugf(ctx, format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Infof logs a formatted informational message.
|
||||||
|
func Infof(ctx context.Context, format string, args ...interface{}) {
|
||||||
|
log.Infof(ctx, format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warnf logs a formatted warning message.
|
||||||
|
func Warnf(ctx context.Context, format string, args ...interface{}) {
|
||||||
|
log.Warnf(ctx, format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Errorf logs a formatted error message.
|
||||||
|
func Errorf(ctx context.Context, format string, args ...interface{}) {
|
||||||
|
log.Errorf(ctx, format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
type fallbackLogger struct{}
|
||||||
|
|
||||||
|
// Debugf logs a formatted debug message.
|
||||||
|
func (f *fallbackLogger) Debugf(ctx context.Context, format string, args ...interface{}) {
|
||||||
|
logrus.WithContext(ctx).Debugf(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Infof logs a formatted informational message.
|
||||||
|
func (f *fallbackLogger) Infof(ctx context.Context, format string, args ...interface{}) {
|
||||||
|
logrus.WithContext(ctx).Infof(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warnf logs a formatted warning message.
|
||||||
|
func (f *fallbackLogger) Warnf(ctx context.Context, format string, args ...interface{}) {
|
||||||
|
logrus.WithContext(ctx).Warnf(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Errorf logs a formatted error message.
|
||||||
|
func (f *fallbackLogger) Errorf(ctx context.Context, format string, args ...interface{}) {
|
||||||
|
logrus.WithContext(ctx).Errorf(format, args...)
|
||||||
|
}
|
||||||
93
vendor/github.com/containerd/nri/pkg/net/conn.go
generated
vendored
Normal file
93
vendor/github.com/containerd/nri/pkg/net/conn.go
generated
vendored
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
/*
|
||||||
|
Copyright The containerd Authors.
|
||||||
|
|
||||||
|
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 net
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewFdConn creates a net.Conn for the given (socket) fd.
|
||||||
|
func NewFdConn(fd int) (net.Conn, error) {
|
||||||
|
f := os.NewFile(uintptr(fd), "fd #"+strconv.Itoa(fd))
|
||||||
|
|
||||||
|
conn, err := net.FileConn(f)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create net.Conn for fd #%d: %w", fd, err)
|
||||||
|
}
|
||||||
|
f.Close()
|
||||||
|
|
||||||
|
return conn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// connListener wraps a pre-connected socket in a net.Listener.
|
||||||
|
type connListener struct {
|
||||||
|
next chan net.Conn
|
||||||
|
conn net.Conn
|
||||||
|
addr net.Addr
|
||||||
|
lock sync.RWMutex // for Close()
|
||||||
|
closed bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewConnListener wraps an existing net.Conn in a net.Listener.
|
||||||
|
//
|
||||||
|
// The first call to Accept() on the listener will return the wrapped
|
||||||
|
// connection. Subsequent calls to Accept() block until the listener
|
||||||
|
// is closed, then return io.EOF. Close() closes the listener and the
|
||||||
|
// wrapped connection.
|
||||||
|
func NewConnListener(conn net.Conn) net.Listener {
|
||||||
|
next := make(chan net.Conn, 1)
|
||||||
|
next <- conn
|
||||||
|
|
||||||
|
return &connListener{
|
||||||
|
next: next,
|
||||||
|
conn: conn,
|
||||||
|
addr: conn.LocalAddr(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Accept returns the wrapped connection when it is called the first
|
||||||
|
// time. Later calls to Accept block until the listener is closed, then
|
||||||
|
// return io.EOF.
|
||||||
|
func (l *connListener) Accept() (net.Conn, error) {
|
||||||
|
conn := <-l.next
|
||||||
|
if conn == nil {
|
||||||
|
return nil, io.EOF
|
||||||
|
}
|
||||||
|
return conn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close closes the listener and the wrapped connection.
|
||||||
|
func (l *connListener) Close() error {
|
||||||
|
l.lock.Lock()
|
||||||
|
defer l.lock.Unlock()
|
||||||
|
if l.closed {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
close(l.next)
|
||||||
|
l.closed = true
|
||||||
|
return l.conn.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Addr returns the local address of the wrapped connection.
|
||||||
|
func (l *connListener) Addr() net.Addr {
|
||||||
|
return l.addr
|
||||||
|
}
|
||||||
460
vendor/github.com/containerd/nri/pkg/net/multiplex/mux.go
generated
vendored
Normal file
460
vendor/github.com/containerd/nri/pkg/net/multiplex/mux.go
generated
vendored
Normal file
@@ -0,0 +1,460 @@
|
|||||||
|
/*
|
||||||
|
Copyright The containerd Authors.
|
||||||
|
|
||||||
|
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 multiplex
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"sync"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
nrinet "github.com/containerd/nri/pkg/net"
|
||||||
|
"github.com/containerd/ttrpc"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Mux multiplexes several logical connections over a single net.Conn.
|
||||||
|
//
|
||||||
|
// Connections are identified within a Mux by ConnIDs which are simple
|
||||||
|
// 32-bit unsigned integers. Opening a connection returns a net.Conn
|
||||||
|
// corrponding to the ConnID. This can then be used to write and read
|
||||||
|
// data through the connection with the Mux performing multiplexing
|
||||||
|
// and demultiplexing of data.
|
||||||
|
//
|
||||||
|
// Writing to a connection is fully synchronous. The caller can safely
|
||||||
|
// reuse the buffer once the call returns. Reading from a connection
|
||||||
|
// returns the oldest demultiplexed buffer for the connection, blocking
|
||||||
|
// if the connections incoming queue is empty. If any incoming queue is
|
||||||
|
// ever overflown the underlying trunk and all multiplexed connections
|
||||||
|
// are closed and an error is recorded. This error is later returned by
|
||||||
|
// any subsequent read from any connection. All connections of the Mux
|
||||||
|
// have the same fixed incoming queue length which can be configured
|
||||||
|
// using the WithReadQueueLength Option during Mux creation.
|
||||||
|
//
|
||||||
|
// The Mux interface also provides functions that emulate net.Dial and
|
||||||
|
// net.Listen for a connection. Usually these can be used for passing
|
||||||
|
// multiplexed connections to packages that insist to Dial or Accept
|
||||||
|
// themselves for connection establishment.
|
||||||
|
//
|
||||||
|
// Note that opening a connection is a virtual operation in the sense
|
||||||
|
// that it has no effects outside the Mux. It is performed without any
|
||||||
|
// signalling or other communication. It merely acquires the net.Conn
|
||||||
|
// corresponding to the connection and blindly assumes that the same
|
||||||
|
// ConnID is or will be opened at the other end of the Mux.
|
||||||
|
type Mux interface {
|
||||||
|
// Open the connection for the given ConnID.
|
||||||
|
Open(ConnID) (net.Conn, error)
|
||||||
|
|
||||||
|
// Close the Mux and all connections associated with it.
|
||||||
|
Close() error
|
||||||
|
|
||||||
|
// Dialer returns a net.Dial-like function for the connection.
|
||||||
|
//
|
||||||
|
// Calling the returned function (with arguments) will return a
|
||||||
|
// net.Conn for the connection.
|
||||||
|
Dialer(ConnID) func(string, string) (net.Conn, error)
|
||||||
|
|
||||||
|
// Listener returns a net.Listener for the connection. The first
|
||||||
|
// call to Accept() on the listener will return a net.Conn for the
|
||||||
|
// connection. Subsequent calls to Accept() will block until the
|
||||||
|
// connection is closed then return io.EOF.
|
||||||
|
Listen(ConnID) (net.Listener, error)
|
||||||
|
|
||||||
|
// Trunk returns the trunk connection for the Mux.
|
||||||
|
Trunk() net.Conn
|
||||||
|
|
||||||
|
// Unblock unblocks the Mux reader.
|
||||||
|
Unblock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConnID uniquely identifies a logical connection within a Mux.
|
||||||
|
type ConnID uint32
|
||||||
|
|
||||||
|
const (
|
||||||
|
// ConnID 0 is reserved for future use.
|
||||||
|
reservedConnID ConnID = iota
|
||||||
|
// LowestConnID is the lowest externally usable ConnID.
|
||||||
|
LowestConnID
|
||||||
|
)
|
||||||
|
|
||||||
|
// Option to apply to a Mux.
|
||||||
|
type Option func(*mux)
|
||||||
|
|
||||||
|
// WithBlockedRead causes the Mux to be blocked for reading until gets Unblock()'ed.
|
||||||
|
func WithBlockedRead() Option {
|
||||||
|
return func(m *mux) {
|
||||||
|
if m.blockC == nil {
|
||||||
|
m.blockC = make(chan struct{})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithReadQueueLength overrides the default read queue size.
|
||||||
|
func WithReadQueueLength(length int) Option {
|
||||||
|
return func(m *mux) {
|
||||||
|
m.qlen = length
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Multiplex returns a multiplexer for the given connection.
|
||||||
|
func Multiplex(trunk net.Conn, options ...Option) Mux {
|
||||||
|
return newMux(trunk, options...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// mux is our implementation of Mux.
|
||||||
|
type mux struct {
|
||||||
|
trunk net.Conn
|
||||||
|
writeLock sync.Mutex
|
||||||
|
conns map[ConnID]*conn
|
||||||
|
connLock sync.RWMutex
|
||||||
|
qlen int
|
||||||
|
errOnce sync.Once
|
||||||
|
err error
|
||||||
|
unblkOnce sync.Once
|
||||||
|
blockC chan struct{}
|
||||||
|
closeOnce sync.Once
|
||||||
|
doneC chan struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
// default read queue length for a single connection
|
||||||
|
readQueueLen = 256
|
||||||
|
// length of frame header: 4-byte ConnID, 4-byte payload length
|
||||||
|
headerLen = 8
|
||||||
|
// max. allowed payload size
|
||||||
|
maxPayloadSize = ttrpcMessageHeaderLength + ttrpcMessageLengthMax
|
||||||
|
)
|
||||||
|
|
||||||
|
// conn represents a single multiplexed connection.
|
||||||
|
type conn struct {
|
||||||
|
id ConnID
|
||||||
|
mux *mux
|
||||||
|
readC chan []byte
|
||||||
|
closeOnce sync.Once
|
||||||
|
doneC chan error
|
||||||
|
}
|
||||||
|
|
||||||
|
func newMux(trunk net.Conn, options ...Option) *mux {
|
||||||
|
m := &mux{
|
||||||
|
trunk: trunk,
|
||||||
|
conns: make(map[ConnID]*conn),
|
||||||
|
qlen: readQueueLen,
|
||||||
|
doneC: make(chan struct{}),
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, o := range options {
|
||||||
|
o(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.blockC == nil {
|
||||||
|
WithBlockedRead()(m)
|
||||||
|
m.Unblock()
|
||||||
|
}
|
||||||
|
|
||||||
|
go m.reader()
|
||||||
|
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mux) Trunk() net.Conn {
|
||||||
|
return m.trunk
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mux) Unblock() {
|
||||||
|
m.unblkOnce.Do(func() {
|
||||||
|
close(m.blockC)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mux) Open(id ConnID) (net.Conn, error) {
|
||||||
|
if id == reservedConnID {
|
||||||
|
return nil, fmt.Errorf("ConnID %d is reserved", id)
|
||||||
|
}
|
||||||
|
|
||||||
|
m.connLock.Lock()
|
||||||
|
defer m.connLock.Unlock()
|
||||||
|
|
||||||
|
c, ok := m.conns[id]
|
||||||
|
if !ok {
|
||||||
|
c = &conn{
|
||||||
|
id: id,
|
||||||
|
mux: m,
|
||||||
|
doneC: make(chan error, 1),
|
||||||
|
readC: make(chan []byte, m.qlen),
|
||||||
|
}
|
||||||
|
m.conns[id] = c
|
||||||
|
}
|
||||||
|
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mux) Close() error {
|
||||||
|
m.closeOnce.Do(func() {
|
||||||
|
m.connLock.Lock()
|
||||||
|
defer m.connLock.Unlock()
|
||||||
|
for _, conn := range m.conns {
|
||||||
|
conn.close()
|
||||||
|
}
|
||||||
|
close(m.doneC)
|
||||||
|
m.trunk.Close()
|
||||||
|
})
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mux) Dialer(id ConnID) func(string, string) (net.Conn, error) {
|
||||||
|
return func(string, string) (net.Conn, error) {
|
||||||
|
return m.Open(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mux) Listen(id ConnID) (net.Listener, error) {
|
||||||
|
conn, err := m.Open(id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return nrinet.NewConnListener(conn), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mux) write(id ConnID, buf []byte) (int, error) {
|
||||||
|
var (
|
||||||
|
hdr [headerLen]byte
|
||||||
|
data = buf[:]
|
||||||
|
size = len(data)
|
||||||
|
)
|
||||||
|
|
||||||
|
m.writeLock.Lock()
|
||||||
|
defer m.writeLock.Unlock()
|
||||||
|
|
||||||
|
for {
|
||||||
|
if size > maxPayloadSize {
|
||||||
|
size = maxPayloadSize
|
||||||
|
}
|
||||||
|
|
||||||
|
binary.BigEndian.PutUint32(hdr[0:4], uint32(id))
|
||||||
|
binary.BigEndian.PutUint32(hdr[4:8], uint32(size))
|
||||||
|
|
||||||
|
n, err := m.trunk.Write(hdr[:])
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("failed to write header to trunk: %w", err)
|
||||||
|
if n != 0 {
|
||||||
|
m.setError(err)
|
||||||
|
m.Close()
|
||||||
|
}
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
n, err = m.trunk.Write(data[:size])
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("failed to write payload to trunk: %w", err)
|
||||||
|
if n != 0 {
|
||||||
|
m.setError(err)
|
||||||
|
m.Close()
|
||||||
|
}
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
data = data[size:]
|
||||||
|
if size > len(data) {
|
||||||
|
size = len(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
if size == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return len(buf), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mux) reader() {
|
||||||
|
var (
|
||||||
|
hdr [headerLen]byte
|
||||||
|
cid uint32
|
||||||
|
cnt uint32
|
||||||
|
buf []byte
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
|
||||||
|
<-m.blockC
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-m.doneC:
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = io.ReadFull(m.trunk, hdr[:])
|
||||||
|
if err != nil {
|
||||||
|
switch {
|
||||||
|
case errors.Is(err, io.EOF):
|
||||||
|
case errors.Is(err, ttrpc.ErrClosed):
|
||||||
|
err = io.EOF
|
||||||
|
case errors.Is(err, ttrpc.ErrServerClosed):
|
||||||
|
err = io.EOF
|
||||||
|
case errors.Is(err, net.ErrClosed):
|
||||||
|
err = io.EOF
|
||||||
|
default:
|
||||||
|
err = fmt.Errorf("failed to read header from trunk: %w", err)
|
||||||
|
}
|
||||||
|
m.setError(err)
|
||||||
|
m.Close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cid = binary.BigEndian.Uint32(hdr[0:4])
|
||||||
|
cnt = binary.BigEndian.Uint32(hdr[4:8])
|
||||||
|
buf = make([]byte, int(cnt))
|
||||||
|
|
||||||
|
_, err = io.ReadFull(m.trunk, buf)
|
||||||
|
if err != nil {
|
||||||
|
switch {
|
||||||
|
case errors.Is(err, io.EOF):
|
||||||
|
case errors.Is(err, ttrpc.ErrClosed):
|
||||||
|
err = io.EOF
|
||||||
|
case errors.Is(err, ttrpc.ErrServerClosed):
|
||||||
|
err = io.EOF
|
||||||
|
case errors.Is(err, net.ErrClosed):
|
||||||
|
err = io.EOF
|
||||||
|
default:
|
||||||
|
err = fmt.Errorf("failed to read payload from trunk: %w", err)
|
||||||
|
}
|
||||||
|
m.setError(err)
|
||||||
|
m.Close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
m.connLock.RLock()
|
||||||
|
conn, ok := m.conns[ConnID(cid)]
|
||||||
|
m.connLock.RUnlock()
|
||||||
|
if ok {
|
||||||
|
select {
|
||||||
|
case conn.readC <- buf:
|
||||||
|
default:
|
||||||
|
m.setError(errors.New("failed to queue payload for reading"))
|
||||||
|
m.Close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mux) setError(err error) {
|
||||||
|
m.errOnce.Do(func() {
|
||||||
|
m.err = err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// nolint
|
||||||
|
func (m *mux) error() error {
|
||||||
|
m.errOnce.Do(func() {
|
||||||
|
if m.err == nil {
|
||||||
|
m.err = io.EOF
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return m.err
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// multiplexed connections
|
||||||
|
//
|
||||||
|
|
||||||
|
// Reads reads the next message from the multiplexed connection.
|
||||||
|
func (c *conn) Read(buf []byte) (int, error) {
|
||||||
|
var (
|
||||||
|
msg []byte
|
||||||
|
err error
|
||||||
|
ok bool
|
||||||
|
)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case err, ok = <-c.doneC:
|
||||||
|
if !ok || err == nil {
|
||||||
|
err = c.mux.error()
|
||||||
|
}
|
||||||
|
return 0, err
|
||||||
|
case msg, ok = <-c.readC:
|
||||||
|
if !ok {
|
||||||
|
return 0, c.mux.error()
|
||||||
|
}
|
||||||
|
if cap(buf) < len(msg) {
|
||||||
|
return 0, syscall.ENOMEM
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
copy(buf, msg)
|
||||||
|
return len(msg), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write writes the given data to the multiplexed connection.
|
||||||
|
func (c *conn) Write(b []byte) (int, error) {
|
||||||
|
select {
|
||||||
|
case err := <-c.doneC:
|
||||||
|
if err == nil {
|
||||||
|
err = io.EOF
|
||||||
|
}
|
||||||
|
return 0, err
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
return c.mux.write(c.id, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close closes the multiplexed connection.
|
||||||
|
func (c *conn) Close() error {
|
||||||
|
c.mux.connLock.Lock()
|
||||||
|
defer c.mux.connLock.Unlock()
|
||||||
|
if c.mux.conns[c.id] == c {
|
||||||
|
delete(c.mux.conns, c.id)
|
||||||
|
}
|
||||||
|
return c.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *conn) close() error {
|
||||||
|
c.closeOnce.Do(func() {
|
||||||
|
close(c.doneC)
|
||||||
|
})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// LocalAddr is the unimplemented stub for the corresponding net.Conn function.
|
||||||
|
func (c *conn) LocalAddr() net.Addr {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoteAddr is the unimplemented stub for the corresponding net.Conn function.
|
||||||
|
func (c *conn) RemoteAddr() net.Addr {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetDeadline is the unimplemented stub for the corresponding net.Conn function.
|
||||||
|
func (c *conn) SetDeadline(_ time.Time) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetReadDeadline is the unimplemented stub for the corresponding net.Conn function.
|
||||||
|
func (c *conn) SetReadDeadline(_ time.Time) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetWriteDeadline is the unimplemented stub for the corresponding net.Conn function.
|
||||||
|
func (c *conn) SetWriteDeadline(_ time.Time) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
29
vendor/github.com/containerd/nri/pkg/net/multiplex/ttrpc.go
generated
vendored
Normal file
29
vendor/github.com/containerd/nri/pkg/net/multiplex/ttrpc.go
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
Copyright The containerd Authors.
|
||||||
|
|
||||||
|
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 multiplex
|
||||||
|
|
||||||
|
const (
|
||||||
|
// PluginServiceConn is the mux connection ID for NRI plugin services.
|
||||||
|
PluginServiceConn ConnID = iota + 1
|
||||||
|
// RuntimeServiceConn is the mux connection ID for NRI runtime services.
|
||||||
|
RuntimeServiceConn
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
ttrpcMessageHeaderLength = 10
|
||||||
|
ttrpcMessageLengthMax = 4 << 20
|
||||||
|
)
|
||||||
93
vendor/github.com/containerd/nri/pkg/net/socketpair.go
generated
vendored
Normal file
93
vendor/github.com/containerd/nri/pkg/net/socketpair.go
generated
vendored
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
/*
|
||||||
|
Copyright The containerd Authors.
|
||||||
|
|
||||||
|
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 net
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SocketPair contains the os.File of a connected pair of sockets.
|
||||||
|
type SocketPair struct {
|
||||||
|
local, peer *os.File
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSocketPair returns a connected pair of sockets.
|
||||||
|
func NewSocketPair() (SocketPair, error) {
|
||||||
|
fds, err := newSocketPairCLOEXEC()
|
||||||
|
if err != nil {
|
||||||
|
return SocketPair{nil, nil}, fmt.Errorf("failed to create socketpair: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
filename := fmt.Sprintf("socketpair-#%d:%d", fds[0], fds[1])
|
||||||
|
|
||||||
|
return SocketPair{
|
||||||
|
os.NewFile(uintptr(fds[0]), filename+"[0]"),
|
||||||
|
os.NewFile(uintptr(fds[1]), filename+"[1]"),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// LocalFile returns the local end of the socketpair as an *os.File.
|
||||||
|
func (sp SocketPair) LocalFile() *os.File {
|
||||||
|
return sp.local
|
||||||
|
}
|
||||||
|
|
||||||
|
// PeerFile returns the peer end of the socketpair as an *os.File.
|
||||||
|
func (sp SocketPair) PeerFile() *os.File {
|
||||||
|
return sp.peer
|
||||||
|
}
|
||||||
|
|
||||||
|
// LocalConn returns a net.Conn for the local end of the socketpair.
|
||||||
|
// This closes LocalFile().
|
||||||
|
func (sp SocketPair) LocalConn() (net.Conn, error) {
|
||||||
|
file := sp.LocalFile()
|
||||||
|
defer file.Close()
|
||||||
|
conn, err := net.FileConn(file)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create net.Conn for %s: %w", file.Name(), err)
|
||||||
|
}
|
||||||
|
return conn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// PeerConn returns a net.Conn for the peer end of the socketpair.
|
||||||
|
// This closes PeerFile().
|
||||||
|
func (sp SocketPair) PeerConn() (net.Conn, error) {
|
||||||
|
file := sp.PeerFile()
|
||||||
|
defer file.Close()
|
||||||
|
conn, err := net.FileConn(file)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create net.Conn for %s: %w", file.Name(), err)
|
||||||
|
}
|
||||||
|
return conn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close closes both ends of the socketpair.
|
||||||
|
func (sp SocketPair) Close() {
|
||||||
|
sp.LocalClose()
|
||||||
|
sp.PeerClose()
|
||||||
|
}
|
||||||
|
|
||||||
|
// LocalClose closes the local end of the socketpair.
|
||||||
|
func (sp SocketPair) LocalClose() {
|
||||||
|
sp.local.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// PeerClose closes the peer end of the socketpair.
|
||||||
|
func (sp SocketPair) PeerClose() {
|
||||||
|
sp.peer.Close()
|
||||||
|
}
|
||||||
27
vendor/github.com/containerd/nri/pkg/net/socketpair_cloexec_linux.go
generated
vendored
Normal file
27
vendor/github.com/containerd/nri/pkg/net/socketpair_cloexec_linux.go
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
//go:build linux
|
||||||
|
|
||||||
|
/*
|
||||||
|
Copyright The containerd Authors.
|
||||||
|
|
||||||
|
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 net
|
||||||
|
|
||||||
|
import (
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
func newSocketPairCLOEXEC() ([2]int, error) {
|
||||||
|
return unix.Socketpair(unix.AF_UNIX, unix.SOCK_STREAM|unix.SOCK_CLOEXEC, 0)
|
||||||
|
}
|
||||||
38
vendor/github.com/containerd/nri/pkg/net/socketpair_cloexec_unix.go
generated
vendored
Normal file
38
vendor/github.com/containerd/nri/pkg/net/socketpair_cloexec_unix.go
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
//go:build !linux && !windows
|
||||||
|
|
||||||
|
/*
|
||||||
|
Copyright The containerd Authors.
|
||||||
|
|
||||||
|
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 net
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
func newSocketPairCLOEXEC() ([2]int, error) {
|
||||||
|
syscall.ForkLock.RLock()
|
||||||
|
defer syscall.ForkLock.RUnlock()
|
||||||
|
fds, err := unix.Socketpair(unix.AF_UNIX, unix.SOCK_STREAM, 0)
|
||||||
|
if err != nil {
|
||||||
|
return fds, err
|
||||||
|
}
|
||||||
|
unix.CloseOnExec(fds[0])
|
||||||
|
unix.CloseOnExec(fds[1])
|
||||||
|
|
||||||
|
return fds, err
|
||||||
|
}
|
||||||
30
vendor/github.com/containerd/nri/pkg/net/socketpair_cloexec_windows.go
generated
vendored
Normal file
30
vendor/github.com/containerd/nri/pkg/net/socketpair_cloexec_windows.go
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
//go:build windows
|
||||||
|
|
||||||
|
/*
|
||||||
|
Copyright The containerd Authors.
|
||||||
|
|
||||||
|
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 net
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
sys "golang.org/x/sys/windows"
|
||||||
|
)
|
||||||
|
|
||||||
|
func newSocketPairCLOEXEC() ([2]sys.Handle, error) {
|
||||||
|
// when implementing do use WSA_FLAG_NO_HANDLE_INHERIT to avoid leaking FDs
|
||||||
|
return [2]sys.Handle{sys.InvalidHandle, sys.InvalidHandle}, errors.New("newSocketPairCLOEXEC unimplemented for windows")
|
||||||
|
}
|
||||||
59
vendor/github.com/containerd/nri/pkg/plugin/annotations.go
generated
vendored
Normal file
59
vendor/github.com/containerd/nri/pkg/plugin/annotations.go
generated
vendored
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
Copyright The containerd Authors.
|
||||||
|
|
||||||
|
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 plugin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/containerd/nri/pkg/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// AnnotationDomain is the domain used for NRI-specific annotations.
|
||||||
|
AnnotationDomain = "noderesource.dev"
|
||||||
|
|
||||||
|
// RequiredPluginsAnnotation can be used to annotate pods with a list
|
||||||
|
// of pod- or container-specific plugins which must process containers
|
||||||
|
// during creation. If enabled, the default validator checks for this
|
||||||
|
// and rejects the creation of containers which fail this check.
|
||||||
|
RequiredPluginsAnnotation = "required-plugins." + AnnotationDomain
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetEffectiveAnnotation retrieves a custom annotation from a pod which
|
||||||
|
// applies to given container. The syntax allows both pod- and container-
|
||||||
|
// scoped annotations. Container-scoped annotations take precedence over
|
||||||
|
// pod-scoped ones. The key syntax defines the scope of the annotation.
|
||||||
|
// - container-scope: <key>/container.<container-name>
|
||||||
|
// - pod-scope: <key>/pod, or just <key>
|
||||||
|
func GetEffectiveAnnotation(pod *api.PodSandbox, key, container string) (string, bool) {
|
||||||
|
annotations := pod.GetAnnotations()
|
||||||
|
if len(annotations) == 0 {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
keys := []string{
|
||||||
|
key + "/container." + container,
|
||||||
|
key + "/pod",
|
||||||
|
key,
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, k := range keys {
|
||||||
|
if v, ok := annotations[k]; ok {
|
||||||
|
return v, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
48
vendor/github.com/containerd/nri/plugins/default-validator/builtin/plugin.go
generated
vendored
Normal file
48
vendor/github.com/containerd/nri/plugins/default-validator/builtin/plugin.go
generated
vendored
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
Copyright The containerd Authors.
|
||||||
|
|
||||||
|
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 builtin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/containerd/nri/pkg/adaptation/builtin"
|
||||||
|
"github.com/containerd/nri/pkg/log"
|
||||||
|
|
||||||
|
validator "github.com/containerd/nri/plugins/default-validator"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
DefaultValidatorConfig = validator.DefaultValidatorConfig
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetDefaultValidator returns a configured instance of the default validator.
|
||||||
|
// If default validation is disabled nil is returned.
|
||||||
|
func GetDefaultValidator(cfg *DefaultValidatorConfig) *builtin.BuiltinPlugin {
|
||||||
|
if cfg == nil || !cfg.Enable {
|
||||||
|
log.Infof(context.TODO(), "built-in NRI default validator is disabled")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
v := validator.NewDefaultValidator(cfg)
|
||||||
|
return &builtin.BuiltinPlugin{
|
||||||
|
Base: "default-validator",
|
||||||
|
Index: "00",
|
||||||
|
Handlers: builtin.BuiltinHandlers{
|
||||||
|
ValidateContainerAdjustment: v.ValidateContainerAdjustment,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
258
vendor/github.com/containerd/nri/plugins/default-validator/default-validator.go
generated
vendored
Normal file
258
vendor/github.com/containerd/nri/plugins/default-validator/default-validator.go
generated
vendored
Normal file
@@ -0,0 +1,258 @@
|
|||||||
|
/*
|
||||||
|
Copyright The containerd Authors.
|
||||||
|
|
||||||
|
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 validator
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"slices"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/containerd/nri/pkg/api"
|
||||||
|
"github.com/containerd/nri/pkg/log"
|
||||||
|
"github.com/containerd/nri/pkg/plugin"
|
||||||
|
yaml "gopkg.in/yaml.v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DefaultValidatorConfig struct {
|
||||||
|
// Enable the default validator plugin.
|
||||||
|
Enable bool `yaml:"enable" toml:"enable"`
|
||||||
|
// RejectOCIHookAdjustment fails validation if OCI hooks are adjusted.
|
||||||
|
RejectOCIHookAdjustment bool `yaml:"rejectOCIHookAdjustment" toml:"reject_oci_hook_adjustment"`
|
||||||
|
// RejectRuntimeDefaultSeccompAdjustment fails validation if a runtime default seccomp
|
||||||
|
// policy is adjusted.
|
||||||
|
RejectRuntimeDefaultSeccompAdjustment bool `yaml:"rejectRuntimeDefaultSeccompAdjustment" toml:"reject_runtime_default_seccomp_adjustment"`
|
||||||
|
// RejectUnconfinedSeccompAdjustment fails validation if an unconfined seccomp policy is
|
||||||
|
// adjusted.
|
||||||
|
RejectUnconfinedSeccompAdjustment bool `yaml:"rejectUnconfinedSeccompAdjustment" toml:"reject_unconfined_seccomp_adjustment"`
|
||||||
|
// RejectCustomSeccompAdjustment fails validation if a custom seccomp policy (aka LOCALHOST)
|
||||||
|
// is adjusted.
|
||||||
|
RejectCustomSeccompAdjustment bool `yaml:"rejectCustomSeccompAdjustment" toml:"reject_custom_seccomp_adjustment"`
|
||||||
|
// RejectNamespaceAdjustment fails validation if any plugin adjusts Linux namespaces.
|
||||||
|
RejectNamespaceAdjustment bool `yaml:"rejectNamespaceAdjustment" toml:"reject_namespace_adjustment"`
|
||||||
|
// RequiredPlugins list globally required plugins. These must be present
|
||||||
|
// or otherwise validation will fail.
|
||||||
|
// WARNING: This is a global setting and will affect all containers. In
|
||||||
|
// particular, if you configure any globally required plugins, you should
|
||||||
|
// annotate your static pods to tolerate missing plugins. Failing to do
|
||||||
|
// so will prevent static pods from starting.
|
||||||
|
// Notes:
|
||||||
|
// Containers can be annotated to tolerate missing plugins using the
|
||||||
|
// toleration annotation, if one is set.
|
||||||
|
RequiredPlugins []string `yaml:"requiredPlugins" toml:"required_plugins"`
|
||||||
|
// TolerateMissingPlugins is an optional annotation key. If set, it can
|
||||||
|
// be used to annotate containers to tolerate missing required plugins.
|
||||||
|
TolerateMissingAnnotation string `yaml:"tolerateMissingPluginsAnnotation" toml:"tolerate_missing_plugins_annotation"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultValidator implements default validation.
|
||||||
|
type DefaultValidator struct {
|
||||||
|
cfg DefaultValidatorConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
// RequiredPlugins is the annotation key for extra required plugins.
|
||||||
|
RequiredPlugins = plugin.RequiredPluginsAnnotation
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// ErrValidation is returned if validation rejects an adjustment.
|
||||||
|
ErrValidation = errors.New("validation error")
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewDefaultValidator creates a new instance of the validator.
|
||||||
|
func NewDefaultValidator(cfg *DefaultValidatorConfig) *DefaultValidator {
|
||||||
|
return &DefaultValidator{cfg: *cfg}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetConfig sets new configuration for the validator.
|
||||||
|
func (v *DefaultValidator) SetConfig(cfg *DefaultValidatorConfig) {
|
||||||
|
if cfg == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
v.cfg = *cfg
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateContainerAdjustment validates a container adjustment.
|
||||||
|
func (v *DefaultValidator) ValidateContainerAdjustment(ctx context.Context, req *api.ValidateContainerAdjustmentRequest) error {
|
||||||
|
log.Debugf(ctx, "Validating adjustment of container %s/%s/%s",
|
||||||
|
req.GetPod().GetNamespace(), req.GetPod().GetName(), req.GetContainer().GetName())
|
||||||
|
|
||||||
|
if err := v.validateOCIHooks(req); err != nil {
|
||||||
|
log.Errorf(ctx, "rejecting adjustment: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := v.validateSeccompPolicy(req); err != nil {
|
||||||
|
log.Errorf(ctx, "rejecting adjustment: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := v.validateNamespaces(req); err != nil {
|
||||||
|
log.Errorf(ctx, "rejecting adjustment: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := v.validateRequiredPlugins(req); err != nil {
|
||||||
|
log.Errorf(ctx, "rejecting adjustment: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *DefaultValidator) validateOCIHooks(req *api.ValidateContainerAdjustmentRequest) error {
|
||||||
|
if req.Adjust == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if !v.cfg.RejectOCIHookAdjustment {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
owners, claimed := req.Owners.HooksOwner(req.Container.Id)
|
||||||
|
if !claimed {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
offender := ""
|
||||||
|
|
||||||
|
if !strings.Contains(owners, ",") {
|
||||||
|
offender = fmt.Sprintf("plugin %q", owners)
|
||||||
|
} else {
|
||||||
|
offender = fmt.Sprintf("plugins %q", owners)
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("%w: %s attempted restricted OCI hook injection", ErrValidation, offender)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *DefaultValidator) validateSeccompPolicy(req *api.ValidateContainerAdjustmentRequest) error {
|
||||||
|
if req.Adjust == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
owner, claimed := req.Owners.SeccompPolicyOwner(req.Container.Id)
|
||||||
|
if !claimed {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
profile := req.Container.GetLinux().GetSeccompProfile()
|
||||||
|
switch {
|
||||||
|
case profile == nil || profile.GetProfileType() == api.SecurityProfile_UNCONFINED:
|
||||||
|
if v.cfg.RejectUnconfinedSeccompAdjustment {
|
||||||
|
return fmt.Errorf("%w: plugin %s attempted restricted "+
|
||||||
|
" unconfined seccomp policy adjustment", ErrValidation, owner)
|
||||||
|
}
|
||||||
|
|
||||||
|
case profile.GetProfileType() == api.SecurityProfile_RUNTIME_DEFAULT:
|
||||||
|
if v.cfg.RejectRuntimeDefaultSeccompAdjustment {
|
||||||
|
return fmt.Errorf("%w: plugin %s attempted restricted "+
|
||||||
|
"runtime default seccomp policy adjustment", ErrValidation, owner)
|
||||||
|
}
|
||||||
|
|
||||||
|
case profile.GetProfileType() == api.SecurityProfile_LOCALHOST:
|
||||||
|
if v.cfg.RejectCustomSeccompAdjustment {
|
||||||
|
return fmt.Errorf("%w: plugin %s attempted restricted "+
|
||||||
|
" custom seccomp policy adjustment", ErrValidation, owner)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *DefaultValidator) validateNamespaces(req *api.ValidateContainerAdjustmentRequest) error {
|
||||||
|
if req.Adjust == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if !v.cfg.RejectNamespaceAdjustment {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
owners, claimed := req.Owners.NamespaceOwners(req.Container.Id)
|
||||||
|
if !claimed {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
offenders := "plugin(s) "
|
||||||
|
sep := ""
|
||||||
|
|
||||||
|
for ns, plugin := range owners {
|
||||||
|
offenders += sep + fmt.Sprintf("%q (namespace %q)", plugin, ns)
|
||||||
|
sep = ", "
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("%w: attempted restricted namespace adjustment by %s",
|
||||||
|
ErrValidation, offenders)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *DefaultValidator) validateRequiredPlugins(req *api.ValidateContainerAdjustmentRequest) error {
|
||||||
|
var (
|
||||||
|
container = req.GetContainer().GetName()
|
||||||
|
required = slices.Clone(v.cfg.RequiredPlugins)
|
||||||
|
)
|
||||||
|
|
||||||
|
if tolerateMissing := v.cfg.TolerateMissingAnnotation; tolerateMissing != "" {
|
||||||
|
value, ok := plugin.GetEffectiveAnnotation(req.GetPod(), tolerateMissing, container)
|
||||||
|
if ok {
|
||||||
|
tolerate, err := strconv.ParseBool(value)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("invalid %s annotation %q: %w", tolerateMissing, value, err)
|
||||||
|
}
|
||||||
|
if tolerate {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if value, ok := plugin.GetEffectiveAnnotation(req.GetPod(), RequiredPlugins, container); ok {
|
||||||
|
var annotated []string
|
||||||
|
if err := yaml.Unmarshal([]byte(value), &annotated); err != nil {
|
||||||
|
return fmt.Errorf("invalid %s annotation %q: %w", RequiredPlugins, value, err)
|
||||||
|
}
|
||||||
|
required = append(required, annotated...)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(required) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
plugins := req.GetPluginMap()
|
||||||
|
missing := []string{}
|
||||||
|
|
||||||
|
for _, r := range required {
|
||||||
|
if _, ok := plugins[r]; !ok {
|
||||||
|
missing = append(missing, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(missing) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
offender := ""
|
||||||
|
|
||||||
|
if len(missing) == 1 {
|
||||||
|
offender = fmt.Sprintf("required plugin %q", missing[0])
|
||||||
|
} else {
|
||||||
|
offender = fmt.Sprintf("required plugins %q", strings.Join(missing, ","))
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("%w: %s not present", ErrValidation, offender)
|
||||||
|
}
|
||||||
21
vendor/github.com/knqyf263/go-plugin/LICENSE
generated
vendored
Normal file
21
vendor/github.com/knqyf263/go-plugin/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2022 Teppei Fukuda
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
47
vendor/github.com/knqyf263/go-plugin/wasm/host.go
generated
vendored
Normal file
47
vendor/github.com/knqyf263/go-plugin/wasm/host.go
generated
vendored
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
//go:build !wasip1
|
||||||
|
|
||||||
|
// This file is designed to be imported by hosts.
|
||||||
|
|
||||||
|
package wasm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/tetratelabs/wazero/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ReadMemory(mem api.Memory, offset, size uint32) ([]byte, error) {
|
||||||
|
buf, ok := mem.Read(offset, size)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("Memory.Read(%d, %d) out of range", offset, size)
|
||||||
|
}
|
||||||
|
return buf, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func WriteMemory(ctx context.Context, m api.Module, data []byte) (uint64, error) {
|
||||||
|
malloc := m.ExportedFunction("malloc")
|
||||||
|
if malloc == nil {
|
||||||
|
return 0, errors.New("malloc is not exported")
|
||||||
|
}
|
||||||
|
|
||||||
|
l := uint64(len(data))
|
||||||
|
if l == 0 {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
results, err := malloc.Call(ctx, l)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
dataPtr := results[0]
|
||||||
|
|
||||||
|
// The pointer is a linear memory offset, which is where we write the name.
|
||||||
|
if !m.Memory().Write(uint32(dataPtr), data) {
|
||||||
|
return 0, fmt.Errorf("Memory.Write(%d, %d) out of range of memory size %d",
|
||||||
|
dataPtr, len(data), m.Memory().Size())
|
||||||
|
}
|
||||||
|
|
||||||
|
return dataPtr, nil
|
||||||
|
}
|
||||||
54
vendor/github.com/knqyf263/go-plugin/wasm/plugin.go
generated
vendored
Normal file
54
vendor/github.com/knqyf263/go-plugin/wasm/plugin.go
generated
vendored
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
//go:build wasip1 && !tinygo.wasm
|
||||||
|
|
||||||
|
// This file is designed to be imported by plugins.
|
||||||
|
|
||||||
|
package wasm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// allocations keeps track of each allocated byte slice, keyed by a fake pointer.
|
||||||
|
// This map ensures the GC will not collect these slices while still in use.
|
||||||
|
var allocations = make(map[uint32][]byte)
|
||||||
|
|
||||||
|
// allocate creates a new byte slice of the given size and stores it in the
|
||||||
|
// allocations map so that it remains valid (not garbage-collected).
|
||||||
|
func allocate(size uint32) uint32 {
|
||||||
|
if size == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
// Create a new byte slice on the Go heap
|
||||||
|
b := make([]byte, size)
|
||||||
|
|
||||||
|
// Obtain the 'address' of the first element in b by converting its pointer to a uint32.
|
||||||
|
ptr := uint32(uintptr(unsafe.Pointer(&b[0])))
|
||||||
|
|
||||||
|
// Store the byte slice in the map, keyed by the pointer
|
||||||
|
allocations[ptr] = b
|
||||||
|
return ptr
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:wasmexport malloc
|
||||||
|
func Malloc(size uint32) uint32 {
|
||||||
|
return allocate(size)
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:wasmexport free
|
||||||
|
func Free(ptr uint32) {
|
||||||
|
// Remove the slice from the allocations map so the GC can reclaim it later.
|
||||||
|
delete(allocations, ptr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func PtrToByte(ptr, size uint32) []byte {
|
||||||
|
return unsafe.Slice((*byte)(unsafe.Pointer(uintptr(ptr))), size)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ByteToPtr(buf []byte) (uint32, uint32) {
|
||||||
|
if len(buf) == 0 {
|
||||||
|
return 0, 0
|
||||||
|
}
|
||||||
|
ptr := &buf[0]
|
||||||
|
unsafePtr := uintptr(unsafe.Pointer(ptr))
|
||||||
|
return uint32(unsafePtr), uint32(len(buf))
|
||||||
|
}
|
||||||
35
vendor/github.com/knqyf263/go-plugin/wasm/plugin_tinygo.go
generated
vendored
Normal file
35
vendor/github.com/knqyf263/go-plugin/wasm/plugin_tinygo.go
generated
vendored
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
//go:build tinygo.wasm
|
||||||
|
|
||||||
|
// This file is designed to be imported by plugins.
|
||||||
|
|
||||||
|
package wasm
|
||||||
|
|
||||||
|
// #include <stdlib.h>
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
func PtrToByte(ptr, size uint32) []byte {
|
||||||
|
b := unsafe.Slice((*byte)(unsafe.Pointer(uintptr(ptr))), size)
|
||||||
|
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func ByteToPtr(buf []byte) (uint32, uint32) {
|
||||||
|
if len(buf) == 0 {
|
||||||
|
return 0, 0
|
||||||
|
}
|
||||||
|
|
||||||
|
size := C.ulong(len(buf))
|
||||||
|
ptr := unsafe.Pointer(C.malloc(size))
|
||||||
|
|
||||||
|
copy(unsafe.Slice((*byte)(ptr), size), buf)
|
||||||
|
|
||||||
|
return uint32(uintptr(ptr)), uint32(len(buf))
|
||||||
|
}
|
||||||
|
|
||||||
|
func Free(ptr uint32) {
|
||||||
|
C.free(unsafe.Pointer(uintptr(ptr)))
|
||||||
|
}
|
||||||
2
vendor/github.com/tetratelabs/wazero/.gitattributes
generated
vendored
Normal file
2
vendor/github.com/tetratelabs/wazero/.gitattributes
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# Improves experience of commands like `make format` on Windows
|
||||||
|
* text=auto eol=lf
|
||||||
46
vendor/github.com/tetratelabs/wazero/.gitignore
generated
vendored
Normal file
46
vendor/github.com/tetratelabs/wazero/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
# If you prefer the allow list template instead of the deny list, see community template:
|
||||||
|
# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
|
||||||
|
#
|
||||||
|
# Binaries for programs and plugins
|
||||||
|
*.exe
|
||||||
|
*.exe~
|
||||||
|
*.dll
|
||||||
|
*.so
|
||||||
|
*.dylib
|
||||||
|
/wazero
|
||||||
|
build
|
||||||
|
dist
|
||||||
|
|
||||||
|
# Test binary, built with `go test -c`
|
||||||
|
*.test
|
||||||
|
|
||||||
|
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||||
|
*.out
|
||||||
|
|
||||||
|
# Dependency directories (remove the comment below to include it)
|
||||||
|
# vendor/
|
||||||
|
|
||||||
|
# Go workspace file
|
||||||
|
go.work
|
||||||
|
|
||||||
|
# Goland
|
||||||
|
.idea
|
||||||
|
|
||||||
|
# AssemblyScript
|
||||||
|
node_modules
|
||||||
|
package-lock.json
|
||||||
|
|
||||||
|
# codecov.io
|
||||||
|
/coverage.txt
|
||||||
|
|
||||||
|
.vagrant
|
||||||
|
|
||||||
|
zig-cache/
|
||||||
|
.zig-cache/
|
||||||
|
zig-out/
|
||||||
|
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# Ignore compiled stdlib test cases.
|
||||||
|
/internal/integration_test/stdlibs/testdata
|
||||||
|
/internal/integration_test/libsodium/testdata
|
||||||
3
vendor/github.com/tetratelabs/wazero/.gitmodules
generated
vendored
Normal file
3
vendor/github.com/tetratelabs/wazero/.gitmodules
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
[submodule "site/themes/hello-friend"]
|
||||||
|
path = site/themes/hello-friend
|
||||||
|
url = https://github.com/panr/hugo-theme-hello-friend.git
|
||||||
75
vendor/github.com/tetratelabs/wazero/CONTRIBUTING.md
generated
vendored
Normal file
75
vendor/github.com/tetratelabs/wazero/CONTRIBUTING.md
generated
vendored
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
# Contributing
|
||||||
|
|
||||||
|
We welcome contributions from the community. Please read the following guidelines carefully to maximize the chances of your PR being merged.
|
||||||
|
|
||||||
|
## Coding Style
|
||||||
|
|
||||||
|
- To ensure your change passes format checks, run `make check`. To format your files, you can run `make format`.
|
||||||
|
- We follow standard Go table-driven tests and use an internal [testing library](./internal/testing/require) to assert correctness. To verify all tests pass, you can run `make test`.
|
||||||
|
|
||||||
|
## DCO
|
||||||
|
|
||||||
|
We require DCO signoff line in every commit to this repo.
|
||||||
|
|
||||||
|
The sign-off is a simple line at the end of the explanation for the
|
||||||
|
patch, which certifies that you wrote it or otherwise have the right to
|
||||||
|
pass it on as an open-source patch. The rules are pretty simple: if you
|
||||||
|
can certify the below (from
|
||||||
|
[developercertificate.org](https://developercertificate.org/)):
|
||||||
|
|
||||||
|
```
|
||||||
|
Developer Certificate of Origin
|
||||||
|
Version 1.1
|
||||||
|
Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
|
||||||
|
660 York Street, Suite 102,
|
||||||
|
San Francisco, CA 94110 USA
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies of this
|
||||||
|
license document, but changing it is not allowed.
|
||||||
|
Developer's Certificate of Origin 1.1
|
||||||
|
By making a contribution to this project, I certify that:
|
||||||
|
(a) The contribution was created in whole or in part by me and I
|
||||||
|
have the right to submit it under the open source license
|
||||||
|
indicated in the file; or
|
||||||
|
(b) The contribution is based upon previous work that, to the best
|
||||||
|
of my knowledge, is covered under an appropriate open source
|
||||||
|
license and I have the right under that license to submit that
|
||||||
|
work with modifications, whether created in whole or in part
|
||||||
|
by me, under the same open source license (unless I am
|
||||||
|
permitted to submit under a different license), as indicated
|
||||||
|
in the file; or
|
||||||
|
(c) The contribution was provided directly to me by some other
|
||||||
|
person who certified (a), (b) or (c) and I have not modified
|
||||||
|
it.
|
||||||
|
(d) I understand and agree that this project and the contribution
|
||||||
|
are public and that a record of the contribution (including all
|
||||||
|
personal information I submit with it, including my sign-off) is
|
||||||
|
maintained indefinitely and may be redistributed consistent with
|
||||||
|
this project or the open source license(s) involved.
|
||||||
|
```
|
||||||
|
|
||||||
|
then you just add a line to every git commit message:
|
||||||
|
|
||||||
|
Signed-off-by: Joe Smith <joe@gmail.com>
|
||||||
|
|
||||||
|
using your real name (sorry, no pseudonyms or anonymous contributions.)
|
||||||
|
|
||||||
|
You can add the sign off when creating the git commit via `git commit -s`.
|
||||||
|
|
||||||
|
## Code Reviews
|
||||||
|
|
||||||
|
* The pull request title should describe what the change does and not embed issue numbers.
|
||||||
|
The pull request should only be blank when the change is minor. Any feature should include
|
||||||
|
a description of the change and what motivated it. If the change or design changes through
|
||||||
|
review, please keep the title and description updated accordingly.
|
||||||
|
* A single approval is sufficient to merge. If a reviewer asks for
|
||||||
|
changes in a PR they should be addressed before the PR is merged,
|
||||||
|
even if another reviewer has already approved the PR.
|
||||||
|
* During the review, address the comments and commit the changes
|
||||||
|
_without_ squashing the commits. This facilitates incremental reviews
|
||||||
|
since the reviewer does not go through all the code again to find out
|
||||||
|
what has changed since the last review. When a change goes out of sync with main,
|
||||||
|
please rebase and force push, keeping the original commits where practical.
|
||||||
|
* Commits are squashed prior to merging a pull request, using the title
|
||||||
|
as commit message by default. Maintainers may request contributors to
|
||||||
|
edit the pull request tite to ensure that it remains descriptive as a
|
||||||
|
commit message. Alternatively, maintainers may change the commit message directly.
|
||||||
201
vendor/github.com/tetratelabs/wazero/LICENSE
generated
vendored
Normal file
201
vendor/github.com/tetratelabs/wazero/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright 2020-2023 wazero authors
|
||||||
|
|
||||||
|
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.
|
||||||
364
vendor/github.com/tetratelabs/wazero/Makefile
generated
vendored
Normal file
364
vendor/github.com/tetratelabs/wazero/Makefile
generated
vendored
Normal file
@@ -0,0 +1,364 @@
|
|||||||
|
|
||||||
|
gofumpt := mvdan.cc/gofumpt@v0.6.0
|
||||||
|
gosimports := github.com/rinchsan/gosimports/cmd/gosimports@v0.3.8
|
||||||
|
golangci_lint := github.com/golangci/golangci-lint/cmd/golangci-lint@v1.64.5
|
||||||
|
asmfmt := github.com/klauspost/asmfmt/cmd/asmfmt@v1.3.2
|
||||||
|
# sync this with netlify.toml!
|
||||||
|
hugo := github.com/gohugoio/hugo@v0.115.2
|
||||||
|
|
||||||
|
# Make 3.81 doesn't support '**' globbing: Set explicitly instead of recursion.
|
||||||
|
all_sources := $(wildcard *.go */*.go */*/*.go */*/*/*.go */*/*/*.go */*/*/*/*.go)
|
||||||
|
all_testdata := $(wildcard testdata/* */testdata/* */*/testdata/* */*/testdata/*/* */*/*/testdata/*)
|
||||||
|
all_testing := $(wildcard internal/testing/* internal/testing/*/* internal/testing/*/*/*)
|
||||||
|
all_examples := $(wildcard examples/* examples/*/* examples/*/*/* */*/example/* */*/example/*/* */*/example/*/*/*)
|
||||||
|
all_it := $(wildcard internal/integration_test/* internal/integration_test/*/* internal/integration_test/*/*/*)
|
||||||
|
# main_sources exclude any test or example related code
|
||||||
|
main_sources := $(wildcard $(filter-out %_test.go $(all_testdata) $(all_testing) $(all_examples) $(all_it), $(all_sources)))
|
||||||
|
# main_packages collect the unique main source directories (sort will dedupe).
|
||||||
|
# Paths need to all start with ./, so we do that manually vs foreach which strips it.
|
||||||
|
main_packages := $(sort $(foreach f,$(dir $(main_sources)),$(if $(findstring ./,$(f)),./,./$(f))))
|
||||||
|
|
||||||
|
go_test_options ?= -timeout 300s
|
||||||
|
|
||||||
|
.PHONY: test.examples
|
||||||
|
test.examples:
|
||||||
|
@go test $(go_test_options) ./examples/... ./imports/assemblyscript/example/... ./imports/emscripten/... ./imports/wasi_snapshot_preview1/example/...
|
||||||
|
|
||||||
|
.PHONY: build.examples.as
|
||||||
|
build.examples.as:
|
||||||
|
@cd ./imports/assemblyscript/example/testdata && npm install && npm run build
|
||||||
|
|
||||||
|
%.wasm: %.zig
|
||||||
|
@(cd $(@D); zig build -Doptimize=ReleaseSmall)
|
||||||
|
@mv $(@D)/zig-out/*/$(@F) $(@D)
|
||||||
|
|
||||||
|
.PHONY: build.examples.zig
|
||||||
|
build.examples.zig: examples/allocation/zig/testdata/greet.wasm imports/wasi_snapshot_preview1/example/testdata/zig/cat.wasm imports/wasi_snapshot_preview1/testdata/zig/wasi.wasm
|
||||||
|
@cd internal/testing/dwarftestdata/testdata/zig; zig build; mv zig-out/*/main.wasm ./ # Need DWARF custom sections.
|
||||||
|
|
||||||
|
tinygo_reactor_sources_reactor := examples/basic/testdata/add.go examples/allocation/tinygo/testdata/greet.go
|
||||||
|
.PHONY: build.examples.tinygo_reactor
|
||||||
|
build.examples.tinygo_reactor: $(tinygo_sources_reactor)
|
||||||
|
@for f in $^; do \
|
||||||
|
tinygo build -o $$(echo $$f | sed -e 's/\.go/\.wasm/') -scheduler=none --no-debug --target=wasip1 -buildmode=c-shared $$f; \
|
||||||
|
done
|
||||||
|
|
||||||
|
tinygo_sources_clis := examples/cli/testdata/cli.go imports/wasi_snapshot_preview1/example/testdata/tinygo/cat.go imports/wasi_snapshot_preview1/testdata/tinygo/wasi.go cmd/wazero/testdata/cat/cat.go
|
||||||
|
.PHONY: build.examples.tinygo_clis
|
||||||
|
build.examples.tinygo_clis: $(tinygo_sources_clis)
|
||||||
|
@for f in $^; do \
|
||||||
|
tinygo build -o $$(echo $$f | sed -e 's/\.go/\.wasm/') -scheduler=none --no-debug --target=wasip1 $$f; \
|
||||||
|
done
|
||||||
|
@mv cmd/wazero/testdata/cat/cat.wasm cmd/wazero/testdata/cat/cat-tinygo.wasm
|
||||||
|
|
||||||
|
.PHONY: build.examples.tinygo
|
||||||
|
build.examples.tinygo: build.examples.tinygo_reactor build.examples.tinygo_clis
|
||||||
|
|
||||||
|
# We use zig to build C as it is easy to install and embeds a copy of zig-cc.
|
||||||
|
# Note: Don't use "-Oz" as that breaks our wasi sock example.
|
||||||
|
c_sources := imports/wasi_snapshot_preview1/example/testdata/zig-cc/cat.c imports/wasi_snapshot_preview1/testdata/zig-cc/wasi.c internal/testing/dwarftestdata/testdata/zig-cc/main.c
|
||||||
|
.PHONY: build.examples.zig-cc
|
||||||
|
build.examples.zig-cc: $(c_sources)
|
||||||
|
@for f in $^; do \
|
||||||
|
zig cc --target=wasm32-wasi -o $$(echo $$f | sed -e 's/\.c/\.wasm/') $$f; \
|
||||||
|
done
|
||||||
|
|
||||||
|
# Here are the emcc args we use:
|
||||||
|
#
|
||||||
|
# * `-Oz` - most optimization for code size.
|
||||||
|
# * `--profiling` - adds the name section.
|
||||||
|
# * `-s STANDALONE_WASM` - ensures wasm is built for a non-js runtime.
|
||||||
|
# * `-s EXPORTED_FUNCTIONS=_malloc,_free` - export allocation functions so that
|
||||||
|
# they can be used externally as "malloc" and "free".
|
||||||
|
# * `-s WARN_ON_UNDEFINED_SYMBOLS=0` - imports not defined in JavaScript error
|
||||||
|
# otherwise. See https://github.com/emscripten-core/emscripten/issues/13641
|
||||||
|
# * `-s TOTAL_STACK=8KB -s TOTAL_MEMORY=64KB` - reduce memory default from 16MB
|
||||||
|
# to one page (64KB). To do this, we have to reduce the stack size.
|
||||||
|
# * `-s ALLOW_MEMORY_GROWTH` - allows "memory.grow" instructions to succeed, but
|
||||||
|
# requires a function import "emscripten_notify_memory_growth".
|
||||||
|
emscripten_sources := $(wildcard imports/emscripten/testdata/*.cc)
|
||||||
|
.PHONY: build.examples.emscripten
|
||||||
|
build.examples.emscripten: $(emscripten_sources)
|
||||||
|
@for f in $^; do \
|
||||||
|
em++ -Oz --profiling \
|
||||||
|
-s STANDALONE_WASM \
|
||||||
|
-s EXPORTED_FUNCTIONS=_malloc,_free \
|
||||||
|
-s WARN_ON_UNDEFINED_SYMBOLS=0 \
|
||||||
|
-s TOTAL_STACK=8KB -s TOTAL_MEMORY=64KB \
|
||||||
|
-s ALLOW_MEMORY_GROWTH \
|
||||||
|
--std=c++17 -o $$(echo $$f | sed -e 's/\.cc/\.wasm/') $$f; \
|
||||||
|
done
|
||||||
|
|
||||||
|
%/greet.wasm : cargo_target := wasm32-unknown-unknown
|
||||||
|
%/cat.wasm : cargo_target := wasm32-wasip1
|
||||||
|
%/wasi.wasm : cargo_target := wasm32-wasip1
|
||||||
|
|
||||||
|
.PHONY: build.examples.rust
|
||||||
|
build.examples.rust: examples/allocation/rust/testdata/greet.wasm imports/wasi_snapshot_preview1/example/testdata/cargo-wasi/cat.wasm imports/wasi_snapshot_preview1/testdata/cargo-wasi/wasi.wasm internal/testing/dwarftestdata/testdata/rust/main.wasm.xz
|
||||||
|
|
||||||
|
# Normally, we build release because it is smaller. Testing dwarf requires the debug build.
|
||||||
|
internal/testing/dwarftestdata/testdata/rust/main.wasm.xz:
|
||||||
|
cd $(@D) && cargo build --target wasm32-wasip1
|
||||||
|
mv $(@D)/target/wasm32-wasip1/debug/main.wasm $(@D)
|
||||||
|
cd $(@D) && xz -k -f ./main.wasm # Rust's DWARF section is huge, so compress it.
|
||||||
|
|
||||||
|
# Builds rust using cargo normally
|
||||||
|
%.wasm: %.rs
|
||||||
|
@(cd $(@D); cargo build --target $(cargo_target) --release)
|
||||||
|
@mv $(@D)/target/$(cargo_target)/release/$(@F) $(@D)
|
||||||
|
|
||||||
|
spectest_base_dir := internal/integration_test/spectest
|
||||||
|
spectest_v1_dir := $(spectest_base_dir)/v1
|
||||||
|
spectest_v1_testdata_dir := $(spectest_v1_dir)/testdata
|
||||||
|
spec_version_v1 := wg-1.0
|
||||||
|
spectest_v2_dir := $(spectest_base_dir)/v2
|
||||||
|
spectest_v2_testdata_dir := $(spectest_v2_dir)/testdata
|
||||||
|
# Latest draft state as of March 12, 2024.
|
||||||
|
spec_version_v2 := 1c5e5d178bd75c79b7a12881c529098beaee2a05
|
||||||
|
spectest_threads_dir := $(spectest_base_dir)/threads
|
||||||
|
spectest_threads_testdata_dir := $(spectest_threads_dir)/testdata
|
||||||
|
# From https://github.com/WebAssembly/threads/tree/upstream-rebuild which has not been merged to main yet.
|
||||||
|
# It will likely be renamed to main in the future - https://github.com/WebAssembly/threads/issues/216.
|
||||||
|
spec_version_threads := 3635ca51a17e57e106988846c5b0e0cc48ac04fc
|
||||||
|
|
||||||
|
.PHONY: build.spectest
|
||||||
|
build.spectest:
|
||||||
|
@$(MAKE) build.spectest.v1
|
||||||
|
@$(MAKE) build.spectest.v2
|
||||||
|
|
||||||
|
.PHONY: build.spectest.v1
|
||||||
|
build.spectest.v1: # Note: wabt by default uses >1.0 features, so wast2json flags might drift as they include more. See WebAssembly/wabt#1878
|
||||||
|
@rm -rf $(spectest_v1_testdata_dir)
|
||||||
|
@mkdir -p $(spectest_v1_testdata_dir)
|
||||||
|
@cd $(spectest_v1_testdata_dir) \
|
||||||
|
&& curl -sSL 'https://api.github.com/repos/WebAssembly/spec/contents/test/core?ref=$(spec_version_v1)' | jq -r '.[]| .download_url' | grep -E ".wast" | xargs -Iurl curl -sJL url -O
|
||||||
|
@cd $(spectest_v1_testdata_dir) && for f in `find . -name '*.wast'`; do \
|
||||||
|
perl -pi -e 's/\(assert_return_canonical_nan\s(\(invoke\s"f32.demote_f64"\s\((f[0-9]{2})\.const\s[a-z0-9.+:-]+\)\))\)/\(assert_return $$1 \(f32.const nan:canonical\)\)/g' $$f; \
|
||||||
|
perl -pi -e 's/\(assert_return_arithmetic_nan\s(\(invoke\s"f32.demote_f64"\s\((f[0-9]{2})\.const\s[a-z0-9.+:-]+\)\))\)/\(assert_return $$1 \(f32.const nan:arithmetic\)\)/g' $$f; \
|
||||||
|
perl -pi -e 's/\(assert_return_canonical_nan\s(\(invoke\s"f64\.promote_f32"\s\((f[0-9]{2})\.const\s[a-z0-9.+:-]+\)\))\)/\(assert_return $$1 \(f64.const nan:canonical\)\)/g' $$f; \
|
||||||
|
perl -pi -e 's/\(assert_return_arithmetic_nan\s(\(invoke\s"f64\.promote_f32"\s\((f[0-9]{2})\.const\s[a-z0-9.+:-]+\)\))\)/\(assert_return $$1 \(f64.const nan:arithmetic\)\)/g' $$f; \
|
||||||
|
perl -pi -e 's/\(assert_return_canonical_nan\s(\(invoke\s"[a-z._0-9]+"\s\((f[0-9]{2})\.const\s[a-z0-9.+:-]+\)\))\)/\(assert_return $$1 \($$2.const nan:canonical\)\)/g' $$f; \
|
||||||
|
perl -pi -e 's/\(assert_return_arithmetic_nan\s(\(invoke\s"[a-z._0-9]+"\s\((f[0-9]{2})\.const\s[a-z0-9.+:-]+\)\))\)/\(assert_return $$1 \($$2.const nan:arithmetic\)\)/g' $$f; \
|
||||||
|
perl -pi -e 's/\(assert_return_canonical_nan\s(\(invoke\s"[a-z._0-9]+"\s\((f[0-9]{2})\.const\s[a-z0-9.+:-]+\)\s\([a-z0-9.\s+-:]+\)\))\)/\(assert_return $$1 \($$2.const nan:canonical\)\)/g' $$f; \
|
||||||
|
perl -pi -e 's/\(assert_return_arithmetic_nan\s(\(invoke\s"[a-z._0-9]+"\s\((f[0-9]{2})\.const\s[a-z0-9.+:-]+\)\s\([a-z0-9.\s+-:]+\)\))\)/\(assert_return $$1 \($$2.const nan:arithmetic\)\)/g' $$f; \
|
||||||
|
perl -pi -e 's/\(assert_return_canonical_nan\s(\(invoke\s"[a-z._0-9]+"\s\((f[0-9]{2})\.const\s[a-z0-9.+:-]+\)\))\)/\(assert_return $$1 \($$2.const nan:canonical\)\)/g' $$f; \
|
||||||
|
perl -pi -e 's/\(assert_return_arithmetic_nan\s(\(invoke\s"[a-z._0-9]+"\s\((f[0-9]{2})\.const\s[a-z0-9.+:-]+\)\))\)/\(assert_return $$1 \($$2.const nan:arithmetic\)\)/g' $$f; \
|
||||||
|
wast2json \
|
||||||
|
--disable-saturating-float-to-int \
|
||||||
|
--disable-sign-extension \
|
||||||
|
--disable-simd \
|
||||||
|
--disable-multi-value \
|
||||||
|
--disable-bulk-memory \
|
||||||
|
--disable-reference-types \
|
||||||
|
--debug-names $$f; \
|
||||||
|
done
|
||||||
|
|
||||||
|
.PHONY: build.spectest.v2
|
||||||
|
build.spectest.v2: # Note: SIMD cases are placed in the "simd" subdirectory.
|
||||||
|
@mkdir -p $(spectest_v2_testdata_dir)
|
||||||
|
@cd $(spectest_v2_testdata_dir) \
|
||||||
|
&& curl -sSL 'https://api.github.com/repos/WebAssembly/spec/contents/test/core?ref=$(spec_version_v2)' | jq -r '.[]| .download_url' | grep -E ".wast" | xargs -Iurl curl -sJL url -O
|
||||||
|
@cd $(spectest_v2_testdata_dir) \
|
||||||
|
&& curl -sSL 'https://api.github.com/repos/WebAssembly/spec/contents/test/core/simd?ref=$(spec_version_v2)' | jq -r '.[]| .download_url' | grep -E ".wast" | xargs -Iurl curl -sJL url -O
|
||||||
|
@cd $(spectest_v2_testdata_dir) && for f in `find . -name '*.wast'`; do \
|
||||||
|
wast2json --debug-names --no-check $$f || true; \
|
||||||
|
done # Ignore the error here as some tests (e.g. comments.wast right now) are not supported by wast2json yet.
|
||||||
|
|
||||||
|
# Note: We currently cannot build the "threads" subdirectory that spawns threads due to missing support in wast2json.
|
||||||
|
# https://github.com/WebAssembly/wabt/issues/2348#issuecomment-1878003959
|
||||||
|
.PHONY: build.spectest.threads
|
||||||
|
build.spectest.threads:
|
||||||
|
@mkdir -p $(spectest_threads_testdata_dir)
|
||||||
|
@cd $(spectest_threads_testdata_dir) \
|
||||||
|
&& curl -sSL 'https://api.github.com/repos/WebAssembly/threads/contents/test/core?ref=$(spec_version_threads)' | jq -r '.[]| .download_url' | grep -E "atomic.wast" | xargs -Iurl curl -sJL url -O
|
||||||
|
@cd $(spectest_threads_testdata_dir) && for f in `find . -name '*.wast'`; do \
|
||||||
|
wast2json --enable-threads --debug-names $$f; \
|
||||||
|
done
|
||||||
|
|
||||||
|
.PHONY: test
|
||||||
|
test:
|
||||||
|
@go test $(go_test_options) ./...
|
||||||
|
@cd internal/version/testdata && go test $(go_test_options) ./...
|
||||||
|
@cd internal/integration_test/fuzz/wazerolib && CGO_ENABLED=0 WASM_BINARY_PATH=testdata/test.wasm go test ./...
|
||||||
|
|
||||||
|
.PHONY: coverage
|
||||||
|
# replace spaces with commas
|
||||||
|
coverpkg = $(shell echo $(main_packages) | tr ' ' ',')
|
||||||
|
coverage: ## Generate test coverage
|
||||||
|
@go test -coverprofile=coverage.txt -covermode=atomic --coverpkg=$(coverpkg) $(main_packages)
|
||||||
|
@go tool cover -func coverage.txt
|
||||||
|
|
||||||
|
golangci_lint_path := $(shell go env GOPATH)/bin/golangci-lint
|
||||||
|
|
||||||
|
$(golangci_lint_path):
|
||||||
|
@go install $(golangci_lint)
|
||||||
|
|
||||||
|
golangci_lint_goarch ?= $(shell go env GOARCH)
|
||||||
|
|
||||||
|
.PHONY: lint
|
||||||
|
lint: $(golangci_lint_path)
|
||||||
|
@GOARCH=$(golangci_lint_goarch) CGO_ENABLED=0 $(golangci_lint_path) run --timeout 5m -E testableexamples
|
||||||
|
|
||||||
|
.PHONY: format
|
||||||
|
format:
|
||||||
|
@go run $(gofumpt) -l -w .
|
||||||
|
@go run $(gosimports) -local github.com/tetratelabs/ -w $(shell find . -name '*.go' -type f)
|
||||||
|
@go run $(asmfmt) -w $(shell find . -name '*.s' -type f)
|
||||||
|
|
||||||
|
.PHONY: check # Pre-flight check for pull requests
|
||||||
|
check:
|
||||||
|
# The following checks help ensure our platform-specific code used for system
|
||||||
|
# calls safely falls back on a platform unsupported by the compiler engine.
|
||||||
|
# This makes sure the intepreter can be used. Most often the package that can
|
||||||
|
# drift here is "platform" or "sysfs":
|
||||||
|
#
|
||||||
|
# Ensure we build on plan9. See #1578
|
||||||
|
@GOARCH=amd64 GOOS=plan9 go build ./...
|
||||||
|
# Ensure we build on gojs. See #1526.
|
||||||
|
@GOARCH=wasm GOOS=js go build ./...
|
||||||
|
# Ensure we build on wasip1. See #1526.
|
||||||
|
@GOARCH=wasm GOOS=wasip1 go build ./...
|
||||||
|
# Ensure we build on aix. See #1723
|
||||||
|
@GOARCH=ppc64 GOOS=aix go build ./...
|
||||||
|
# Ensure we build on windows:
|
||||||
|
@GOARCH=amd64 GOOS=windows go build ./...
|
||||||
|
# Ensure we build on an arbitrary operating system:
|
||||||
|
@GOARCH=amd64 GOOS=dragonfly go build ./...
|
||||||
|
# Ensure we build on solaris/illumos:
|
||||||
|
@GOARCH=amd64 GOOS=illumos go build ./...
|
||||||
|
@GOARCH=amd64 GOOS=solaris go build ./...
|
||||||
|
# Ensure we build on linux arm for Dapr:
|
||||||
|
# gh release view -R dapr/dapr --json assets --jq 'first(.assets[] | select(.name = "daprd_linux_arm.tar.gz") | {url, downloadCount})'
|
||||||
|
@GOARCH=arm GOOS=linux go build ./...
|
||||||
|
# Ensure we build on linux 386 for Trivy:
|
||||||
|
# gh release view -R aquasecurity/trivy --json assets --jq 'first(.assets[] | select(.name| test("Linux-32bit.*tar.gz")) | {url, downloadCount})'
|
||||||
|
@GOARCH=386 GOOS=linux go build ./...
|
||||||
|
# Ensure we build on FreeBSD amd64 for Trivy:
|
||||||
|
# gh release view -R aquasecurity/trivy --json assets --jq 'first(.assets[] | select(.name| test("FreeBSD-64bit.*tar.gz")) | {url, downloadCount})'
|
||||||
|
@GOARCH=amd64 GOOS=freebsd go build ./...
|
||||||
|
@$(MAKE) lint golangci_lint_goarch=arm64
|
||||||
|
@$(MAKE) lint golangci_lint_goarch=amd64
|
||||||
|
@$(MAKE) format
|
||||||
|
@go mod tidy
|
||||||
|
@if [ ! -z "`git status -s`" ]; then \
|
||||||
|
echo "The following differences will fail CI until committed:"; \
|
||||||
|
git diff --exit-code; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
.PHONY: site
|
||||||
|
site: ## Serve website content
|
||||||
|
@git submodule update --init
|
||||||
|
@cd site && go run $(hugo) server --minify --disableFastRender --baseURL localhost:1313 --cleanDestinationDir -D
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
|
clean: ## Ensure a clean build
|
||||||
|
@rm -rf dist build coverage.txt
|
||||||
|
@go clean -testcache
|
||||||
|
|
||||||
|
fuzz_default_flags := --no-trace-compares --sanitizer=none -- -rss_limit_mb=8192
|
||||||
|
|
||||||
|
fuzz_timeout_seconds ?= 10
|
||||||
|
.PHONY: fuzz
|
||||||
|
fuzz:
|
||||||
|
@cd internal/integration_test/fuzz && cargo test
|
||||||
|
@cd internal/integration_test/fuzz && cargo fuzz run logging_no_diff $(fuzz_default_flags) -max_total_time=$(fuzz_timeout_seconds)
|
||||||
|
@cd internal/integration_test/fuzz && cargo fuzz run no_diff $(fuzz_default_flags) -max_total_time=$(fuzz_timeout_seconds)
|
||||||
|
@cd internal/integration_test/fuzz && cargo fuzz run memory_no_diff $(fuzz_default_flags) -max_total_time=$(fuzz_timeout_seconds)
|
||||||
|
@cd internal/integration_test/fuzz && cargo fuzz run validation $(fuzz_default_flags) -max_total_time=$(fuzz_timeout_seconds)
|
||||||
|
|
||||||
|
libsodium:
|
||||||
|
cd ./internal/integration_test/libsodium/testdata && \
|
||||||
|
curl -s "https://api.github.com/repos/jedisct1/webassembly-benchmarks/contents/2022-12/wasm?ref=7e86d68e99e60130899fbe3b3ab6e9dce9187a7c" \
|
||||||
|
| jq -r '.[] | .download_url' | xargs -n 1 curl -LO
|
||||||
|
|
||||||
|
#### CLI release related ####
|
||||||
|
|
||||||
|
VERSION ?= dev
|
||||||
|
# Default to a dummy version 0.0.1.1, which is always lower than a real release.
|
||||||
|
# Legal version values should look like 'x.x.x.x' where x is an integer from 0 to 65534.
|
||||||
|
# https://learn.microsoft.com/en-us/windows/win32/msi/productversion?redirectedfrom=MSDN
|
||||||
|
# https://stackoverflow.com/questions/9312221/msi-version-numbers
|
||||||
|
MSI_VERSION ?= 0.0.1.1
|
||||||
|
non_windows_platforms := darwin_amd64 darwin_arm64 linux_amd64 linux_arm64
|
||||||
|
non_windows_archives := $(non_windows_platforms:%=dist/wazero_$(VERSION)_%.tar.gz)
|
||||||
|
windows_platforms := windows_amd64 # TODO: add arm64 windows once we start testing on it.
|
||||||
|
windows_archives := $(windows_platforms:%=dist/wazero_$(VERSION)_%.zip) $(windows_platforms:%=dist/wazero_$(VERSION)_%.msi)
|
||||||
|
checksum_txt := dist/wazero_$(VERSION)_checksums.txt
|
||||||
|
|
||||||
|
# define macros for multi-platform builds. these parse the filename being built
|
||||||
|
go-arch = $(if $(findstring amd64,$1),amd64,arm64)
|
||||||
|
go-os = $(if $(findstring .exe,$1),windows,$(if $(findstring linux,$1),linux,darwin))
|
||||||
|
# msi-arch is a macro so we can detect it based on the file naming convention
|
||||||
|
msi-arch = $(if $(findstring amd64,$1),x64,arm64)
|
||||||
|
|
||||||
|
build/wazero_%/wazero:
|
||||||
|
$(call go-build,$@,$<)
|
||||||
|
|
||||||
|
build/wazero_%/wazero.exe:
|
||||||
|
$(call go-build,$@,$<)
|
||||||
|
|
||||||
|
dist/wazero_$(VERSION)_%.tar.gz: build/wazero_%/wazero
|
||||||
|
@echo tar.gz "tarring $@"
|
||||||
|
@mkdir -p $(@D)
|
||||||
|
# On Windows, we pass the special flag `--mode='+rx' to ensure that we set the executable flag.
|
||||||
|
# This is only supported by GNU Tar, so we set it conditionally.
|
||||||
|
@tar -C $(<D) -cpzf $@ $(if $(findstring Windows_NT,$(OS)),--mode='+rx',) $(<F)
|
||||||
|
@echo tar.gz "ok"
|
||||||
|
|
||||||
|
define go-build
|
||||||
|
@echo "building $1"
|
||||||
|
@# $(go:go=) removes the trailing 'go', so we can insert cross-build variables
|
||||||
|
@$(go:go=) CGO_ENABLED=0 GOOS=$(call go-os,$1) GOARCH=$(call go-arch,$1) go build \
|
||||||
|
-ldflags "-s -w -X github.com/tetratelabs/wazero/internal/version.version=$(VERSION)" \
|
||||||
|
-o $1 $2 ./cmd/wazero
|
||||||
|
@echo build "ok"
|
||||||
|
endef
|
||||||
|
|
||||||
|
# this makes a marker file ending in .signed to avoid repeatedly calling codesign
|
||||||
|
%.signed: %
|
||||||
|
$(call codesign,$<)
|
||||||
|
@touch $@
|
||||||
|
|
||||||
|
# This requires osslsigncode package (apt or brew) or latest windows release from mtrojnar/osslsigncode
|
||||||
|
#
|
||||||
|
# Default is self-signed while production should be a Digicert signing key
|
||||||
|
#
|
||||||
|
# Ex.
|
||||||
|
# ```bash
|
||||||
|
# keytool -genkey -alias wazero -storetype PKCS12 -keyalg RSA -keysize 2048 -storepass wazero-bunch \
|
||||||
|
# -keystore wazero.p12 -dname "O=wazero,CN=wazero.io" -validity 3650
|
||||||
|
# ```
|
||||||
|
WINDOWS_CODESIGN_P12 ?= packaging/msi/wazero.p12
|
||||||
|
WINDOWS_CODESIGN_PASSWORD ?= wazero-bunch
|
||||||
|
define codesign
|
||||||
|
@printf "$(ansi_format_dark)" codesign "signing $1"
|
||||||
|
@osslsigncode sign -h sha256 -pkcs12 ${WINDOWS_CODESIGN_P12} -pass "${WINDOWS_CODESIGN_PASSWORD}" \
|
||||||
|
-n "wazero is the zero dependency WebAssembly runtime for Go developers" -i https://wazero.io -t http://timestamp.digicert.com \
|
||||||
|
$(if $(findstring msi,$(1)),-add-msi-dse) -in $1 -out $1-signed
|
||||||
|
@mv $1-signed $1
|
||||||
|
@printf "$(ansi_format_bright)" codesign "ok"
|
||||||
|
endef
|
||||||
|
|
||||||
|
# This task is only supported on Windows, where we use candle.exe (compile wxs to wixobj) and light.exe (link to msi)
|
||||||
|
dist/wazero_$(VERSION)_%.msi: build/wazero_%/wazero.exe.signed
|
||||||
|
ifeq ($(OS),Windows_NT)
|
||||||
|
@echo msi "building $@"
|
||||||
|
@mkdir -p $(@D)
|
||||||
|
@candle -nologo -arch $(call msi-arch,$@) -dVersion=$(MSI_VERSION) -dBin=$(<:.signed=) -o build/wazero.wixobj packaging/msi/wazero.wxs
|
||||||
|
@light -nologo -o $@ build/wazero.wixobj -spdb
|
||||||
|
$(call codesign,$@)
|
||||||
|
@echo msi "ok"
|
||||||
|
endif
|
||||||
|
|
||||||
|
dist/wazero_$(VERSION)_%.zip: build/wazero_%/wazero.exe.signed
|
||||||
|
@echo zip "zipping $@"
|
||||||
|
@mkdir -p $(@D)
|
||||||
|
@zip -qj $@ $(<:.signed=)
|
||||||
|
@echo zip "ok"
|
||||||
|
|
||||||
|
# Darwin doesn't have sha256sum. See https://github.com/actions/virtual-environments/issues/90
|
||||||
|
sha256sum := $(if $(findstring darwin,$(shell go env GOOS)),shasum -a 256,sha256sum)
|
||||||
|
$(checksum_txt):
|
||||||
|
@cd $(@D); touch $(@F); $(sha256sum) * >> $(@F)
|
||||||
|
|
||||||
|
dist: $(non_windows_archives) $(if $(findstring Windows_NT,$(OS)),$(windows_archives),) $(checksum_txt)
|
||||||
2
vendor/github.com/tetratelabs/wazero/NOTICE
generated
vendored
Normal file
2
vendor/github.com/tetratelabs/wazero/NOTICE
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
wazero
|
||||||
|
Copyright 2020-2023 wazero authors
|
||||||
1587
vendor/github.com/tetratelabs/wazero/RATIONALE.md
generated
vendored
Normal file
1587
vendor/github.com/tetratelabs/wazero/RATIONALE.md
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
139
vendor/github.com/tetratelabs/wazero/README.md
generated
vendored
Normal file
139
vendor/github.com/tetratelabs/wazero/README.md
generated
vendored
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
# wazero: the zero dependency WebAssembly runtime for Go developers
|
||||||
|
|
||||||
|
[](https://pkg.go.dev/github.com/tetratelabs/wazero) [](https://opensource.org/licenses/Apache-2.0)
|
||||||
|
|
||||||
|
WebAssembly is a way to safely run code compiled in other languages. Runtimes
|
||||||
|
execute WebAssembly Modules (Wasm), which are most often binaries with a `.wasm`
|
||||||
|
extension.
|
||||||
|
|
||||||
|
wazero is a WebAssembly Core Specification [1.0][1] and [2.0][2] compliant
|
||||||
|
runtime written in Go. It has *zero dependencies*, and doesn't rely on CGO.
|
||||||
|
This means you can run applications in other languages and still keep cross
|
||||||
|
compilation.
|
||||||
|
|
||||||
|
Import wazero and extend your Go application with code written in any language!
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
The best way to learn wazero is by trying one of our [examples](examples/README.md). The
|
||||||
|
most [basic example](examples/basic) extends a Go application with an addition
|
||||||
|
function defined in WebAssembly.
|
||||||
|
|
||||||
|
## Runtime
|
||||||
|
|
||||||
|
There are two runtime configurations supported in wazero: _Compiler_ is default:
|
||||||
|
|
||||||
|
By default, ex `wazero.NewRuntime(ctx)`, the Compiler is used if supported. You
|
||||||
|
can also force the interpreter like so:
|
||||||
|
```go
|
||||||
|
r := wazero.NewRuntimeWithConfig(ctx, wazero.NewRuntimeConfigInterpreter())
|
||||||
|
```
|
||||||
|
|
||||||
|
### Interpreter
|
||||||
|
Interpreter is a naive interpreter-based implementation of Wasm virtual
|
||||||
|
machine. Its implementation doesn't have any platform (GOARCH, GOOS) specific
|
||||||
|
code, therefore _interpreter_ can be used for any compilation target available
|
||||||
|
for Go (such as `riscv64`).
|
||||||
|
|
||||||
|
### Compiler
|
||||||
|
Compiler compiles WebAssembly modules into machine code ahead of time (AOT),
|
||||||
|
during `Runtime.CompileModule`. This means your WebAssembly functions execute
|
||||||
|
natively at runtime. Compiler is faster than Interpreter, often by order of
|
||||||
|
magnitude (10x) or more. This is done without host-specific dependencies.
|
||||||
|
|
||||||
|
### Conformance
|
||||||
|
|
||||||
|
Both runtimes pass WebAssembly Core [1.0][7] and [2.0][14] specification tests
|
||||||
|
on supported platforms:
|
||||||
|
|
||||||
|
| Runtime | Usage | amd64 | arm64 | others |
|
||||||
|
|:-----------:|:--------------------------------------:|:-----:|:-----:|:------:|
|
||||||
|
| Interpreter | `wazero.NewRuntimeConfigInterpreter()` | ✅ | ✅ | ✅ |
|
||||||
|
| Compiler | `wazero.NewRuntimeConfigCompiler()` | ✅ | ✅ | ❌ |
|
||||||
|
|
||||||
|
## Support Policy
|
||||||
|
|
||||||
|
The below support policy focuses on compatibility concerns of those embedding
|
||||||
|
wazero into their Go applications.
|
||||||
|
|
||||||
|
### wazero
|
||||||
|
|
||||||
|
wazero's [1.0 release][15] happened in March 2023, and is [in use][16] by many
|
||||||
|
projects and production sites.
|
||||||
|
|
||||||
|
We offer an API stability promise with semantic versioning. In other words, we
|
||||||
|
promise to not break any exported function signature without incrementing the
|
||||||
|
major version. This does not mean no innovation: New features and behaviors
|
||||||
|
happen with a minor version increment, e.g. 1.0.11 to 1.2.0. We also fix bugs
|
||||||
|
or change internal details with a patch version, e.g. 1.0.0 to 1.0.1.
|
||||||
|
|
||||||
|
You can get the latest version of wazero like this.
|
||||||
|
```bash
|
||||||
|
go get github.com/tetratelabs/wazero@latest
|
||||||
|
```
|
||||||
|
|
||||||
|
Please give us a [star][17] if you end up using wazero!
|
||||||
|
|
||||||
|
### Go
|
||||||
|
|
||||||
|
wazero has no dependencies except Go, so the only source of conflict in your
|
||||||
|
project's use of wazero is the Go version.
|
||||||
|
|
||||||
|
wazero follows the same version policy as Go's [Release Policy][10]: two
|
||||||
|
versions. wazero will ensure these versions work and bugs are valid if there's
|
||||||
|
an issue with a current Go version.
|
||||||
|
|
||||||
|
Additionally, wazero intentionally delays usage of language or standard library
|
||||||
|
features one additional version. For example, when Go 1.29 is released, wazero
|
||||||
|
can use language features or standard libraries added in 1.27. This is a
|
||||||
|
convenience for embedders who have a slower version policy than Go. However,
|
||||||
|
only supported Go versions may be used to raise support issues.
|
||||||
|
|
||||||
|
### Platform
|
||||||
|
|
||||||
|
wazero has two runtime modes: Interpreter and Compiler. The only supported operating
|
||||||
|
systems are ones we test, but that doesn't necessarily mean other operating
|
||||||
|
system versions won't work.
|
||||||
|
|
||||||
|
We currently test Linux (Ubuntu and scratch), MacOS and Windows as packaged by
|
||||||
|
[GitHub Actions][11], as well as nested VMs running on Linux for FreeBSD, NetBSD,
|
||||||
|
OpenBSD, DragonFly BSD, illumos and Solaris.
|
||||||
|
|
||||||
|
We also test cross compilation for many `GOOS` and `GOARCH` combinations.
|
||||||
|
|
||||||
|
* Interpreter
|
||||||
|
* Linux is tested on amd64 (native) as well arm64 and riscv64 via emulation.
|
||||||
|
* Windows, FreeBSD, NetBSD, OpenBSD, DragonFly BSD, illumos and Solaris are
|
||||||
|
tested only on amd64.
|
||||||
|
* macOS is tested only on arm64.
|
||||||
|
* Compiler
|
||||||
|
* Linux is tested on amd64 (native) as well arm64 via emulation.
|
||||||
|
* Windows, FreeBSD, NetBSD, DragonFly BSD, illumos and Solaris are
|
||||||
|
tested only on amd64.
|
||||||
|
* macOS is tested only on arm64.
|
||||||
|
|
||||||
|
wazero has no dependencies and doesn't require CGO. This means it can also be
|
||||||
|
embedded in an application that doesn't use an operating system. This is a main
|
||||||
|
differentiator between wazero and alternatives.
|
||||||
|
|
||||||
|
We verify zero dependencies by running tests in Docker's [scratch image][12].
|
||||||
|
This approach ensures compatibility with any parent image.
|
||||||
|
|
||||||
|
-----
|
||||||
|
wazero is a registered trademark of Tetrate.io, Inc. in the United States and/or other countries
|
||||||
|
|
||||||
|
[1]: https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/
|
||||||
|
[2]: https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/
|
||||||
|
[4]: https://github.com/WebAssembly/meetings/blob/main/process/subgroups.md
|
||||||
|
[5]: https://github.com/WebAssembly/WASI
|
||||||
|
[6]: https://pkg.go.dev/golang.org/x/sys/unix
|
||||||
|
[7]: https://github.com/WebAssembly/spec/tree/wg-1.0/test/core
|
||||||
|
[9]: https://github.com/tetratelabs/wazero/issues/506
|
||||||
|
[10]: https://go.dev/doc/devel/release
|
||||||
|
[11]: https://github.com/actions/virtual-environments
|
||||||
|
[12]: https://docs.docker.com/develop/develop-images/baseimages/#create-a-simple-parent-image-using-scratch
|
||||||
|
[13]: https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md
|
||||||
|
[14]: https://github.com/WebAssembly/spec/tree/d39195773112a22b245ffbe864bab6d1182ccb06/test/core
|
||||||
|
[15]: https://tetrate.io/blog/introducing-wazero-from-tetrate/
|
||||||
|
[16]: https://wazero.io/community/users/
|
||||||
|
[17]: https://github.com/tetratelabs/wazero/stargazers
|
||||||
214
vendor/github.com/tetratelabs/wazero/api/features.go
generated
vendored
Normal file
214
vendor/github.com/tetratelabs/wazero/api/features.go
generated
vendored
Normal file
@@ -0,0 +1,214 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CoreFeatures is a bit flag of WebAssembly Core specification features. See
|
||||||
|
// https://github.com/WebAssembly/proposals for proposals and their status.
|
||||||
|
//
|
||||||
|
// Constants define individual features, such as CoreFeatureMultiValue, or
|
||||||
|
// groups of "finished" features, assigned to a WebAssembly Core Specification
|
||||||
|
// version, e.g. CoreFeaturesV1 or CoreFeaturesV2.
|
||||||
|
//
|
||||||
|
// Note: Numeric values are not intended to be interpreted except as bit flags.
|
||||||
|
type CoreFeatures uint64
|
||||||
|
|
||||||
|
// CoreFeaturesV1 are features included in the WebAssembly Core Specification
|
||||||
|
// 1.0. As of late 2022, this is the only version that is a Web Standard (W3C
|
||||||
|
// Recommendation).
|
||||||
|
//
|
||||||
|
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/
|
||||||
|
const CoreFeaturesV1 = CoreFeatureMutableGlobal
|
||||||
|
|
||||||
|
// CoreFeaturesV2 are features included in the WebAssembly Core Specification
|
||||||
|
// 2.0 (20220419). As of late 2022, version 2.0 is a W3C working draft, not yet
|
||||||
|
// a Web Standard (W3C Recommendation).
|
||||||
|
//
|
||||||
|
// See https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/appendix/changes.html#release-1-1
|
||||||
|
const CoreFeaturesV2 = CoreFeaturesV1 |
|
||||||
|
CoreFeatureBulkMemoryOperations |
|
||||||
|
CoreFeatureMultiValue |
|
||||||
|
CoreFeatureNonTrappingFloatToIntConversion |
|
||||||
|
CoreFeatureReferenceTypes |
|
||||||
|
CoreFeatureSignExtensionOps |
|
||||||
|
CoreFeatureSIMD
|
||||||
|
|
||||||
|
const (
|
||||||
|
// CoreFeatureBulkMemoryOperations adds instructions modify ranges of
|
||||||
|
// memory or table entries ("bulk-memory-operations"). This is included in
|
||||||
|
// CoreFeaturesV2, but not CoreFeaturesV1.
|
||||||
|
//
|
||||||
|
// Here are the notable effects:
|
||||||
|
// - Adds `memory.fill`, `memory.init`, `memory.copy` and `data.drop`
|
||||||
|
// instructions.
|
||||||
|
// - Adds `table.init`, `table.copy` and `elem.drop` instructions.
|
||||||
|
// - Introduces a "passive" form of element and data segments.
|
||||||
|
// - Stops checking "active" element and data segment boundaries at
|
||||||
|
// compile-time, meaning they can error at runtime.
|
||||||
|
//
|
||||||
|
// Note: "bulk-memory-operations" is mixed with the "reference-types"
|
||||||
|
// proposal due to the WebAssembly Working Group merging them
|
||||||
|
// "mutually dependent". Therefore, enabling this feature requires enabling
|
||||||
|
// CoreFeatureReferenceTypes, and vice-versa.
|
||||||
|
//
|
||||||
|
// See https://github.com/WebAssembly/spec/blob/wg-2.0.draft1/proposals/bulk-memory-operations/Overview.md
|
||||||
|
// https://github.com/WebAssembly/spec/blob/wg-2.0.draft1/proposals/reference-types/Overview.md and
|
||||||
|
// https://github.com/WebAssembly/spec/pull/1287
|
||||||
|
CoreFeatureBulkMemoryOperations CoreFeatures = 1 << iota
|
||||||
|
|
||||||
|
// CoreFeatureMultiValue enables multiple values ("multi-value"). This is
|
||||||
|
// included in CoreFeaturesV2, but not CoreFeaturesV1.
|
||||||
|
//
|
||||||
|
// Here are the notable effects:
|
||||||
|
// - Function (`func`) types allow more than one result.
|
||||||
|
// - Block types (`block`, `loop` and `if`) can be arbitrary function
|
||||||
|
// types.
|
||||||
|
//
|
||||||
|
// See https://github.com/WebAssembly/spec/blob/wg-2.0.draft1/proposals/multi-value/Overview.md
|
||||||
|
CoreFeatureMultiValue
|
||||||
|
|
||||||
|
// CoreFeatureMutableGlobal allows globals to be mutable. This is included
|
||||||
|
// in both CoreFeaturesV1 and CoreFeaturesV2.
|
||||||
|
//
|
||||||
|
// When false, an api.Global can never be cast to an api.MutableGlobal, and
|
||||||
|
// any wasm that includes global vars will fail to parse.
|
||||||
|
CoreFeatureMutableGlobal
|
||||||
|
|
||||||
|
// CoreFeatureNonTrappingFloatToIntConversion enables non-trapping
|
||||||
|
// float-to-int conversions ("nontrapping-float-to-int-conversion"). This
|
||||||
|
// is included in CoreFeaturesV2, but not CoreFeaturesV1.
|
||||||
|
//
|
||||||
|
// The only effect of enabling is allowing the following instructions,
|
||||||
|
// which return 0 on NaN instead of panicking.
|
||||||
|
// - `i32.trunc_sat_f32_s`
|
||||||
|
// - `i32.trunc_sat_f32_u`
|
||||||
|
// - `i32.trunc_sat_f64_s`
|
||||||
|
// - `i32.trunc_sat_f64_u`
|
||||||
|
// - `i64.trunc_sat_f32_s`
|
||||||
|
// - `i64.trunc_sat_f32_u`
|
||||||
|
// - `i64.trunc_sat_f64_s`
|
||||||
|
// - `i64.trunc_sat_f64_u`
|
||||||
|
//
|
||||||
|
// See https://github.com/WebAssembly/spec/blob/wg-2.0.draft1/proposals/nontrapping-float-to-int-conversion/Overview.md
|
||||||
|
CoreFeatureNonTrappingFloatToIntConversion
|
||||||
|
|
||||||
|
// CoreFeatureReferenceTypes enables various instructions and features
|
||||||
|
// related to table and new reference types. This is included in
|
||||||
|
// CoreFeaturesV2, but not CoreFeaturesV1.
|
||||||
|
//
|
||||||
|
// - Introduction of new value types: `funcref` and `externref`.
|
||||||
|
// - Support for the following new instructions:
|
||||||
|
// - `ref.null`
|
||||||
|
// - `ref.func`
|
||||||
|
// - `ref.is_null`
|
||||||
|
// - `table.fill`
|
||||||
|
// - `table.get`
|
||||||
|
// - `table.grow`
|
||||||
|
// - `table.set`
|
||||||
|
// - `table.size`
|
||||||
|
// - Support for multiple tables per module:
|
||||||
|
// - `call_indirect`, `table.init`, `table.copy` and `elem.drop`
|
||||||
|
// - Support for instructions can take non-zero table index.
|
||||||
|
// - Element segments can take non-zero table index.
|
||||||
|
//
|
||||||
|
// Note: "reference-types" is mixed with the "bulk-memory-operations"
|
||||||
|
// proposal due to the WebAssembly Working Group merging them
|
||||||
|
// "mutually dependent". Therefore, enabling this feature requires enabling
|
||||||
|
// CoreFeatureBulkMemoryOperations, and vice-versa.
|
||||||
|
//
|
||||||
|
// See https://github.com/WebAssembly/spec/blob/wg-2.0.draft1/proposals/bulk-memory-operations/Overview.md
|
||||||
|
// https://github.com/WebAssembly/spec/blob/wg-2.0.draft1/proposals/reference-types/Overview.md and
|
||||||
|
// https://github.com/WebAssembly/spec/pull/1287
|
||||||
|
CoreFeatureReferenceTypes
|
||||||
|
|
||||||
|
// CoreFeatureSignExtensionOps enables sign extension instructions
|
||||||
|
// ("sign-extension-ops"). This is included in CoreFeaturesV2, but not
|
||||||
|
// CoreFeaturesV1.
|
||||||
|
//
|
||||||
|
// Adds instructions:
|
||||||
|
// - `i32.extend8_s`
|
||||||
|
// - `i32.extend16_s`
|
||||||
|
// - `i64.extend8_s`
|
||||||
|
// - `i64.extend16_s`
|
||||||
|
// - `i64.extend32_s`
|
||||||
|
//
|
||||||
|
// See https://github.com/WebAssembly/spec/blob/wg-2.0.draft1/proposals/sign-extension-ops/Overview.md
|
||||||
|
CoreFeatureSignExtensionOps
|
||||||
|
|
||||||
|
// CoreFeatureSIMD enables the vector value type and vector instructions
|
||||||
|
// (aka SIMD). This is included in CoreFeaturesV2, but not CoreFeaturesV1.
|
||||||
|
//
|
||||||
|
// Note: The instruction list is too long to enumerate in godoc.
|
||||||
|
// See https://github.com/WebAssembly/spec/blob/wg-2.0.draft1/proposals/simd/SIMD.md
|
||||||
|
CoreFeatureSIMD
|
||||||
|
|
||||||
|
// Update experimental/features.go when adding elements here.
|
||||||
|
)
|
||||||
|
|
||||||
|
// SetEnabled enables or disables the feature or group of features.
|
||||||
|
func (f CoreFeatures) SetEnabled(feature CoreFeatures, val bool) CoreFeatures {
|
||||||
|
if val {
|
||||||
|
return f | feature
|
||||||
|
}
|
||||||
|
return f &^ feature
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsEnabled returns true if the feature (or group of features) is enabled.
|
||||||
|
func (f CoreFeatures) IsEnabled(feature CoreFeatures) bool {
|
||||||
|
return f&feature != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// RequireEnabled returns an error if the feature (or group of features) is not
|
||||||
|
// enabled.
|
||||||
|
func (f CoreFeatures) RequireEnabled(feature CoreFeatures) error {
|
||||||
|
if f&feature == 0 {
|
||||||
|
return fmt.Errorf("feature %q is disabled", feature)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// String implements fmt.Stringer by returning each enabled feature.
|
||||||
|
func (f CoreFeatures) String() string {
|
||||||
|
var builder strings.Builder
|
||||||
|
for i := 0; i <= 63; i++ { // cycle through all bits to reduce code and maintenance
|
||||||
|
target := CoreFeatures(1 << i)
|
||||||
|
if f.IsEnabled(target) {
|
||||||
|
if name := featureName(target); name != "" {
|
||||||
|
if builder.Len() > 0 {
|
||||||
|
builder.WriteByte('|')
|
||||||
|
}
|
||||||
|
builder.WriteString(name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return builder.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func featureName(f CoreFeatures) string {
|
||||||
|
switch f {
|
||||||
|
case CoreFeatureMutableGlobal:
|
||||||
|
// match https://github.com/WebAssembly/mutable-global
|
||||||
|
return "mutable-global"
|
||||||
|
case CoreFeatureSignExtensionOps:
|
||||||
|
// match https://github.com/WebAssembly/spec/blob/wg-2.0.draft1/proposals/sign-extension-ops/Overview.md
|
||||||
|
return "sign-extension-ops"
|
||||||
|
case CoreFeatureMultiValue:
|
||||||
|
// match https://github.com/WebAssembly/spec/blob/wg-2.0.draft1/proposals/multi-value/Overview.md
|
||||||
|
return "multi-value"
|
||||||
|
case CoreFeatureNonTrappingFloatToIntConversion:
|
||||||
|
// match https://github.com/WebAssembly/spec/blob/wg-2.0.draft1/proposals/nontrapping-float-to-int-conversion/Overview.md
|
||||||
|
return "nontrapping-float-to-int-conversion"
|
||||||
|
case CoreFeatureBulkMemoryOperations:
|
||||||
|
// match https://github.com/WebAssembly/spec/blob/wg-2.0.draft1/proposals/bulk-memory-operations/Overview.md
|
||||||
|
return "bulk-memory-operations"
|
||||||
|
case CoreFeatureReferenceTypes:
|
||||||
|
// match https://github.com/WebAssembly/spec/blob/wg-2.0.draft1/proposals/reference-types/Overview.md
|
||||||
|
return "reference-types"
|
||||||
|
case CoreFeatureSIMD:
|
||||||
|
// match https://github.com/WebAssembly/spec/blob/wg-2.0.draft1/proposals/simd/SIMD.md
|
||||||
|
return "simd"
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
766
vendor/github.com/tetratelabs/wazero/api/wasm.go
generated
vendored
Normal file
766
vendor/github.com/tetratelabs/wazero/api/wasm.go
generated
vendored
Normal file
@@ -0,0 +1,766 @@
|
|||||||
|
// Package api includes constants and interfaces used by both end-users and internal implementations.
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
|
||||||
|
"github.com/tetratelabs/wazero/internal/internalapi"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ExternType classifies imports and exports with their respective types.
|
||||||
|
//
|
||||||
|
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#external-types%E2%91%A0
|
||||||
|
type ExternType = byte
|
||||||
|
|
||||||
|
const (
|
||||||
|
ExternTypeFunc ExternType = 0x00
|
||||||
|
ExternTypeTable ExternType = 0x01
|
||||||
|
ExternTypeMemory ExternType = 0x02
|
||||||
|
ExternTypeGlobal ExternType = 0x03
|
||||||
|
)
|
||||||
|
|
||||||
|
// The below are exported to consolidate parsing behavior for external types.
|
||||||
|
const (
|
||||||
|
// ExternTypeFuncName is the name of the WebAssembly 1.0 (20191205) Text Format field for ExternTypeFunc.
|
||||||
|
ExternTypeFuncName = "func"
|
||||||
|
// ExternTypeTableName is the name of the WebAssembly 1.0 (20191205) Text Format field for ExternTypeTable.
|
||||||
|
ExternTypeTableName = "table"
|
||||||
|
// ExternTypeMemoryName is the name of the WebAssembly 1.0 (20191205) Text Format field for ExternTypeMemory.
|
||||||
|
ExternTypeMemoryName = "memory"
|
||||||
|
// ExternTypeGlobalName is the name of the WebAssembly 1.0 (20191205) Text Format field for ExternTypeGlobal.
|
||||||
|
ExternTypeGlobalName = "global"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ExternTypeName returns the name of the WebAssembly 1.0 (20191205) Text Format field of the given type.
|
||||||
|
//
|
||||||
|
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#exports%E2%91%A4
|
||||||
|
func ExternTypeName(et ExternType) string {
|
||||||
|
switch et {
|
||||||
|
case ExternTypeFunc:
|
||||||
|
return ExternTypeFuncName
|
||||||
|
case ExternTypeTable:
|
||||||
|
return ExternTypeTableName
|
||||||
|
case ExternTypeMemory:
|
||||||
|
return ExternTypeMemoryName
|
||||||
|
case ExternTypeGlobal:
|
||||||
|
return ExternTypeGlobalName
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%#x", et)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValueType describes a parameter or result type mapped to a WebAssembly
|
||||||
|
// function signature.
|
||||||
|
//
|
||||||
|
// The following describes how to convert between Wasm and Golang types:
|
||||||
|
//
|
||||||
|
// - ValueTypeI32 - EncodeU32 DecodeU32 for uint32 / EncodeI32 DecodeI32 for int32
|
||||||
|
// - ValueTypeI64 - uint64(int64)
|
||||||
|
// - ValueTypeF32 - EncodeF32 DecodeF32 from float32
|
||||||
|
// - ValueTypeF64 - EncodeF64 DecodeF64 from float64
|
||||||
|
// - ValueTypeExternref - unintptr(unsafe.Pointer(p)) where p is any pointer
|
||||||
|
// type in Go (e.g. *string)
|
||||||
|
//
|
||||||
|
// e.g. Given a Text Format type use (param i64) (result i64), no conversion is
|
||||||
|
// necessary.
|
||||||
|
//
|
||||||
|
// results, _ := fn(ctx, input)
|
||||||
|
// result := result[0]
|
||||||
|
//
|
||||||
|
// e.g. Given a Text Format type use (param f64) (result f64), conversion is
|
||||||
|
// necessary.
|
||||||
|
//
|
||||||
|
// results, _ := fn(ctx, api.EncodeF64(input))
|
||||||
|
// result := api.DecodeF64(result[0])
|
||||||
|
//
|
||||||
|
// Note: This is a type alias as it is easier to encode and decode in the
|
||||||
|
// binary format.
|
||||||
|
//
|
||||||
|
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-valtype
|
||||||
|
type ValueType = byte
|
||||||
|
|
||||||
|
const (
|
||||||
|
// ValueTypeI32 is a 32-bit integer.
|
||||||
|
ValueTypeI32 ValueType = 0x7f
|
||||||
|
// ValueTypeI64 is a 64-bit integer.
|
||||||
|
ValueTypeI64 ValueType = 0x7e
|
||||||
|
// ValueTypeF32 is a 32-bit floating point number.
|
||||||
|
ValueTypeF32 ValueType = 0x7d
|
||||||
|
// ValueTypeF64 is a 64-bit floating point number.
|
||||||
|
ValueTypeF64 ValueType = 0x7c
|
||||||
|
|
||||||
|
// ValueTypeExternref is a externref type.
|
||||||
|
//
|
||||||
|
// Note: in wazero, externref type value are opaque raw 64-bit pointers,
|
||||||
|
// and the ValueTypeExternref type in the signature will be translated as
|
||||||
|
// uintptr in wazero's API level.
|
||||||
|
//
|
||||||
|
// For example, given the import function:
|
||||||
|
// (func (import "env" "f") (param externref) (result externref))
|
||||||
|
//
|
||||||
|
// This can be defined in Go as:
|
||||||
|
// r.NewHostModuleBuilder("env").
|
||||||
|
// NewFunctionBuilder().
|
||||||
|
// WithFunc(func(context.Context, _ uintptr) (_ uintptr) { return }).
|
||||||
|
// Export("f")
|
||||||
|
//
|
||||||
|
// Note: The usage of this type is toggled with api.CoreFeatureBulkMemoryOperations.
|
||||||
|
ValueTypeExternref ValueType = 0x6f
|
||||||
|
)
|
||||||
|
|
||||||
|
// ValueTypeName returns the type name of the given ValueType as a string.
|
||||||
|
// These type names match the names used in the WebAssembly text format.
|
||||||
|
//
|
||||||
|
// Note: This returns "unknown", if an undefined ValueType value is passed.
|
||||||
|
func ValueTypeName(t ValueType) string {
|
||||||
|
switch t {
|
||||||
|
case ValueTypeI32:
|
||||||
|
return "i32"
|
||||||
|
case ValueTypeI64:
|
||||||
|
return "i64"
|
||||||
|
case ValueTypeF32:
|
||||||
|
return "f32"
|
||||||
|
case ValueTypeF64:
|
||||||
|
return "f64"
|
||||||
|
case ValueTypeExternref:
|
||||||
|
return "externref"
|
||||||
|
}
|
||||||
|
return "unknown"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Module is a sandboxed, ready to execute Wasm module. This can be used to get exported functions, etc.
|
||||||
|
//
|
||||||
|
// In WebAssembly terminology, this corresponds to a "Module Instance", but wazero calls pre-instantiation module as
|
||||||
|
// "Compiled Module" as in wazero.CompiledModule, therefore we call this post-instantiation module simply "Module".
|
||||||
|
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#module-instances%E2%91%A0
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// - This is an interface for decoupling, not third-party implementations.
|
||||||
|
// All implementations are in wazero.
|
||||||
|
// - Closing the wazero.Runtime closes any Module it instantiated.
|
||||||
|
type Module interface {
|
||||||
|
fmt.Stringer
|
||||||
|
|
||||||
|
// Name is the name this module was instantiated with. Exported functions can be imported with this name.
|
||||||
|
Name() string
|
||||||
|
|
||||||
|
// Memory returns a memory defined in this module or nil if there are none wasn't.
|
||||||
|
Memory() Memory
|
||||||
|
|
||||||
|
// ExportedFunction returns a function exported from this module or nil if it wasn't.
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
// - The default wazero.ModuleConfig attempts to invoke `_start`, which
|
||||||
|
// in rare cases can close the module. When in doubt, check IsClosed prior
|
||||||
|
// to invoking a function export after instantiation.
|
||||||
|
// - The semantics of host functions assumes the existence of an "importing module" because, for example, the host function needs access to
|
||||||
|
// the memory of the importing module. Therefore, direct use of ExportedFunction is forbidden for host modules.
|
||||||
|
// Practically speaking, it is usually meaningless to directly call a host function from Go code as it is already somewhere in Go code.
|
||||||
|
ExportedFunction(name string) Function
|
||||||
|
|
||||||
|
// ExportedFunctionDefinitions returns all the exported function
|
||||||
|
// definitions in this module, keyed on export name.
|
||||||
|
ExportedFunctionDefinitions() map[string]FunctionDefinition
|
||||||
|
|
||||||
|
// TODO: Table
|
||||||
|
|
||||||
|
// ExportedMemory returns a memory exported from this module or nil if it wasn't.
|
||||||
|
//
|
||||||
|
// WASI modules require exporting a Memory named "memory". This means that a module successfully initialized
|
||||||
|
// as a WASI Command or Reactor will never return nil for this name.
|
||||||
|
//
|
||||||
|
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/design/application-abi.md#current-unstable-abi
|
||||||
|
ExportedMemory(name string) Memory
|
||||||
|
|
||||||
|
// ExportedMemoryDefinitions returns all the exported memory definitions
|
||||||
|
// in this module, keyed on export name.
|
||||||
|
//
|
||||||
|
// Note: As of WebAssembly Core Specification 2.0, there can be at most one
|
||||||
|
// memory.
|
||||||
|
ExportedMemoryDefinitions() map[string]MemoryDefinition
|
||||||
|
|
||||||
|
// ExportedGlobal a global exported from this module or nil if it wasn't.
|
||||||
|
ExportedGlobal(name string) Global
|
||||||
|
|
||||||
|
// CloseWithExitCode releases resources allocated for this Module. Use a non-zero exitCode parameter to indicate a
|
||||||
|
// failure to ExportedFunction callers.
|
||||||
|
//
|
||||||
|
// The error returned here, if present, is about resource de-allocation (such as I/O errors). Only the last error is
|
||||||
|
// returned, so a non-nil return means at least one error happened. Regardless of error, this Module will
|
||||||
|
// be removed, making its name available again.
|
||||||
|
//
|
||||||
|
// Calling this inside a host function is safe, and may cause ExportedFunction callers to receive a sys.ExitError
|
||||||
|
// with the exitCode.
|
||||||
|
CloseWithExitCode(ctx context.Context, exitCode uint32) error
|
||||||
|
|
||||||
|
// Closer closes this module by delegating to CloseWithExitCode with an exit code of zero.
|
||||||
|
Closer
|
||||||
|
|
||||||
|
// IsClosed returns true if the module is closed, so no longer usable.
|
||||||
|
//
|
||||||
|
// This can happen for the following reasons:
|
||||||
|
// - Closer was called directly.
|
||||||
|
// - A guest function called Closer indirectly, such as `_start` calling
|
||||||
|
// `proc_exit`, which internally closed the module.
|
||||||
|
// - wazero.RuntimeConfig `WithCloseOnContextDone` was enabled and a
|
||||||
|
// context completion closed the module.
|
||||||
|
//
|
||||||
|
// Where any of the above are possible, check this value before calling an
|
||||||
|
// ExportedFunction, even if you didn't formerly receive a sys.ExitError.
|
||||||
|
// sys.ExitError is only returned on non-zero code, something that closes
|
||||||
|
// the module successfully will not result it one.
|
||||||
|
IsClosed() bool
|
||||||
|
|
||||||
|
internalapi.WazeroOnly
|
||||||
|
}
|
||||||
|
|
||||||
|
// Closer closes a resource.
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// - This is an interface for decoupling, not third-party implementations.
|
||||||
|
// All implementations are in wazero.
|
||||||
|
type Closer interface {
|
||||||
|
// Close closes the resource.
|
||||||
|
//
|
||||||
|
// Note: The context parameter is used for value lookup, such as for
|
||||||
|
// logging. A canceled or otherwise done context will not prevent Close
|
||||||
|
// from succeeding.
|
||||||
|
Close(context.Context) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExportDefinition is a WebAssembly type exported in a module
|
||||||
|
// (wazero.CompiledModule).
|
||||||
|
//
|
||||||
|
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#exports%E2%91%A0
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// - This is an interface for decoupling, not third-party implementations.
|
||||||
|
// All implementations are in wazero.
|
||||||
|
type ExportDefinition interface {
|
||||||
|
// ModuleName is the possibly empty name of the module defining this
|
||||||
|
// export.
|
||||||
|
//
|
||||||
|
// Note: This may be different from Module.Name, because a compiled module
|
||||||
|
// can be instantiated multiple times as different names.
|
||||||
|
ModuleName() string
|
||||||
|
|
||||||
|
// Index is the position in the module's index, imports first.
|
||||||
|
Index() uint32
|
||||||
|
|
||||||
|
// Import returns true with the module and name when this was imported.
|
||||||
|
// Otherwise, it returns false.
|
||||||
|
//
|
||||||
|
// Note: Empty string is valid for both names in the WebAssembly Core
|
||||||
|
// Specification, so "" "" is possible.
|
||||||
|
Import() (moduleName, name string, isImport bool)
|
||||||
|
|
||||||
|
// ExportNames include all exported names.
|
||||||
|
//
|
||||||
|
// Note: The empty name is allowed in the WebAssembly Core Specification,
|
||||||
|
// so "" is possible.
|
||||||
|
ExportNames() []string
|
||||||
|
|
||||||
|
internalapi.WazeroOnly
|
||||||
|
}
|
||||||
|
|
||||||
|
// MemoryDefinition is a WebAssembly memory exported in a module
|
||||||
|
// (wazero.CompiledModule). Units are in pages (64KB).
|
||||||
|
//
|
||||||
|
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#exports%E2%91%A0
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// - This is an interface for decoupling, not third-party implementations.
|
||||||
|
// All implementations are in wazero.
|
||||||
|
type MemoryDefinition interface {
|
||||||
|
ExportDefinition
|
||||||
|
|
||||||
|
// Min returns the possibly zero initial count of 64KB pages.
|
||||||
|
Min() uint32
|
||||||
|
|
||||||
|
// Max returns the possibly zero max count of 64KB pages, or false if
|
||||||
|
// unbounded.
|
||||||
|
Max() (uint32, bool)
|
||||||
|
|
||||||
|
internalapi.WazeroOnly
|
||||||
|
}
|
||||||
|
|
||||||
|
// FunctionDefinition is a WebAssembly function exported in a module
|
||||||
|
// (wazero.CompiledModule).
|
||||||
|
//
|
||||||
|
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#exports%E2%91%A0
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// - This is an interface for decoupling, not third-party implementations.
|
||||||
|
// All implementations are in wazero.
|
||||||
|
type FunctionDefinition interface {
|
||||||
|
ExportDefinition
|
||||||
|
|
||||||
|
// Name is the module-defined name of the function, which is not necessarily
|
||||||
|
// the same as its export name.
|
||||||
|
Name() string
|
||||||
|
|
||||||
|
// DebugName identifies this function based on its Index or Name in the
|
||||||
|
// module. This is used for errors and stack traces. e.g. "env.abort".
|
||||||
|
//
|
||||||
|
// When the function name is empty, a substitute name is generated by
|
||||||
|
// prefixing '$' to its position in the index. Ex ".$0" is the
|
||||||
|
// first function (possibly imported) in an unnamed module.
|
||||||
|
//
|
||||||
|
// The format is dot-delimited module and function name, but there are no
|
||||||
|
// restrictions on the module and function name. This means either can be
|
||||||
|
// empty or include dots. e.g. "x.x.x" could mean module "x" and name "x.x",
|
||||||
|
// or it could mean module "x.x" and name "x".
|
||||||
|
//
|
||||||
|
// Note: This name is stable regardless of import or export. For example,
|
||||||
|
// if Import returns true, the value is still based on the Name or Index
|
||||||
|
// and not the imported function name.
|
||||||
|
DebugName() string
|
||||||
|
|
||||||
|
// GoFunction is non-nil when implemented by the embedder instead of a wasm
|
||||||
|
// binary, e.g. via wazero.HostModuleBuilder
|
||||||
|
//
|
||||||
|
// The expected results are nil, GoFunction or GoModuleFunction.
|
||||||
|
GoFunction() interface{}
|
||||||
|
|
||||||
|
// ParamTypes are the possibly empty sequence of value types accepted by a
|
||||||
|
// function with this signature.
|
||||||
|
//
|
||||||
|
// See ValueType documentation for encoding rules.
|
||||||
|
ParamTypes() []ValueType
|
||||||
|
|
||||||
|
// ParamNames are index-correlated with ParamTypes or nil if not available
|
||||||
|
// for one or more parameters.
|
||||||
|
ParamNames() []string
|
||||||
|
|
||||||
|
// ResultTypes are the results of the function.
|
||||||
|
//
|
||||||
|
// When WebAssembly 1.0 (20191205), there can be at most one result.
|
||||||
|
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#result-types%E2%91%A0
|
||||||
|
//
|
||||||
|
// See ValueType documentation for encoding rules.
|
||||||
|
ResultTypes() []ValueType
|
||||||
|
|
||||||
|
// ResultNames are index-correlated with ResultTypes or nil if not
|
||||||
|
// available for one or more results.
|
||||||
|
ResultNames() []string
|
||||||
|
|
||||||
|
internalapi.WazeroOnly
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function is a WebAssembly function exported from an instantiated module
|
||||||
|
// (wazero.Runtime InstantiateModule).
|
||||||
|
//
|
||||||
|
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#syntax-func
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// - This is an interface for decoupling, not third-party implementations.
|
||||||
|
// All implementations are in wazero.
|
||||||
|
type Function interface {
|
||||||
|
// Definition is metadata about this function from its defining module.
|
||||||
|
Definition() FunctionDefinition
|
||||||
|
|
||||||
|
// Call invokes the function with the given parameters and returns any
|
||||||
|
// results or an error for any failure looking up or invoking the function.
|
||||||
|
//
|
||||||
|
// Encoding is described in Definition, and supplying an incorrect count of
|
||||||
|
// parameters vs FunctionDefinition.ParamTypes is an error.
|
||||||
|
//
|
||||||
|
// If the exporting Module was closed during this call, the error returned
|
||||||
|
// may be a sys.ExitError. See Module.CloseWithExitCode for details.
|
||||||
|
//
|
||||||
|
// Call is not goroutine-safe, therefore it is recommended to create
|
||||||
|
// another Function if you want to invoke the same function concurrently.
|
||||||
|
// On the other hand, sequential invocations of Call is allowed.
|
||||||
|
// However, this should not be called multiple times until the previous Call returns.
|
||||||
|
//
|
||||||
|
// To safely encode/decode params/results expressed as uint64, users are encouraged to
|
||||||
|
// use api.EncodeXXX or DecodeXXX functions. See the docs on api.ValueType.
|
||||||
|
//
|
||||||
|
// When RuntimeConfig.WithCloseOnContextDone is toggled, the invocation of this Call method is ensured to be closed
|
||||||
|
// whenever one of the three conditions is met. In the event of close, sys.ExitError will be returned and
|
||||||
|
// the api.Module from which this api.Function is derived will be made closed. See the documentation of
|
||||||
|
// WithCloseOnContextDone on wazero.RuntimeConfig for detail. See examples in context_done_example_test.go for
|
||||||
|
// the end-to-end demonstrations of how these terminations can be performed.
|
||||||
|
Call(ctx context.Context, params ...uint64) ([]uint64, error)
|
||||||
|
|
||||||
|
// CallWithStack is an optimized variation of Call that saves memory
|
||||||
|
// allocations when the stack slice is reused across calls.
|
||||||
|
//
|
||||||
|
// Stack length must be at least the max of parameter or result length.
|
||||||
|
// The caller adds parameters in order to the stack, and reads any results
|
||||||
|
// in order from the stack, except in the error case.
|
||||||
|
//
|
||||||
|
// For example, the following reuses the same stack slice to call searchFn
|
||||||
|
// repeatedly saving one allocation per iteration:
|
||||||
|
//
|
||||||
|
// stack := make([]uint64, 4)
|
||||||
|
// for i, search := range searchParams {
|
||||||
|
// // copy the next params to the stack
|
||||||
|
// copy(stack, search)
|
||||||
|
// if err := searchFn.CallWithStack(ctx, stack); err != nil {
|
||||||
|
// return err
|
||||||
|
// } else if stack[0] == 1 { // found
|
||||||
|
// return i // searchParams[i] matched!
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// - This is similar to GoModuleFunction, except for using calling functions
|
||||||
|
// instead of implementing them. Moreover, this is used regardless of
|
||||||
|
// whether the callee is a host or wasm defined function.
|
||||||
|
CallWithStack(ctx context.Context, stack []uint64) error
|
||||||
|
|
||||||
|
internalapi.WazeroOnly
|
||||||
|
}
|
||||||
|
|
||||||
|
// GoModuleFunction is a Function implemented in Go instead of a wasm binary.
|
||||||
|
// The Module parameter is the calling module, used to access memory or
|
||||||
|
// exported functions. See GoModuleFunc for an example.
|
||||||
|
//
|
||||||
|
// The stack is includes any parameters encoded according to their ValueType.
|
||||||
|
// Its length is the max of parameter or result length. When there are results,
|
||||||
|
// write them in order beginning at index zero. Do not use the stack after the
|
||||||
|
// function returns.
|
||||||
|
//
|
||||||
|
// Here's a typical way to read three parameters and write back one.
|
||||||
|
//
|
||||||
|
// // read parameters off the stack in index order
|
||||||
|
// argv, argvBuf := api.DecodeU32(stack[0]), api.DecodeU32(stack[1])
|
||||||
|
//
|
||||||
|
// // write results back to the stack in index order
|
||||||
|
// stack[0] = api.EncodeU32(ErrnoSuccess)
|
||||||
|
//
|
||||||
|
// This function can be non-deterministic or cause side effects. It also
|
||||||
|
// has special properties not defined in the WebAssembly Core specification.
|
||||||
|
// Notably, this uses the caller's memory (via Module.Memory). See
|
||||||
|
// https://www.w3.org/TR/wasm-core-1/#host-functions%E2%91%A0
|
||||||
|
//
|
||||||
|
// Most end users will not define functions directly with this, as they will
|
||||||
|
// use reflection or code generators instead. These approaches are more
|
||||||
|
// idiomatic as they can map go types to ValueType. This type is exposed for
|
||||||
|
// those willing to trade usability and safety for performance.
|
||||||
|
//
|
||||||
|
// To safely decode/encode values from/to the uint64 stack, users are encouraged to use
|
||||||
|
// api.EncodeXXX or api.DecodeXXX functions. See the docs on api.ValueType.
|
||||||
|
type GoModuleFunction interface {
|
||||||
|
Call(ctx context.Context, mod Module, stack []uint64)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GoModuleFunc is a convenience for defining an inlined function.
|
||||||
|
//
|
||||||
|
// For example, the following returns an uint32 value read from parameter zero:
|
||||||
|
//
|
||||||
|
// api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {
|
||||||
|
// offset := api.DecodeU32(stack[0]) // read the parameter from the stack
|
||||||
|
//
|
||||||
|
// ret, ok := mod.Memory().ReadUint32Le(offset)
|
||||||
|
// if !ok {
|
||||||
|
// panic("out of memory")
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// stack[0] = api.EncodeU32(ret) // add the result back to the stack.
|
||||||
|
// })
|
||||||
|
type GoModuleFunc func(ctx context.Context, mod Module, stack []uint64)
|
||||||
|
|
||||||
|
// Call implements GoModuleFunction.Call.
|
||||||
|
func (f GoModuleFunc) Call(ctx context.Context, mod Module, stack []uint64) {
|
||||||
|
f(ctx, mod, stack)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GoFunction is an optimized form of GoModuleFunction which doesn't require
|
||||||
|
// the Module parameter. See GoFunc for an example.
|
||||||
|
//
|
||||||
|
// For example, this function does not need to use the importing module's
|
||||||
|
// memory or exported functions.
|
||||||
|
type GoFunction interface {
|
||||||
|
Call(ctx context.Context, stack []uint64)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GoFunc is a convenience for defining an inlined function.
|
||||||
|
//
|
||||||
|
// For example, the following returns the sum of two uint32 parameters:
|
||||||
|
//
|
||||||
|
// api.GoFunc(func(ctx context.Context, stack []uint64) {
|
||||||
|
// x, y := api.DecodeU32(stack[0]), api.DecodeU32(stack[1])
|
||||||
|
// stack[0] = api.EncodeU32(x + y)
|
||||||
|
// })
|
||||||
|
type GoFunc func(ctx context.Context, stack []uint64)
|
||||||
|
|
||||||
|
// Call implements GoFunction.Call.
|
||||||
|
func (f GoFunc) Call(ctx context.Context, stack []uint64) {
|
||||||
|
f(ctx, stack)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Global is a WebAssembly 1.0 (20191205) global exported from an instantiated module (wazero.Runtime InstantiateModule).
|
||||||
|
//
|
||||||
|
// For example, if the value is not mutable, you can read it once:
|
||||||
|
//
|
||||||
|
// offset := module.ExportedGlobal("memory.offset").Get()
|
||||||
|
//
|
||||||
|
// Globals are allowed by specification to be mutable. However, this can be disabled by configuration. When in doubt,
|
||||||
|
// safe cast to find out if the value can change. Here's an example:
|
||||||
|
//
|
||||||
|
// offset := module.ExportedGlobal("memory.offset")
|
||||||
|
// if _, ok := offset.(api.MutableGlobal); ok {
|
||||||
|
// // value can change
|
||||||
|
// } else {
|
||||||
|
// // value is constant
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#globals%E2%91%A0
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// - This is an interface for decoupling, not third-party implementations.
|
||||||
|
// All implementations are in wazero.
|
||||||
|
type Global interface {
|
||||||
|
fmt.Stringer
|
||||||
|
|
||||||
|
// Type describes the numeric type of the global.
|
||||||
|
Type() ValueType
|
||||||
|
|
||||||
|
// Get returns the last known value of this global.
|
||||||
|
//
|
||||||
|
// See Type for how to decode this value to a Go type.
|
||||||
|
Get() uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
// MutableGlobal is a Global whose value can be updated at runtime (variable).
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// - This is an interface for decoupling, not third-party implementations.
|
||||||
|
// All implementations are in wazero.
|
||||||
|
type MutableGlobal interface {
|
||||||
|
Global
|
||||||
|
|
||||||
|
// Set updates the value of this global.
|
||||||
|
//
|
||||||
|
// See Global.Type for how to encode this value from a Go type.
|
||||||
|
Set(v uint64)
|
||||||
|
|
||||||
|
internalapi.WazeroOnly
|
||||||
|
}
|
||||||
|
|
||||||
|
// Memory allows restricted access to a module's memory. Notably, this does not allow growing.
|
||||||
|
//
|
||||||
|
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#storage%E2%91%A0
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// - This is an interface for decoupling, not third-party implementations.
|
||||||
|
// All implementations are in wazero.
|
||||||
|
// - This includes all value types available in WebAssembly 1.0 (20191205) and all are encoded little-endian.
|
||||||
|
type Memory interface {
|
||||||
|
// Definition is metadata about this memory from its defining module.
|
||||||
|
Definition() MemoryDefinition
|
||||||
|
|
||||||
|
// Size returns the memory size in bytes available.
|
||||||
|
// e.g. If the underlying memory has 1 page: 65536
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// - This overflows (returns zero) if the memory has the maximum 65536 pages.
|
||||||
|
// As a workaround until wazero v2 to fix the return type, use Grow(0) to obtain the current pages and
|
||||||
|
// multiply by 65536.
|
||||||
|
//
|
||||||
|
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#-hrefsyntax-instr-memorymathsfmemorysize%E2%91%A0
|
||||||
|
Size() uint32
|
||||||
|
|
||||||
|
// Grow increases memory by the delta in pages (65536 bytes per page).
|
||||||
|
// The return val is the previous memory size in pages, or false if the
|
||||||
|
// delta was ignored as it exceeds MemoryDefinition.Max.
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// - This is the same as the "memory.grow" instruction defined in the
|
||||||
|
// WebAssembly Core Specification, except returns false instead of -1.
|
||||||
|
// - When this returns true, any shared views via Read must be refreshed.
|
||||||
|
//
|
||||||
|
// See MemorySizer Read and https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#grow-mem
|
||||||
|
Grow(deltaPages uint32) (previousPages uint32, ok bool)
|
||||||
|
|
||||||
|
// ReadByte reads a single byte from the underlying buffer at the offset or returns false if out of range.
|
||||||
|
ReadByte(offset uint32) (byte, bool)
|
||||||
|
|
||||||
|
// ReadUint16Le reads a uint16 in little-endian encoding from the underlying buffer at the offset in or returns
|
||||||
|
// false if out of range.
|
||||||
|
ReadUint16Le(offset uint32) (uint16, bool)
|
||||||
|
|
||||||
|
// ReadUint32Le reads a uint32 in little-endian encoding from the underlying buffer at the offset in or returns
|
||||||
|
// false if out of range.
|
||||||
|
ReadUint32Le(offset uint32) (uint32, bool)
|
||||||
|
|
||||||
|
// ReadFloat32Le reads a float32 from 32 IEEE 754 little-endian encoded bits in the underlying buffer at the offset
|
||||||
|
// or returns false if out of range.
|
||||||
|
// See math.Float32bits
|
||||||
|
ReadFloat32Le(offset uint32) (float32, bool)
|
||||||
|
|
||||||
|
// ReadUint64Le reads a uint64 in little-endian encoding from the underlying buffer at the offset or returns false
|
||||||
|
// if out of range.
|
||||||
|
ReadUint64Le(offset uint32) (uint64, bool)
|
||||||
|
|
||||||
|
// ReadFloat64Le reads a float64 from 64 IEEE 754 little-endian encoded bits in the underlying buffer at the offset
|
||||||
|
// or returns false if out of range.
|
||||||
|
//
|
||||||
|
// See math.Float64bits
|
||||||
|
ReadFloat64Le(offset uint32) (float64, bool)
|
||||||
|
|
||||||
|
// Read reads byteCount bytes from the underlying buffer at the offset or
|
||||||
|
// returns false if out of range.
|
||||||
|
//
|
||||||
|
// For example, to search for a NUL-terminated string:
|
||||||
|
// buf, _ = memory.Read(offset, byteCount)
|
||||||
|
// n := bytes.IndexByte(buf, 0)
|
||||||
|
// if n < 0 {
|
||||||
|
// // Not found!
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Write-through
|
||||||
|
//
|
||||||
|
// This returns a view of the underlying memory, not a copy. This means any
|
||||||
|
// writes to the slice returned are visible to Wasm, and any updates from
|
||||||
|
// Wasm are visible reading the returned slice.
|
||||||
|
//
|
||||||
|
// For example:
|
||||||
|
// buf, _ = memory.Read(offset, byteCount)
|
||||||
|
// buf[1] = 'a' // writes through to memory, meaning Wasm code see 'a'.
|
||||||
|
//
|
||||||
|
// If you don't intend-write through, make a copy of the returned slice.
|
||||||
|
//
|
||||||
|
// When to refresh Read
|
||||||
|
//
|
||||||
|
// The returned slice disconnects on any capacity change. For example,
|
||||||
|
// `buf = append(buf, 'a')` might result in a slice that is no longer
|
||||||
|
// shared. The same exists Wasm side. For example, if Wasm changes its
|
||||||
|
// memory capacity, ex via "memory.grow"), the host slice is no longer
|
||||||
|
// shared. Those who need a stable view must set Wasm memory min=max, or
|
||||||
|
// use wazero.RuntimeConfig WithMemoryCapacityPages to ensure max is always
|
||||||
|
// allocated.
|
||||||
|
Read(offset, byteCount uint32) ([]byte, bool)
|
||||||
|
|
||||||
|
// WriteByte writes a single byte to the underlying buffer at the offset in or returns false if out of range.
|
||||||
|
WriteByte(offset uint32, v byte) bool
|
||||||
|
|
||||||
|
// WriteUint16Le writes the value in little-endian encoding to the underlying buffer at the offset in or returns
|
||||||
|
// false if out of range.
|
||||||
|
WriteUint16Le(offset uint32, v uint16) bool
|
||||||
|
|
||||||
|
// WriteUint32Le writes the value in little-endian encoding to the underlying buffer at the offset in or returns
|
||||||
|
// false if out of range.
|
||||||
|
WriteUint32Le(offset, v uint32) bool
|
||||||
|
|
||||||
|
// WriteFloat32Le writes the value in 32 IEEE 754 little-endian encoded bits to the underlying buffer at the offset
|
||||||
|
// or returns false if out of range.
|
||||||
|
//
|
||||||
|
// See math.Float32bits
|
||||||
|
WriteFloat32Le(offset uint32, v float32) bool
|
||||||
|
|
||||||
|
// WriteUint64Le writes the value in little-endian encoding to the underlying buffer at the offset in or returns
|
||||||
|
// false if out of range.
|
||||||
|
WriteUint64Le(offset uint32, v uint64) bool
|
||||||
|
|
||||||
|
// WriteFloat64Le writes the value in 64 IEEE 754 little-endian encoded bits to the underlying buffer at the offset
|
||||||
|
// or returns false if out of range.
|
||||||
|
//
|
||||||
|
// See math.Float64bits
|
||||||
|
WriteFloat64Le(offset uint32, v float64) bool
|
||||||
|
|
||||||
|
// Write writes the slice to the underlying buffer at the offset or returns false if out of range.
|
||||||
|
Write(offset uint32, v []byte) bool
|
||||||
|
|
||||||
|
// WriteString writes the string to the underlying buffer at the offset or returns false if out of range.
|
||||||
|
WriteString(offset uint32, v string) bool
|
||||||
|
|
||||||
|
internalapi.WazeroOnly
|
||||||
|
}
|
||||||
|
|
||||||
|
// CustomSection contains the name and raw data of a custom section.
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// - This is an interface for decoupling, not third-party implementations.
|
||||||
|
// All implementations are in wazero.
|
||||||
|
type CustomSection interface {
|
||||||
|
// Name is the name of the custom section
|
||||||
|
Name() string
|
||||||
|
// Data is the raw data of the custom section
|
||||||
|
Data() []byte
|
||||||
|
|
||||||
|
internalapi.WazeroOnly
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncodeExternref encodes the input as a ValueTypeExternref.
|
||||||
|
//
|
||||||
|
// See DecodeExternref
|
||||||
|
func EncodeExternref(input uintptr) uint64 {
|
||||||
|
return uint64(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecodeExternref decodes the input as a ValueTypeExternref.
|
||||||
|
//
|
||||||
|
// See EncodeExternref
|
||||||
|
func DecodeExternref(input uint64) uintptr {
|
||||||
|
return uintptr(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncodeI32 encodes the input as a ValueTypeI32.
|
||||||
|
func EncodeI32(input int32) uint64 {
|
||||||
|
return uint64(uint32(input))
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecodeI32 decodes the input as a ValueTypeI32.
|
||||||
|
func DecodeI32(input uint64) int32 {
|
||||||
|
return int32(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncodeU32 encodes the input as a ValueTypeI32.
|
||||||
|
func EncodeU32(input uint32) uint64 {
|
||||||
|
return uint64(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecodeU32 decodes the input as a ValueTypeI32.
|
||||||
|
func DecodeU32(input uint64) uint32 {
|
||||||
|
return uint32(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncodeI64 encodes the input as a ValueTypeI64.
|
||||||
|
func EncodeI64(input int64) uint64 {
|
||||||
|
return uint64(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncodeF32 encodes the input as a ValueTypeF32.
|
||||||
|
//
|
||||||
|
// See DecodeF32
|
||||||
|
func EncodeF32(input float32) uint64 {
|
||||||
|
return uint64(math.Float32bits(input))
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecodeF32 decodes the input as a ValueTypeF32.
|
||||||
|
//
|
||||||
|
// See EncodeF32
|
||||||
|
func DecodeF32(input uint64) float32 {
|
||||||
|
return math.Float32frombits(uint32(input))
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncodeF64 encodes the input as a ValueTypeF64.
|
||||||
|
//
|
||||||
|
// See EncodeF32
|
||||||
|
func EncodeF64(input float64) uint64 {
|
||||||
|
return math.Float64bits(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecodeF64 decodes the input as a ValueTypeF64.
|
||||||
|
//
|
||||||
|
// See EncodeF64
|
||||||
|
func DecodeF64(input uint64) float64 {
|
||||||
|
return math.Float64frombits(input)
|
||||||
|
}
|
||||||
367
vendor/github.com/tetratelabs/wazero/builder.go
generated
vendored
Normal file
367
vendor/github.com/tetratelabs/wazero/builder.go
generated
vendored
Normal file
@@ -0,0 +1,367 @@
|
|||||||
|
package wazero
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/tetratelabs/wazero/api"
|
||||||
|
"github.com/tetratelabs/wazero/internal/wasm"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HostFunctionBuilder defines a host function (in Go), so that a
|
||||||
|
// WebAssembly binary (e.g. %.wasm file) can import and use it.
|
||||||
|
//
|
||||||
|
// Here's an example of an addition function:
|
||||||
|
//
|
||||||
|
// hostModuleBuilder.NewFunctionBuilder().
|
||||||
|
// WithFunc(func(cxt context.Context, x, y uint32) uint32 {
|
||||||
|
// return x + y
|
||||||
|
// }).
|
||||||
|
// Export("add")
|
||||||
|
//
|
||||||
|
// # Memory
|
||||||
|
//
|
||||||
|
// All host functions act on the importing api.Module, including any memory
|
||||||
|
// exported in its binary (%.wasm file). If you are reading or writing memory,
|
||||||
|
// it is sand-boxed Wasm memory defined by the guest.
|
||||||
|
//
|
||||||
|
// Below, `m` is the importing module, defined in Wasm. `fn` is a host function
|
||||||
|
// added via Export. This means that `x` was read from memory defined in Wasm,
|
||||||
|
// not arbitrary memory in the process.
|
||||||
|
//
|
||||||
|
// fn := func(ctx context.Context, m api.Module, offset uint32) uint32 {
|
||||||
|
// x, _ := m.Memory().ReadUint32Le(ctx, offset)
|
||||||
|
// return x
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// - This is an interface for decoupling, not third-party implementations.
|
||||||
|
// All implementations are in wazero.
|
||||||
|
type HostFunctionBuilder interface {
|
||||||
|
// WithGoFunction is an advanced feature for those who need higher
|
||||||
|
// performance than WithFunc at the cost of more complexity.
|
||||||
|
//
|
||||||
|
// Here's an example addition function:
|
||||||
|
//
|
||||||
|
// builder.WithGoFunction(api.GoFunc(func(ctx context.Context, stack []uint64) {
|
||||||
|
// x, y := api.DecodeI32(stack[0]), api.DecodeI32(stack[1])
|
||||||
|
// sum := x + y
|
||||||
|
// stack[0] = api.EncodeI32(sum)
|
||||||
|
// }), []api.ValueType{api.ValueTypeI32, api.ValueTypeI32}, []api.ValueType{api.ValueTypeI32})
|
||||||
|
//
|
||||||
|
// As you can see above, defining in this way implies knowledge of which
|
||||||
|
// WebAssembly api.ValueType is appropriate for each parameter and result.
|
||||||
|
//
|
||||||
|
// See WithGoModuleFunction if you also need to access the calling module.
|
||||||
|
WithGoFunction(fn api.GoFunction, params, results []api.ValueType) HostFunctionBuilder
|
||||||
|
|
||||||
|
// WithGoModuleFunction is an advanced feature for those who need higher
|
||||||
|
// performance than WithFunc at the cost of more complexity.
|
||||||
|
//
|
||||||
|
// Here's an example addition function that loads operands from memory:
|
||||||
|
//
|
||||||
|
// builder.WithGoModuleFunction(api.GoModuleFunc(func(ctx context.Context, m api.Module, stack []uint64) {
|
||||||
|
// mem := m.Memory()
|
||||||
|
// offset := api.DecodeU32(stack[0])
|
||||||
|
//
|
||||||
|
// x, _ := mem.ReadUint32Le(ctx, offset)
|
||||||
|
// y, _ := mem.ReadUint32Le(ctx, offset + 4) // 32 bits == 4 bytes!
|
||||||
|
// sum := x + y
|
||||||
|
//
|
||||||
|
// stack[0] = api.EncodeU32(sum)
|
||||||
|
// }), []api.ValueType{api.ValueTypeI32}, []api.ValueType{api.ValueTypeI32})
|
||||||
|
//
|
||||||
|
// As you can see above, defining in this way implies knowledge of which
|
||||||
|
// WebAssembly api.ValueType is appropriate for each parameter and result.
|
||||||
|
//
|
||||||
|
// See WithGoFunction if you don't need access to the calling module.
|
||||||
|
WithGoModuleFunction(fn api.GoModuleFunction, params, results []api.ValueType) HostFunctionBuilder
|
||||||
|
|
||||||
|
// WithFunc uses reflect.Value to map a go `func` to a WebAssembly
|
||||||
|
// compatible Signature. An input that isn't a `func` will fail to
|
||||||
|
// instantiate.
|
||||||
|
//
|
||||||
|
// Here's an example of an addition function:
|
||||||
|
//
|
||||||
|
// builder.WithFunc(func(cxt context.Context, x, y uint32) uint32 {
|
||||||
|
// return x + y
|
||||||
|
// })
|
||||||
|
//
|
||||||
|
// # Defining a function
|
||||||
|
//
|
||||||
|
// Except for the context.Context and optional api.Module, all parameters
|
||||||
|
// or result types must map to WebAssembly numeric value types. This means
|
||||||
|
// uint32, int32, uint64, int64, float32 or float64.
|
||||||
|
//
|
||||||
|
// api.Module may be specified as the second parameter, usually to access
|
||||||
|
// memory. This is important because there are only numeric types in Wasm.
|
||||||
|
// The only way to share other data is via writing memory and sharing
|
||||||
|
// offsets.
|
||||||
|
//
|
||||||
|
// builder.WithFunc(func(ctx context.Context, m api.Module, offset uint32) uint32 {
|
||||||
|
// mem := m.Memory()
|
||||||
|
// x, _ := mem.ReadUint32Le(ctx, offset)
|
||||||
|
// y, _ := mem.ReadUint32Le(ctx, offset + 4) // 32 bits == 4 bytes!
|
||||||
|
// return x + y
|
||||||
|
// })
|
||||||
|
//
|
||||||
|
// This example propagates context properly when calling other functions
|
||||||
|
// exported in the api.Module:
|
||||||
|
//
|
||||||
|
// builder.WithFunc(func(ctx context.Context, m api.Module, offset, byteCount uint32) uint32 {
|
||||||
|
// fn = m.ExportedFunction("__read")
|
||||||
|
// results, err := fn(ctx, offset, byteCount)
|
||||||
|
// --snip--
|
||||||
|
WithFunc(interface{}) HostFunctionBuilder
|
||||||
|
|
||||||
|
// WithName defines the optional module-local name of this function, e.g.
|
||||||
|
// "random_get"
|
||||||
|
//
|
||||||
|
// Note: This is not required to match the Export name.
|
||||||
|
WithName(name string) HostFunctionBuilder
|
||||||
|
|
||||||
|
// WithParameterNames defines optional parameter names of the function
|
||||||
|
// signature, e.x. "buf", "buf_len"
|
||||||
|
//
|
||||||
|
// Note: When defined, names must be provided for all parameters.
|
||||||
|
WithParameterNames(names ...string) HostFunctionBuilder
|
||||||
|
|
||||||
|
// WithResultNames defines optional result names of the function
|
||||||
|
// signature, e.x. "errno"
|
||||||
|
//
|
||||||
|
// Note: When defined, names must be provided for all results.
|
||||||
|
WithResultNames(names ...string) HostFunctionBuilder
|
||||||
|
|
||||||
|
// Export exports this to the HostModuleBuilder as the given name, e.g.
|
||||||
|
// "random_get"
|
||||||
|
Export(name string) HostModuleBuilder
|
||||||
|
}
|
||||||
|
|
||||||
|
// HostModuleBuilder is a way to define host functions (in Go), so that a
|
||||||
|
// WebAssembly binary (e.g. %.wasm file) can import and use them.
|
||||||
|
//
|
||||||
|
// Specifically, this implements the host side of an Application Binary
|
||||||
|
// Interface (ABI) like WASI or AssemblyScript.
|
||||||
|
//
|
||||||
|
// For example, this defines and instantiates a module named "env" with one
|
||||||
|
// function:
|
||||||
|
//
|
||||||
|
// ctx := context.Background()
|
||||||
|
// r := wazero.NewRuntime(ctx)
|
||||||
|
// defer r.Close(ctx) // This closes everything this Runtime created.
|
||||||
|
//
|
||||||
|
// hello := func() {
|
||||||
|
// println("hello!")
|
||||||
|
// }
|
||||||
|
// env, _ := r.NewHostModuleBuilder("env").
|
||||||
|
// NewFunctionBuilder().WithFunc(hello).Export("hello").
|
||||||
|
// Instantiate(ctx)
|
||||||
|
//
|
||||||
|
// If the same module may be instantiated multiple times, it is more efficient
|
||||||
|
// to separate steps. Here's an example:
|
||||||
|
//
|
||||||
|
// compiled, _ := r.NewHostModuleBuilder("env").
|
||||||
|
// NewFunctionBuilder().WithFunc(getRandomString).Export("get_random_string").
|
||||||
|
// Compile(ctx)
|
||||||
|
//
|
||||||
|
// env1, _ := r.InstantiateModule(ctx, compiled, wazero.NewModuleConfig().WithName("env.1"))
|
||||||
|
// env2, _ := r.InstantiateModule(ctx, compiled, wazero.NewModuleConfig().WithName("env.2"))
|
||||||
|
//
|
||||||
|
// See HostFunctionBuilder for valid host function signatures and other details.
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// - This is an interface for decoupling, not third-party implementations.
|
||||||
|
// All implementations are in wazero.
|
||||||
|
// - HostModuleBuilder is mutable: each method returns the same instance for
|
||||||
|
// chaining.
|
||||||
|
// - methods do not return errors, to allow chaining. Any validation errors
|
||||||
|
// are deferred until Compile.
|
||||||
|
// - Functions are indexed in order of calls to NewFunctionBuilder as
|
||||||
|
// insertion ordering is needed by ABI such as Emscripten (invoke_*).
|
||||||
|
// - The semantics of host functions assumes the existence of an "importing module" because, for example, the host function needs access to
|
||||||
|
// the memory of the importing module. Therefore, direct use of ExportedFunction is forbidden for host modules.
|
||||||
|
// Practically speaking, it is usually meaningless to directly call a host function from Go code as it is already somewhere in Go code.
|
||||||
|
type HostModuleBuilder interface {
|
||||||
|
// Note: until golang/go#5860, we can't use example tests to embed code in interface godocs.
|
||||||
|
|
||||||
|
// NewFunctionBuilder begins the definition of a host function.
|
||||||
|
NewFunctionBuilder() HostFunctionBuilder
|
||||||
|
|
||||||
|
// Compile returns a CompiledModule that can be instantiated by Runtime.
|
||||||
|
Compile(context.Context) (CompiledModule, error)
|
||||||
|
|
||||||
|
// Instantiate is a convenience that calls Compile, then Runtime.InstantiateModule.
|
||||||
|
// This can fail for reasons documented on Runtime.InstantiateModule.
|
||||||
|
//
|
||||||
|
// Here's an example:
|
||||||
|
//
|
||||||
|
// ctx := context.Background()
|
||||||
|
// r := wazero.NewRuntime(ctx)
|
||||||
|
// defer r.Close(ctx) // This closes everything this Runtime created.
|
||||||
|
//
|
||||||
|
// hello := func() {
|
||||||
|
// println("hello!")
|
||||||
|
// }
|
||||||
|
// env, _ := r.NewHostModuleBuilder("env").
|
||||||
|
// NewFunctionBuilder().WithFunc(hello).Export("hello").
|
||||||
|
// Instantiate(ctx)
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// - Closing the Runtime has the same effect as closing the result.
|
||||||
|
// - Fields in the builder are copied during instantiation: Later changes do not affect the instantiated result.
|
||||||
|
// - To avoid using configuration defaults, use Compile instead.
|
||||||
|
Instantiate(context.Context) (api.Module, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// hostModuleBuilder implements HostModuleBuilder
|
||||||
|
type hostModuleBuilder struct {
|
||||||
|
r *runtime
|
||||||
|
moduleName string
|
||||||
|
exportNames []string
|
||||||
|
nameToHostFunc map[string]*wasm.HostFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewHostModuleBuilder implements Runtime.NewHostModuleBuilder
|
||||||
|
func (r *runtime) NewHostModuleBuilder(moduleName string) HostModuleBuilder {
|
||||||
|
return &hostModuleBuilder{
|
||||||
|
r: r,
|
||||||
|
moduleName: moduleName,
|
||||||
|
nameToHostFunc: map[string]*wasm.HostFunc{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// hostFunctionBuilder implements HostFunctionBuilder
|
||||||
|
type hostFunctionBuilder struct {
|
||||||
|
b *hostModuleBuilder
|
||||||
|
fn interface{}
|
||||||
|
name string
|
||||||
|
paramNames []string
|
||||||
|
resultNames []string
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithGoFunction implements HostFunctionBuilder.WithGoFunction
|
||||||
|
func (h *hostFunctionBuilder) WithGoFunction(fn api.GoFunction, params, results []api.ValueType) HostFunctionBuilder {
|
||||||
|
h.fn = &wasm.HostFunc{ParamTypes: params, ResultTypes: results, Code: wasm.Code{GoFunc: fn}}
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithGoModuleFunction implements HostFunctionBuilder.WithGoModuleFunction
|
||||||
|
func (h *hostFunctionBuilder) WithGoModuleFunction(fn api.GoModuleFunction, params, results []api.ValueType) HostFunctionBuilder {
|
||||||
|
h.fn = &wasm.HostFunc{ParamTypes: params, ResultTypes: results, Code: wasm.Code{GoFunc: fn}}
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithFunc implements HostFunctionBuilder.WithFunc
|
||||||
|
func (h *hostFunctionBuilder) WithFunc(fn interface{}) HostFunctionBuilder {
|
||||||
|
h.fn = fn
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithName implements HostFunctionBuilder.WithName
|
||||||
|
func (h *hostFunctionBuilder) WithName(name string) HostFunctionBuilder {
|
||||||
|
h.name = name
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithParameterNames implements HostFunctionBuilder.WithParameterNames
|
||||||
|
func (h *hostFunctionBuilder) WithParameterNames(names ...string) HostFunctionBuilder {
|
||||||
|
h.paramNames = names
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithResultNames implements HostFunctionBuilder.WithResultNames
|
||||||
|
func (h *hostFunctionBuilder) WithResultNames(names ...string) HostFunctionBuilder {
|
||||||
|
h.resultNames = names
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
|
||||||
|
// Export implements HostFunctionBuilder.Export
|
||||||
|
func (h *hostFunctionBuilder) Export(exportName string) HostModuleBuilder {
|
||||||
|
var hostFn *wasm.HostFunc
|
||||||
|
if fn, ok := h.fn.(*wasm.HostFunc); ok {
|
||||||
|
hostFn = fn
|
||||||
|
} else {
|
||||||
|
hostFn = &wasm.HostFunc{Code: wasm.Code{GoFunc: h.fn}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assign any names from the builder
|
||||||
|
hostFn.ExportName = exportName
|
||||||
|
if h.name != "" {
|
||||||
|
hostFn.Name = h.name
|
||||||
|
}
|
||||||
|
if len(h.paramNames) != 0 {
|
||||||
|
hostFn.ParamNames = h.paramNames
|
||||||
|
}
|
||||||
|
if len(h.resultNames) != 0 {
|
||||||
|
hostFn.ResultNames = h.resultNames
|
||||||
|
}
|
||||||
|
|
||||||
|
h.b.ExportHostFunc(hostFn)
|
||||||
|
return h.b
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExportHostFunc implements wasm.HostFuncExporter
|
||||||
|
func (b *hostModuleBuilder) ExportHostFunc(fn *wasm.HostFunc) {
|
||||||
|
if _, ok := b.nameToHostFunc[fn.ExportName]; !ok { // add a new name
|
||||||
|
b.exportNames = append(b.exportNames, fn.ExportName)
|
||||||
|
}
|
||||||
|
b.nameToHostFunc[fn.ExportName] = fn
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewFunctionBuilder implements HostModuleBuilder.NewFunctionBuilder
|
||||||
|
func (b *hostModuleBuilder) NewFunctionBuilder() HostFunctionBuilder {
|
||||||
|
return &hostFunctionBuilder{b: b}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compile implements HostModuleBuilder.Compile
|
||||||
|
func (b *hostModuleBuilder) Compile(ctx context.Context) (CompiledModule, error) {
|
||||||
|
module, err := wasm.NewHostModule(b.moduleName, b.exportNames, b.nameToHostFunc, b.r.enabledFeatures)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if err = module.Validate(b.r.enabledFeatures); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
c := &compiledModule{module: module, compiledEngine: b.r.store.Engine}
|
||||||
|
listeners, err := buildFunctionListeners(ctx, module)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = b.r.store.Engine.CompileModule(ctx, module, listeners, false); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// typeIDs are static and compile-time known.
|
||||||
|
typeIDs, err := b.r.store.GetFunctionTypeIDs(module.TypeSection)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
c.typeIDs = typeIDs
|
||||||
|
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// hostModuleInstance is a wrapper around api.Module that prevents calling ExportedFunction.
|
||||||
|
type hostModuleInstance struct{ api.Module }
|
||||||
|
|
||||||
|
// ExportedFunction implements api.Module ExportedFunction.
|
||||||
|
func (h hostModuleInstance) ExportedFunction(name string) api.Function {
|
||||||
|
panic("calling ExportedFunction is forbidden on host modules. See the note on ExportedFunction interface")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Instantiate implements HostModuleBuilder.Instantiate
|
||||||
|
func (b *hostModuleBuilder) Instantiate(ctx context.Context) (api.Module, error) {
|
||||||
|
if compiled, err := b.Compile(ctx); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
compiled.(*compiledModule).closeWithModule = true
|
||||||
|
m, err := b.r.InstantiateModule(ctx, compiled, NewModuleConfig())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return hostModuleInstance{m}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
123
vendor/github.com/tetratelabs/wazero/cache.go
generated
vendored
Normal file
123
vendor/github.com/tetratelabs/wazero/cache.go
generated
vendored
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
package wazero
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"path/filepath"
|
||||||
|
goruntime "runtime"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/tetratelabs/wazero/api"
|
||||||
|
"github.com/tetratelabs/wazero/internal/filecache"
|
||||||
|
"github.com/tetratelabs/wazero/internal/version"
|
||||||
|
"github.com/tetratelabs/wazero/internal/wasm"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CompilationCache reduces time spent compiling (Runtime.CompileModule) the same wasm module.
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// - This is an interface for decoupling, not third-party implementations.
|
||||||
|
// All implementations are in wazero.
|
||||||
|
// - Instances of this can be reused across multiple runtimes, if configured
|
||||||
|
// via RuntimeConfig.
|
||||||
|
// - The cache check happens before the compilation, so if multiple Goroutines are
|
||||||
|
// trying to compile the same module simultaneously, it is possible that they
|
||||||
|
// all compile the module. The design here is that the lock isn't held for the action "Compile"
|
||||||
|
// but only for checking and saving the compiled result. Therefore, we strongly recommend that the embedder
|
||||||
|
// does the centralized compilation in a single Goroutines (or multiple Goroutines per Wasm binary) to generate cache rather than
|
||||||
|
// trying to Compile in parallel for a single module. In other words, we always recommend to produce CompiledModule
|
||||||
|
// share it across multiple Goroutines to avoid trying to compile the same module simultaneously.
|
||||||
|
type CompilationCache interface{ api.Closer }
|
||||||
|
|
||||||
|
// NewCompilationCache returns a new CompilationCache to be passed to RuntimeConfig.
|
||||||
|
// This configures only in-memory cache, and doesn't persist to the file system. See wazero.NewCompilationCacheWithDir for detail.
|
||||||
|
//
|
||||||
|
// The returned CompilationCache can be used to share the in-memory compilation results across multiple instances of wazero.Runtime.
|
||||||
|
func NewCompilationCache() CompilationCache {
|
||||||
|
return &cache{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewCompilationCacheWithDir is like wazero.NewCompilationCache except the result also writes
|
||||||
|
// state into the directory specified by `dirname` parameter.
|
||||||
|
//
|
||||||
|
// If the dirname doesn't exist, this creates it or returns an error.
|
||||||
|
//
|
||||||
|
// Those running wazero as a CLI or frequently restarting a process using the same wasm should
|
||||||
|
// use this feature to reduce time waiting to compile the same module a second time.
|
||||||
|
//
|
||||||
|
// The contents written into dirname are wazero-version specific, meaning different versions of
|
||||||
|
// wazero will duplicate entries for the same input wasm.
|
||||||
|
//
|
||||||
|
// Note: The embedder must safeguard this directory from external changes.
|
||||||
|
func NewCompilationCacheWithDir(dirname string) (CompilationCache, error) {
|
||||||
|
c := &cache{}
|
||||||
|
err := c.ensuresFileCache(dirname, version.GetWazeroVersion())
|
||||||
|
return c, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// cache implements Cache interface.
|
||||||
|
type cache struct {
|
||||||
|
// eng is the engine for this cache. If the cache is configured, the engine is shared across multiple instances of
|
||||||
|
// Runtime, and its lifetime is not bound to them. Instead, the engine is alive until Cache.Close is called.
|
||||||
|
engs [engineKindCount]wasm.Engine
|
||||||
|
fileCache filecache.Cache
|
||||||
|
initOnces [engineKindCount]sync.Once
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cache) initEngine(ek engineKind, ne newEngine, ctx context.Context, features api.CoreFeatures) wasm.Engine {
|
||||||
|
c.initOnces[ek].Do(func() { c.engs[ek] = ne(ctx, features, c.fileCache) })
|
||||||
|
return c.engs[ek]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close implements the same method on the Cache interface.
|
||||||
|
func (c *cache) Close(_ context.Context) (err error) {
|
||||||
|
for _, eng := range c.engs {
|
||||||
|
if eng != nil {
|
||||||
|
if err = eng.Close(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cache) ensuresFileCache(dir string, wazeroVersion string) error {
|
||||||
|
// Resolve a potentially relative directory into an absolute one.
|
||||||
|
var err error
|
||||||
|
dir, err = filepath.Abs(dir)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure the user-supplied directory.
|
||||||
|
if err = mkdir(dir); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a version-specific directory to avoid conflicts.
|
||||||
|
dirname := path.Join(dir, "wazero-"+wazeroVersion+"-"+goruntime.GOARCH+"-"+goruntime.GOOS)
|
||||||
|
if err = mkdir(dirname); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
c.fileCache = filecache.New(dirname)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func mkdir(dirname string) error {
|
||||||
|
if st, err := os.Stat(dirname); errors.Is(err, os.ErrNotExist) {
|
||||||
|
// If the directory not found, create the cache dir.
|
||||||
|
if err = os.MkdirAll(dirname, 0o700); err != nil {
|
||||||
|
return fmt.Errorf("create directory %s: %v", dirname, err)
|
||||||
|
}
|
||||||
|
} else if err != nil {
|
||||||
|
return err
|
||||||
|
} else if !st.IsDir() {
|
||||||
|
return fmt.Errorf("%s is not dir", dirname)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
9
vendor/github.com/tetratelabs/wazero/codecov.yml
generated
vendored
Normal file
9
vendor/github.com/tetratelabs/wazero/codecov.yml
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# Codecov for main is visible here https://app.codecov.io/gh/tetratelabs/wazero
|
||||||
|
|
||||||
|
# We use codecov only as a UI, so we disable PR comments and commit status.
|
||||||
|
# See https://docs.codecov.com/docs/pull-request-comments
|
||||||
|
comment: false
|
||||||
|
coverage:
|
||||||
|
status:
|
||||||
|
project: off
|
||||||
|
patch: off
|
||||||
899
vendor/github.com/tetratelabs/wazero/config.go
generated
vendored
Normal file
899
vendor/github.com/tetratelabs/wazero/config.go
generated
vendored
Normal file
@@ -0,0 +1,899 @@
|
|||||||
|
package wazero
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/fs"
|
||||||
|
"math"
|
||||||
|
"net"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/tetratelabs/wazero/api"
|
||||||
|
experimentalsys "github.com/tetratelabs/wazero/experimental/sys"
|
||||||
|
"github.com/tetratelabs/wazero/internal/filecache"
|
||||||
|
"github.com/tetratelabs/wazero/internal/internalapi"
|
||||||
|
"github.com/tetratelabs/wazero/internal/platform"
|
||||||
|
internalsock "github.com/tetratelabs/wazero/internal/sock"
|
||||||
|
internalsys "github.com/tetratelabs/wazero/internal/sys"
|
||||||
|
"github.com/tetratelabs/wazero/internal/wasm"
|
||||||
|
"github.com/tetratelabs/wazero/sys"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RuntimeConfig controls runtime behavior, with the default implementation as
|
||||||
|
// NewRuntimeConfig
|
||||||
|
//
|
||||||
|
// The example below explicitly limits to Wasm Core 1.0 features as opposed to
|
||||||
|
// relying on defaults:
|
||||||
|
//
|
||||||
|
// rConfig = wazero.NewRuntimeConfig().WithCoreFeatures(api.CoreFeaturesV1)
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// - This is an interface for decoupling, not third-party implementations.
|
||||||
|
// All implementations are in wazero.
|
||||||
|
// - RuntimeConfig is immutable. Each WithXXX function returns a new instance
|
||||||
|
// including the corresponding change.
|
||||||
|
type RuntimeConfig interface {
|
||||||
|
// WithCoreFeatures sets the WebAssembly Core specification features this
|
||||||
|
// runtime supports. Defaults to api.CoreFeaturesV2.
|
||||||
|
//
|
||||||
|
// Example of disabling a specific feature:
|
||||||
|
// features := api.CoreFeaturesV2.SetEnabled(api.CoreFeatureMutableGlobal, false)
|
||||||
|
// rConfig = wazero.NewRuntimeConfig().WithCoreFeatures(features)
|
||||||
|
//
|
||||||
|
// # Why default to version 2.0?
|
||||||
|
//
|
||||||
|
// Many compilers that target WebAssembly require features after
|
||||||
|
// api.CoreFeaturesV1 by default. For example, TinyGo v0.24+ requires
|
||||||
|
// api.CoreFeatureBulkMemoryOperations. To avoid runtime errors, wazero
|
||||||
|
// defaults to api.CoreFeaturesV2, even though it is not yet a Web
|
||||||
|
// Standard (REC).
|
||||||
|
WithCoreFeatures(api.CoreFeatures) RuntimeConfig
|
||||||
|
|
||||||
|
// WithMemoryLimitPages overrides the maximum pages allowed per memory. The
|
||||||
|
// default is 65536, allowing 4GB total memory per instance if the maximum is
|
||||||
|
// not encoded in a Wasm binary. Setting a value larger than default will panic.
|
||||||
|
//
|
||||||
|
// This example reduces the largest possible memory size from 4GB to 128KB:
|
||||||
|
// rConfig = wazero.NewRuntimeConfig().WithMemoryLimitPages(2)
|
||||||
|
//
|
||||||
|
// Note: Wasm has 32-bit memory and each page is 65536 (2^16) bytes. This
|
||||||
|
// implies a max of 65536 (2^16) addressable pages.
|
||||||
|
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#grow-mem
|
||||||
|
WithMemoryLimitPages(memoryLimitPages uint32) RuntimeConfig
|
||||||
|
|
||||||
|
// WithMemoryCapacityFromMax eagerly allocates max memory, unless max is
|
||||||
|
// not defined. The default is false, which means minimum memory is
|
||||||
|
// allocated and any call to grow memory results in re-allocations.
|
||||||
|
//
|
||||||
|
// This example ensures any memory.grow instruction will never re-allocate:
|
||||||
|
// rConfig = wazero.NewRuntimeConfig().WithMemoryCapacityFromMax(true)
|
||||||
|
//
|
||||||
|
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#grow-mem
|
||||||
|
//
|
||||||
|
// Note: if the memory maximum is not encoded in a Wasm binary, this
|
||||||
|
// results in allocating 4GB. See the doc on WithMemoryLimitPages for detail.
|
||||||
|
WithMemoryCapacityFromMax(memoryCapacityFromMax bool) RuntimeConfig
|
||||||
|
|
||||||
|
// WithDebugInfoEnabled toggles DWARF based stack traces in the face of
|
||||||
|
// runtime errors. Defaults to true.
|
||||||
|
//
|
||||||
|
// Those who wish to disable this, can like so:
|
||||||
|
//
|
||||||
|
// r := wazero.NewRuntimeWithConfig(wazero.NewRuntimeConfig().WithDebugInfoEnabled(false)
|
||||||
|
//
|
||||||
|
// When disabled, a stack trace message looks like:
|
||||||
|
//
|
||||||
|
// wasm stack trace:
|
||||||
|
// .runtime._panic(i32)
|
||||||
|
// .myFunc()
|
||||||
|
// .main.main()
|
||||||
|
// .runtime.run()
|
||||||
|
// ._start()
|
||||||
|
//
|
||||||
|
// When enabled, the stack trace includes source code information:
|
||||||
|
//
|
||||||
|
// wasm stack trace:
|
||||||
|
// .runtime._panic(i32)
|
||||||
|
// 0x16e2: /opt/homebrew/Cellar/tinygo/0.26.0/src/runtime/runtime_tinygowasm.go:73:6
|
||||||
|
// .myFunc()
|
||||||
|
// 0x190b: /Users/XXXXX/wazero/internal/testing/dwarftestdata/testdata/main.go:19:7
|
||||||
|
// .main.main()
|
||||||
|
// 0x18ed: /Users/XXXXX/wazero/internal/testing/dwarftestdata/testdata/main.go:4:3
|
||||||
|
// .runtime.run()
|
||||||
|
// 0x18cc: /opt/homebrew/Cellar/tinygo/0.26.0/src/runtime/scheduler_none.go:26:10
|
||||||
|
// ._start()
|
||||||
|
// 0x18b6: /opt/homebrew/Cellar/tinygo/0.26.0/src/runtime/runtime_wasm_wasi.go:22:5
|
||||||
|
//
|
||||||
|
// Note: This only takes into effect when the original Wasm binary has the
|
||||||
|
// DWARF "custom sections" that are often stripped, depending on
|
||||||
|
// optimization flags passed to the compiler.
|
||||||
|
WithDebugInfoEnabled(bool) RuntimeConfig
|
||||||
|
|
||||||
|
// WithCompilationCache configures how runtime caches the compiled modules. In the default configuration, compilation results are
|
||||||
|
// only in-memory until Runtime.Close is closed, and not shareable by multiple Runtime.
|
||||||
|
//
|
||||||
|
// Below defines the shared cache across multiple instances of Runtime:
|
||||||
|
//
|
||||||
|
// // Creates the new Cache and the runtime configuration with it.
|
||||||
|
// cache := wazero.NewCompilationCache()
|
||||||
|
// defer cache.Close()
|
||||||
|
// config := wazero.NewRuntimeConfig().WithCompilationCache(c)
|
||||||
|
//
|
||||||
|
// // Creates two runtimes while sharing compilation caches.
|
||||||
|
// foo := wazero.NewRuntimeWithConfig(context.Background(), config)
|
||||||
|
// bar := wazero.NewRuntimeWithConfig(context.Background(), config)
|
||||||
|
//
|
||||||
|
// # Cache Key
|
||||||
|
//
|
||||||
|
// Cached files are keyed on the version of wazero. This is obtained from go.mod of your application,
|
||||||
|
// and we use it to verify the compatibility of caches against the currently-running wazero.
|
||||||
|
// However, if you use this in tests of a package not named as `main`, then wazero cannot obtain the correct
|
||||||
|
// version of wazero due to the known issue of debug.BuildInfo function: https://github.com/golang/go/issues/33976.
|
||||||
|
// As a consequence, your cache won't contain the correct version information and always be treated as `dev` version.
|
||||||
|
// To avoid this issue, you can pass -ldflags "-X github.com/tetratelabs/wazero/internal/version.version=foo" when running tests.
|
||||||
|
WithCompilationCache(CompilationCache) RuntimeConfig
|
||||||
|
|
||||||
|
// WithCustomSections toggles parsing of "custom sections". Defaults to false.
|
||||||
|
//
|
||||||
|
// When enabled, it is possible to retrieve custom sections from a CompiledModule:
|
||||||
|
//
|
||||||
|
// config := wazero.NewRuntimeConfig().WithCustomSections(true)
|
||||||
|
// r := wazero.NewRuntimeWithConfig(ctx, config)
|
||||||
|
// c, err := r.CompileModule(ctx, wasm)
|
||||||
|
// customSections := c.CustomSections()
|
||||||
|
WithCustomSections(bool) RuntimeConfig
|
||||||
|
|
||||||
|
// WithCloseOnContextDone ensures the executions of functions to be terminated under one of the following circumstances:
|
||||||
|
//
|
||||||
|
// - context.Context passed to the Call method of api.Function is canceled during execution. (i.e. ctx by context.WithCancel)
|
||||||
|
// - context.Context passed to the Call method of api.Function reaches timeout during execution. (i.e. ctx by context.WithTimeout or context.WithDeadline)
|
||||||
|
// - Close or CloseWithExitCode of api.Module is explicitly called during execution.
|
||||||
|
//
|
||||||
|
// This is especially useful when one wants to run untrusted Wasm binaries since otherwise, any invocation of
|
||||||
|
// api.Function can potentially block the corresponding Goroutine forever. Moreover, it might block the
|
||||||
|
// entire underlying OS thread which runs the api.Function call. See "Why it's safe to execute runtime-generated
|
||||||
|
// machine codes against async Goroutine preemption" section in RATIONALE.md for detail.
|
||||||
|
//
|
||||||
|
// Upon the termination of the function executions, api.Module is closed.
|
||||||
|
//
|
||||||
|
// Note that this comes with a bit of extra cost when enabled. The reason is that internally this forces
|
||||||
|
// interpreter and compiler runtimes to insert the periodical checks on the conditions above. For that reason,
|
||||||
|
// this is disabled by default.
|
||||||
|
//
|
||||||
|
// See examples in context_done_example_test.go for the end-to-end demonstrations.
|
||||||
|
//
|
||||||
|
// When the invocations of api.Function are closed due to this, sys.ExitError is raised to the callers and
|
||||||
|
// the api.Module from which the functions are derived is made closed.
|
||||||
|
WithCloseOnContextDone(bool) RuntimeConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewRuntimeConfig returns a RuntimeConfig using the compiler if it is supported in this environment,
|
||||||
|
// or the interpreter otherwise.
|
||||||
|
func NewRuntimeConfig() RuntimeConfig {
|
||||||
|
ret := engineLessConfig.clone()
|
||||||
|
ret.engineKind = engineKindAuto
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
type newEngine func(context.Context, api.CoreFeatures, filecache.Cache) wasm.Engine
|
||||||
|
|
||||||
|
type runtimeConfig struct {
|
||||||
|
enabledFeatures api.CoreFeatures
|
||||||
|
memoryLimitPages uint32
|
||||||
|
memoryCapacityFromMax bool
|
||||||
|
engineKind engineKind
|
||||||
|
dwarfDisabled bool // negative as defaults to enabled
|
||||||
|
newEngine newEngine
|
||||||
|
cache CompilationCache
|
||||||
|
storeCustomSections bool
|
||||||
|
ensureTermination bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// engineLessConfig helps avoid copy/pasting the wrong defaults.
|
||||||
|
var engineLessConfig = &runtimeConfig{
|
||||||
|
enabledFeatures: api.CoreFeaturesV2,
|
||||||
|
memoryLimitPages: wasm.MemoryLimitPages,
|
||||||
|
memoryCapacityFromMax: false,
|
||||||
|
dwarfDisabled: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
type engineKind int
|
||||||
|
|
||||||
|
const (
|
||||||
|
engineKindAuto engineKind = iota - 1
|
||||||
|
engineKindCompiler
|
||||||
|
engineKindInterpreter
|
||||||
|
engineKindCount
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewRuntimeConfigCompiler compiles WebAssembly modules into
|
||||||
|
// runtime.GOARCH-specific assembly for optimal performance.
|
||||||
|
//
|
||||||
|
// The default implementation is AOT (Ahead of Time) compilation, applied at
|
||||||
|
// Runtime.CompileModule. This allows consistent runtime performance, as well
|
||||||
|
// the ability to reduce any first request penalty.
|
||||||
|
//
|
||||||
|
// Note: While this is technically AOT, this does not imply any action on your
|
||||||
|
// part. wazero automatically performs ahead-of-time compilation as needed when
|
||||||
|
// Runtime.CompileModule is invoked.
|
||||||
|
//
|
||||||
|
// # Warning
|
||||||
|
//
|
||||||
|
// - This panics at runtime if the runtime.GOOS or runtime.GOARCH does not
|
||||||
|
// support compiler. Use NewRuntimeConfig to safely detect and fallback to
|
||||||
|
// NewRuntimeConfigInterpreter if needed.
|
||||||
|
//
|
||||||
|
// - If you are using wazero in buildmode=c-archive or c-shared, make sure that you set up the alternate signal stack
|
||||||
|
// by using, e.g. `sigaltstack` combined with `SA_ONSTACK` flag on `sigaction` on Linux,
|
||||||
|
// before calling any api.Function. This is because the Go runtime does not set up the alternate signal stack
|
||||||
|
// for c-archive or c-shared modes, and wazero uses the different stack than the calling Goroutine.
|
||||||
|
// Hence, the signal handler might get invoked on the wazero's stack, which may cause a stack overflow.
|
||||||
|
// https://github.com/tetratelabs/wazero/blob/2092c0a879f30d49d7b37f333f4547574b8afe0d/internal/integration_test/fuzz/fuzz/tests/sigstack.rs#L19-L36
|
||||||
|
func NewRuntimeConfigCompiler() RuntimeConfig {
|
||||||
|
ret := engineLessConfig.clone()
|
||||||
|
ret.engineKind = engineKindCompiler
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewRuntimeConfigInterpreter interprets WebAssembly modules instead of compiling them into assembly.
|
||||||
|
func NewRuntimeConfigInterpreter() RuntimeConfig {
|
||||||
|
ret := engineLessConfig.clone()
|
||||||
|
ret.engineKind = engineKindInterpreter
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// clone makes a deep copy of this runtime config.
|
||||||
|
func (c *runtimeConfig) clone() *runtimeConfig {
|
||||||
|
ret := *c // copy except maps which share a ref
|
||||||
|
return &ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithCoreFeatures implements RuntimeConfig.WithCoreFeatures
|
||||||
|
func (c *runtimeConfig) WithCoreFeatures(features api.CoreFeatures) RuntimeConfig {
|
||||||
|
ret := c.clone()
|
||||||
|
ret.enabledFeatures = features
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithCloseOnContextDone implements RuntimeConfig.WithCloseOnContextDone
|
||||||
|
func (c *runtimeConfig) WithCloseOnContextDone(ensure bool) RuntimeConfig {
|
||||||
|
ret := c.clone()
|
||||||
|
ret.ensureTermination = ensure
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithMemoryLimitPages implements RuntimeConfig.WithMemoryLimitPages
|
||||||
|
func (c *runtimeConfig) WithMemoryLimitPages(memoryLimitPages uint32) RuntimeConfig {
|
||||||
|
ret := c.clone()
|
||||||
|
// This panics instead of returning an error as it is unlikely.
|
||||||
|
if memoryLimitPages > wasm.MemoryLimitPages {
|
||||||
|
panic(fmt.Errorf("memoryLimitPages invalid: %d > %d", memoryLimitPages, wasm.MemoryLimitPages))
|
||||||
|
}
|
||||||
|
ret.memoryLimitPages = memoryLimitPages
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithCompilationCache implements RuntimeConfig.WithCompilationCache
|
||||||
|
func (c *runtimeConfig) WithCompilationCache(ca CompilationCache) RuntimeConfig {
|
||||||
|
ret := c.clone()
|
||||||
|
ret.cache = ca
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithMemoryCapacityFromMax implements RuntimeConfig.WithMemoryCapacityFromMax
|
||||||
|
func (c *runtimeConfig) WithMemoryCapacityFromMax(memoryCapacityFromMax bool) RuntimeConfig {
|
||||||
|
ret := c.clone()
|
||||||
|
ret.memoryCapacityFromMax = memoryCapacityFromMax
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithDebugInfoEnabled implements RuntimeConfig.WithDebugInfoEnabled
|
||||||
|
func (c *runtimeConfig) WithDebugInfoEnabled(dwarfEnabled bool) RuntimeConfig {
|
||||||
|
ret := c.clone()
|
||||||
|
ret.dwarfDisabled = !dwarfEnabled
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithCustomSections implements RuntimeConfig.WithCustomSections
|
||||||
|
func (c *runtimeConfig) WithCustomSections(storeCustomSections bool) RuntimeConfig {
|
||||||
|
ret := c.clone()
|
||||||
|
ret.storeCustomSections = storeCustomSections
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// CompiledModule is a WebAssembly module ready to be instantiated (Runtime.InstantiateModule) as an api.Module.
|
||||||
|
//
|
||||||
|
// In WebAssembly terminology, this is a decoded, validated, and possibly also compiled module. wazero avoids using
|
||||||
|
// the name "Module" for both before and after instantiation as the name conflation has caused confusion.
|
||||||
|
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#semantic-phases%E2%91%A0
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// - This is an interface for decoupling, not third-party implementations.
|
||||||
|
// All implementations are in wazero.
|
||||||
|
// - Closing the wazero.Runtime closes any CompiledModule it compiled.
|
||||||
|
type CompiledModule interface {
|
||||||
|
// Name returns the module name encoded into the binary or empty if not.
|
||||||
|
Name() string
|
||||||
|
|
||||||
|
// ImportedFunctions returns all the imported functions
|
||||||
|
// (api.FunctionDefinition) in this module or nil if there are none.
|
||||||
|
//
|
||||||
|
// Note: Unlike ExportedFunctions, there is no unique constraint on
|
||||||
|
// imports.
|
||||||
|
ImportedFunctions() []api.FunctionDefinition
|
||||||
|
|
||||||
|
// ExportedFunctions returns all the exported functions
|
||||||
|
// (api.FunctionDefinition) in this module keyed on export name.
|
||||||
|
ExportedFunctions() map[string]api.FunctionDefinition
|
||||||
|
|
||||||
|
// ImportedMemories returns all the imported memories
|
||||||
|
// (api.MemoryDefinition) in this module or nil if there are none.
|
||||||
|
//
|
||||||
|
// ## Notes
|
||||||
|
// - As of WebAssembly Core Specification 2.0, there can be at most one
|
||||||
|
// memory.
|
||||||
|
// - Unlike ExportedMemories, there is no unique constraint on imports.
|
||||||
|
ImportedMemories() []api.MemoryDefinition
|
||||||
|
|
||||||
|
// ExportedMemories returns all the exported memories
|
||||||
|
// (api.MemoryDefinition) in this module keyed on export name.
|
||||||
|
//
|
||||||
|
// Note: As of WebAssembly Core Specification 2.0, there can be at most one
|
||||||
|
// memory.
|
||||||
|
ExportedMemories() map[string]api.MemoryDefinition
|
||||||
|
|
||||||
|
// CustomSections returns all the custom sections
|
||||||
|
// (api.CustomSection) in this module keyed on the section name.
|
||||||
|
CustomSections() []api.CustomSection
|
||||||
|
|
||||||
|
// Close releases all the allocated resources for this CompiledModule.
|
||||||
|
//
|
||||||
|
// Note: It is safe to call Close while having outstanding calls from an
|
||||||
|
// api.Module instantiated from this.
|
||||||
|
Close(context.Context) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// compile-time check to ensure compiledModule implements CompiledModule
|
||||||
|
var _ CompiledModule = &compiledModule{}
|
||||||
|
|
||||||
|
type compiledModule struct {
|
||||||
|
module *wasm.Module
|
||||||
|
// compiledEngine holds an engine on which `module` is compiled.
|
||||||
|
compiledEngine wasm.Engine
|
||||||
|
// closeWithModule prevents leaking compiled code when a module is compiled implicitly.
|
||||||
|
closeWithModule bool
|
||||||
|
typeIDs []wasm.FunctionTypeID
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name implements CompiledModule.Name
|
||||||
|
func (c *compiledModule) Name() (moduleName string) {
|
||||||
|
if ns := c.module.NameSection; ns != nil {
|
||||||
|
moduleName = ns.ModuleName
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close implements CompiledModule.Close
|
||||||
|
func (c *compiledModule) Close(context.Context) error {
|
||||||
|
c.compiledEngine.DeleteCompiledModule(c.module)
|
||||||
|
// It is possible the underlying may need to return an error later, but in any case this matches api.Module.Close.
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ImportedFunctions implements CompiledModule.ImportedFunctions
|
||||||
|
func (c *compiledModule) ImportedFunctions() []api.FunctionDefinition {
|
||||||
|
return c.module.ImportedFunctions()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExportedFunctions implements CompiledModule.ExportedFunctions
|
||||||
|
func (c *compiledModule) ExportedFunctions() map[string]api.FunctionDefinition {
|
||||||
|
return c.module.ExportedFunctions()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ImportedMemories implements CompiledModule.ImportedMemories
|
||||||
|
func (c *compiledModule) ImportedMemories() []api.MemoryDefinition {
|
||||||
|
return c.module.ImportedMemories()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExportedMemories implements CompiledModule.ExportedMemories
|
||||||
|
func (c *compiledModule) ExportedMemories() map[string]api.MemoryDefinition {
|
||||||
|
return c.module.ExportedMemories()
|
||||||
|
}
|
||||||
|
|
||||||
|
// CustomSections implements CompiledModule.CustomSections
|
||||||
|
func (c *compiledModule) CustomSections() []api.CustomSection {
|
||||||
|
ret := make([]api.CustomSection, len(c.module.CustomSections))
|
||||||
|
for i, d := range c.module.CustomSections {
|
||||||
|
ret[i] = &customSection{data: d.Data, name: d.Name}
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// customSection implements wasm.CustomSection
|
||||||
|
type customSection struct {
|
||||||
|
internalapi.WazeroOnlyType
|
||||||
|
name string
|
||||||
|
data []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name implements wasm.CustomSection.Name
|
||||||
|
func (c *customSection) Name() string {
|
||||||
|
return c.name
|
||||||
|
}
|
||||||
|
|
||||||
|
// Data implements wasm.CustomSection.Data
|
||||||
|
func (c *customSection) Data() []byte {
|
||||||
|
return c.data
|
||||||
|
}
|
||||||
|
|
||||||
|
// ModuleConfig configures resources needed by functions that have low-level interactions with the host operating
|
||||||
|
// system. Using this, resources such as STDIN can be isolated, so that the same module can be safely instantiated
|
||||||
|
// multiple times.
|
||||||
|
//
|
||||||
|
// Here's an example:
|
||||||
|
//
|
||||||
|
// // Initialize base configuration:
|
||||||
|
// config := wazero.NewModuleConfig().WithStdout(buf).WithSysNanotime()
|
||||||
|
//
|
||||||
|
// // Assign different configuration on each instantiation
|
||||||
|
// mod, _ := r.InstantiateModule(ctx, compiled, config.WithName("rotate").WithArgs("rotate", "angle=90", "dir=cw"))
|
||||||
|
//
|
||||||
|
// While wazero supports Windows as a platform, host functions using ModuleConfig follow a UNIX dialect.
|
||||||
|
// See RATIONALE.md for design background and relationship to WebAssembly System Interfaces (WASI).
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// - This is an interface for decoupling, not third-party implementations.
|
||||||
|
// All implementations are in wazero.
|
||||||
|
// - ModuleConfig is immutable. Each WithXXX function returns a new instance
|
||||||
|
// including the corresponding change.
|
||||||
|
type ModuleConfig interface {
|
||||||
|
// WithArgs assigns command-line arguments visible to an imported function that reads an arg vector (argv). Defaults to
|
||||||
|
// none. Runtime.InstantiateModule errs if any arg is empty.
|
||||||
|
//
|
||||||
|
// These values are commonly read by the functions like "args_get" in "wasi_snapshot_preview1" although they could be
|
||||||
|
// read by functions imported from other modules.
|
||||||
|
//
|
||||||
|
// Similar to os.Args and exec.Cmd Env, many implementations would expect a program name to be argv[0]. However, neither
|
||||||
|
// WebAssembly nor WebAssembly System Interfaces (WASI) define this. Regardless, you may choose to set the first
|
||||||
|
// argument to the same value set via WithName.
|
||||||
|
//
|
||||||
|
// Note: This does not default to os.Args as that violates sandboxing.
|
||||||
|
//
|
||||||
|
// See https://linux.die.net/man/3/argv and https://en.wikipedia.org/wiki/Null-terminated_string
|
||||||
|
WithArgs(...string) ModuleConfig
|
||||||
|
|
||||||
|
// WithEnv sets an environment variable visible to a Module that imports functions. Defaults to none.
|
||||||
|
// Runtime.InstantiateModule errs if the key is empty or contains a NULL(0) or equals("") character.
|
||||||
|
//
|
||||||
|
// Validation is the same as os.Setenv on Linux and replaces any existing value. Unlike exec.Cmd Env, this does not
|
||||||
|
// default to the current process environment as that would violate sandboxing. This also does not preserve order.
|
||||||
|
//
|
||||||
|
// Environment variables are commonly read by the functions like "environ_get" in "wasi_snapshot_preview1" although
|
||||||
|
// they could be read by functions imported from other modules.
|
||||||
|
//
|
||||||
|
// While similar to process configuration, there are no assumptions that can be made about anything OS-specific. For
|
||||||
|
// example, neither WebAssembly nor WebAssembly System Interfaces (WASI) define concerns processes have, such as
|
||||||
|
// case-sensitivity on environment keys. For portability, define entries with case-insensitively unique keys.
|
||||||
|
//
|
||||||
|
// See https://linux.die.net/man/3/environ and https://en.wikipedia.org/wiki/Null-terminated_string
|
||||||
|
WithEnv(key, value string) ModuleConfig
|
||||||
|
|
||||||
|
// WithFS is a convenience that calls WithFSConfig with an FSConfig of the
|
||||||
|
// input for the root ("/") guest path.
|
||||||
|
WithFS(fs.FS) ModuleConfig
|
||||||
|
|
||||||
|
// WithFSConfig configures the filesystem available to each guest
|
||||||
|
// instantiated with this configuration. By default, no file access is
|
||||||
|
// allowed, so functions like `path_open` result in unsupported errors
|
||||||
|
// (e.g. syscall.ENOSYS).
|
||||||
|
WithFSConfig(FSConfig) ModuleConfig
|
||||||
|
|
||||||
|
// WithName configures the module name. Defaults to what was decoded from
|
||||||
|
// the name section. Duplicate names are not allowed in a single Runtime.
|
||||||
|
//
|
||||||
|
// Calling this with the empty string "" makes the module anonymous.
|
||||||
|
// That is useful when you want to instantiate the same CompiledModule multiple times like below:
|
||||||
|
//
|
||||||
|
// for i := 0; i < N; i++ {
|
||||||
|
// // Instantiate a new Wasm module from the already compiled `compiledWasm` anonymously without a name.
|
||||||
|
// instance, err := r.InstantiateModule(ctx, compiledWasm, wazero.NewModuleConfig().WithName(""))
|
||||||
|
// // ....
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// See the `concurrent-instantiation` example for a complete usage.
|
||||||
|
//
|
||||||
|
// Non-empty named modules are available for other modules to import by name.
|
||||||
|
WithName(string) ModuleConfig
|
||||||
|
|
||||||
|
// WithStartFunctions configures the functions to call after the module is
|
||||||
|
// instantiated. Defaults to "_start".
|
||||||
|
//
|
||||||
|
// Clearing the default is supported, via `WithStartFunctions()`.
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// - If a start function doesn't exist, it is skipped. However, any that
|
||||||
|
// do exist are called in order.
|
||||||
|
// - Start functions are not intended to be called multiple times.
|
||||||
|
// Functions that should be called multiple times should be invoked
|
||||||
|
// manually via api.Module's `ExportedFunction` method.
|
||||||
|
// - Start functions commonly exit the module during instantiation,
|
||||||
|
// preventing use of any functions later. This is the case in "wasip1",
|
||||||
|
// which defines the default value "_start".
|
||||||
|
// - See /RATIONALE.md for motivation of this feature.
|
||||||
|
WithStartFunctions(...string) ModuleConfig
|
||||||
|
|
||||||
|
// WithStderr configures where standard error (file descriptor 2) is written. Defaults to io.Discard.
|
||||||
|
//
|
||||||
|
// This writer is most commonly used by the functions like "fd_write" in "wasi_snapshot_preview1" although it could
|
||||||
|
// be used by functions imported from other modules.
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// - The caller is responsible to close any io.Writer they supply: It is not closed on api.Module Close.
|
||||||
|
// - This does not default to os.Stderr as that both violates sandboxing and prevents concurrent modules.
|
||||||
|
//
|
||||||
|
// See https://linux.die.net/man/3/stderr
|
||||||
|
WithStderr(io.Writer) ModuleConfig
|
||||||
|
|
||||||
|
// WithStdin configures where standard input (file descriptor 0) is read. Defaults to return io.EOF.
|
||||||
|
//
|
||||||
|
// This reader is most commonly used by the functions like "fd_read" in "wasi_snapshot_preview1" although it could
|
||||||
|
// be used by functions imported from other modules.
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// - The caller is responsible to close any io.Reader they supply: It is not closed on api.Module Close.
|
||||||
|
// - This does not default to os.Stdin as that both violates sandboxing and prevents concurrent modules.
|
||||||
|
//
|
||||||
|
// See https://linux.die.net/man/3/stdin
|
||||||
|
WithStdin(io.Reader) ModuleConfig
|
||||||
|
|
||||||
|
// WithStdout configures where standard output (file descriptor 1) is written. Defaults to io.Discard.
|
||||||
|
//
|
||||||
|
// This writer is most commonly used by the functions like "fd_write" in "wasi_snapshot_preview1" although it could
|
||||||
|
// be used by functions imported from other modules.
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// - The caller is responsible to close any io.Writer they supply: It is not closed on api.Module Close.
|
||||||
|
// - This does not default to os.Stdout as that both violates sandboxing and prevents concurrent modules.
|
||||||
|
//
|
||||||
|
// See https://linux.die.net/man/3/stdout
|
||||||
|
WithStdout(io.Writer) ModuleConfig
|
||||||
|
|
||||||
|
// WithWalltime configures the wall clock, sometimes referred to as the
|
||||||
|
// real time clock. sys.Walltime returns the current unix/epoch time,
|
||||||
|
// seconds since midnight UTC 1 January 1970, with a nanosecond fraction.
|
||||||
|
// This defaults to a fake result that increases by 1ms on each reading.
|
||||||
|
//
|
||||||
|
// Here's an example that uses a custom clock:
|
||||||
|
// moduleConfig = moduleConfig.
|
||||||
|
// WithWalltime(func(context.Context) (sec int64, nsec int32) {
|
||||||
|
// return clock.walltime()
|
||||||
|
// }, sys.ClockResolution(time.Microsecond.Nanoseconds()))
|
||||||
|
//
|
||||||
|
// # Notes:
|
||||||
|
// - This does not default to time.Now as that violates sandboxing.
|
||||||
|
// - This is used to implement host functions such as WASI
|
||||||
|
// `clock_time_get` with the `realtime` clock ID.
|
||||||
|
// - Use WithSysWalltime for a usable implementation.
|
||||||
|
WithWalltime(sys.Walltime, sys.ClockResolution) ModuleConfig
|
||||||
|
|
||||||
|
// WithSysWalltime uses time.Now for sys.Walltime with a resolution of 1us
|
||||||
|
// (1000ns).
|
||||||
|
//
|
||||||
|
// See WithWalltime
|
||||||
|
WithSysWalltime() ModuleConfig
|
||||||
|
|
||||||
|
// WithNanotime configures the monotonic clock, used to measure elapsed
|
||||||
|
// time in nanoseconds. Defaults to a fake result that increases by 1ms
|
||||||
|
// on each reading.
|
||||||
|
//
|
||||||
|
// Here's an example that uses a custom clock:
|
||||||
|
// moduleConfig = moduleConfig.
|
||||||
|
// WithNanotime(func(context.Context) int64 {
|
||||||
|
// return clock.nanotime()
|
||||||
|
// }, sys.ClockResolution(time.Microsecond.Nanoseconds()))
|
||||||
|
//
|
||||||
|
// # Notes:
|
||||||
|
// - This does not default to time.Since as that violates sandboxing.
|
||||||
|
// - This is used to implement host functions such as WASI
|
||||||
|
// `clock_time_get` with the `monotonic` clock ID.
|
||||||
|
// - Some compilers implement sleep by looping on sys.Nanotime (e.g. Go).
|
||||||
|
// - If you set this, you should probably set WithNanosleep also.
|
||||||
|
// - Use WithSysNanotime for a usable implementation.
|
||||||
|
WithNanotime(sys.Nanotime, sys.ClockResolution) ModuleConfig
|
||||||
|
|
||||||
|
// WithSysNanotime uses time.Now for sys.Nanotime with a resolution of 1us.
|
||||||
|
//
|
||||||
|
// See WithNanotime
|
||||||
|
WithSysNanotime() ModuleConfig
|
||||||
|
|
||||||
|
// WithNanosleep configures the how to pause the current goroutine for at
|
||||||
|
// least the configured nanoseconds. Defaults to return immediately.
|
||||||
|
//
|
||||||
|
// This example uses a custom sleep function:
|
||||||
|
// moduleConfig = moduleConfig.
|
||||||
|
// WithNanosleep(func(ns int64) {
|
||||||
|
// rel := unix.NsecToTimespec(ns)
|
||||||
|
// remain := unix.Timespec{}
|
||||||
|
// for { // loop until no more time remaining
|
||||||
|
// err := unix.ClockNanosleep(unix.CLOCK_MONOTONIC, 0, &rel, &remain)
|
||||||
|
// --snip--
|
||||||
|
//
|
||||||
|
// # Notes:
|
||||||
|
// - This does not default to time.Sleep as that violates sandboxing.
|
||||||
|
// - This is used to implement host functions such as WASI `poll_oneoff`.
|
||||||
|
// - Some compilers implement sleep by looping on sys.Nanotime (e.g. Go).
|
||||||
|
// - If you set this, you should probably set WithNanotime also.
|
||||||
|
// - Use WithSysNanosleep for a usable implementation.
|
||||||
|
WithNanosleep(sys.Nanosleep) ModuleConfig
|
||||||
|
|
||||||
|
// WithOsyield yields the processor, typically to implement spin-wait
|
||||||
|
// loops. Defaults to return immediately.
|
||||||
|
//
|
||||||
|
// # Notes:
|
||||||
|
// - This primarily supports `sched_yield` in WASI
|
||||||
|
// - This does not default to runtime.osyield as that violates sandboxing.
|
||||||
|
WithOsyield(sys.Osyield) ModuleConfig
|
||||||
|
|
||||||
|
// WithSysNanosleep uses time.Sleep for sys.Nanosleep.
|
||||||
|
//
|
||||||
|
// See WithNanosleep
|
||||||
|
WithSysNanosleep() ModuleConfig
|
||||||
|
|
||||||
|
// WithRandSource configures a source of random bytes. Defaults to return a
|
||||||
|
// deterministic source. You might override this with crypto/rand.Reader
|
||||||
|
//
|
||||||
|
// This reader is most commonly used by the functions like "random_get" in
|
||||||
|
// "wasi_snapshot_preview1", "seed" in AssemblyScript standard "env", and
|
||||||
|
// "getRandomData" when runtime.GOOS is "js".
|
||||||
|
//
|
||||||
|
// Note: The caller is responsible to close any io.Reader they supply: It
|
||||||
|
// is not closed on api.Module Close.
|
||||||
|
WithRandSource(io.Reader) ModuleConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
type moduleConfig struct {
|
||||||
|
name string
|
||||||
|
nameSet bool
|
||||||
|
startFunctions []string
|
||||||
|
stdin io.Reader
|
||||||
|
stdout io.Writer
|
||||||
|
stderr io.Writer
|
||||||
|
randSource io.Reader
|
||||||
|
walltime sys.Walltime
|
||||||
|
walltimeResolution sys.ClockResolution
|
||||||
|
nanotime sys.Nanotime
|
||||||
|
nanotimeResolution sys.ClockResolution
|
||||||
|
nanosleep sys.Nanosleep
|
||||||
|
osyield sys.Osyield
|
||||||
|
args [][]byte
|
||||||
|
// environ is pair-indexed to retain order similar to os.Environ.
|
||||||
|
environ [][]byte
|
||||||
|
// environKeys allow overwriting of existing values.
|
||||||
|
environKeys map[string]int
|
||||||
|
// fsConfig is the file system configuration for ABI like WASI.
|
||||||
|
fsConfig FSConfig
|
||||||
|
// sockConfig is the network listener configuration for ABI like WASI.
|
||||||
|
sockConfig *internalsock.Config
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewModuleConfig returns a ModuleConfig that can be used for configuring module instantiation.
|
||||||
|
func NewModuleConfig() ModuleConfig {
|
||||||
|
return &moduleConfig{
|
||||||
|
startFunctions: []string{"_start"},
|
||||||
|
environKeys: map[string]int{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// clone makes a deep copy of this module config.
|
||||||
|
func (c *moduleConfig) clone() *moduleConfig {
|
||||||
|
ret := *c // copy except maps which share a ref
|
||||||
|
ret.environKeys = make(map[string]int, len(c.environKeys))
|
||||||
|
for key, value := range c.environKeys {
|
||||||
|
ret.environKeys[key] = value
|
||||||
|
}
|
||||||
|
return &ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithArgs implements ModuleConfig.WithArgs
|
||||||
|
func (c *moduleConfig) WithArgs(args ...string) ModuleConfig {
|
||||||
|
ret := c.clone()
|
||||||
|
ret.args = toByteSlices(args)
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func toByteSlices(strings []string) (result [][]byte) {
|
||||||
|
if len(strings) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
result = make([][]byte, len(strings))
|
||||||
|
for i, a := range strings {
|
||||||
|
result[i] = []byte(a)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithEnv implements ModuleConfig.WithEnv
|
||||||
|
func (c *moduleConfig) WithEnv(key, value string) ModuleConfig {
|
||||||
|
ret := c.clone()
|
||||||
|
// Check to see if this key already exists and update it.
|
||||||
|
if i, ok := ret.environKeys[key]; ok {
|
||||||
|
ret.environ[i+1] = []byte(value) // environ is pair-indexed, so the value is 1 after the key.
|
||||||
|
} else {
|
||||||
|
ret.environKeys[key] = len(ret.environ)
|
||||||
|
ret.environ = append(ret.environ, []byte(key), []byte(value))
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithFS implements ModuleConfig.WithFS
|
||||||
|
func (c *moduleConfig) WithFS(fs fs.FS) ModuleConfig {
|
||||||
|
var config FSConfig
|
||||||
|
if fs != nil {
|
||||||
|
config = NewFSConfig().WithFSMount(fs, "")
|
||||||
|
}
|
||||||
|
return c.WithFSConfig(config)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithFSConfig implements ModuleConfig.WithFSConfig
|
||||||
|
func (c *moduleConfig) WithFSConfig(config FSConfig) ModuleConfig {
|
||||||
|
ret := c.clone()
|
||||||
|
ret.fsConfig = config
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithName implements ModuleConfig.WithName
|
||||||
|
func (c *moduleConfig) WithName(name string) ModuleConfig {
|
||||||
|
ret := c.clone()
|
||||||
|
ret.nameSet = true
|
||||||
|
ret.name = name
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithStartFunctions implements ModuleConfig.WithStartFunctions
|
||||||
|
func (c *moduleConfig) WithStartFunctions(startFunctions ...string) ModuleConfig {
|
||||||
|
ret := c.clone()
|
||||||
|
ret.startFunctions = startFunctions
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithStderr implements ModuleConfig.WithStderr
|
||||||
|
func (c *moduleConfig) WithStderr(stderr io.Writer) ModuleConfig {
|
||||||
|
ret := c.clone()
|
||||||
|
ret.stderr = stderr
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithStdin implements ModuleConfig.WithStdin
|
||||||
|
func (c *moduleConfig) WithStdin(stdin io.Reader) ModuleConfig {
|
||||||
|
ret := c.clone()
|
||||||
|
ret.stdin = stdin
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithStdout implements ModuleConfig.WithStdout
|
||||||
|
func (c *moduleConfig) WithStdout(stdout io.Writer) ModuleConfig {
|
||||||
|
ret := c.clone()
|
||||||
|
ret.stdout = stdout
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithWalltime implements ModuleConfig.WithWalltime
|
||||||
|
func (c *moduleConfig) WithWalltime(walltime sys.Walltime, resolution sys.ClockResolution) ModuleConfig {
|
||||||
|
ret := c.clone()
|
||||||
|
ret.walltime = walltime
|
||||||
|
ret.walltimeResolution = resolution
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// We choose arbitrary resolutions here because there's no perfect alternative. For example, according to the
|
||||||
|
// source in time.go, windows monotonic resolution can be 15ms. This chooses arbitrarily 1us for wall time and
|
||||||
|
// 1ns for monotonic. See RATIONALE.md for more context.
|
||||||
|
|
||||||
|
// WithSysWalltime implements ModuleConfig.WithSysWalltime
|
||||||
|
func (c *moduleConfig) WithSysWalltime() ModuleConfig {
|
||||||
|
return c.WithWalltime(platform.Walltime, sys.ClockResolution(time.Microsecond.Nanoseconds()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithNanotime implements ModuleConfig.WithNanotime
|
||||||
|
func (c *moduleConfig) WithNanotime(nanotime sys.Nanotime, resolution sys.ClockResolution) ModuleConfig {
|
||||||
|
ret := c.clone()
|
||||||
|
ret.nanotime = nanotime
|
||||||
|
ret.nanotimeResolution = resolution
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithSysNanotime implements ModuleConfig.WithSysNanotime
|
||||||
|
func (c *moduleConfig) WithSysNanotime() ModuleConfig {
|
||||||
|
return c.WithNanotime(platform.Nanotime, sys.ClockResolution(1))
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithNanosleep implements ModuleConfig.WithNanosleep
|
||||||
|
func (c *moduleConfig) WithNanosleep(nanosleep sys.Nanosleep) ModuleConfig {
|
||||||
|
ret := *c // copy
|
||||||
|
ret.nanosleep = nanosleep
|
||||||
|
return &ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithOsyield implements ModuleConfig.WithOsyield
|
||||||
|
func (c *moduleConfig) WithOsyield(osyield sys.Osyield) ModuleConfig {
|
||||||
|
ret := *c // copy
|
||||||
|
ret.osyield = osyield
|
||||||
|
return &ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithSysNanosleep implements ModuleConfig.WithSysNanosleep
|
||||||
|
func (c *moduleConfig) WithSysNanosleep() ModuleConfig {
|
||||||
|
return c.WithNanosleep(platform.Nanosleep)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithRandSource implements ModuleConfig.WithRandSource
|
||||||
|
func (c *moduleConfig) WithRandSource(source io.Reader) ModuleConfig {
|
||||||
|
ret := c.clone()
|
||||||
|
ret.randSource = source
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// toSysContext creates a baseline wasm.Context configured by ModuleConfig.
|
||||||
|
func (c *moduleConfig) toSysContext() (sysCtx *internalsys.Context, err error) {
|
||||||
|
var environ [][]byte // Intentionally doesn't pre-allocate to reduce logic to default to nil.
|
||||||
|
// Same validation as syscall.Setenv for Linux
|
||||||
|
for i := 0; i < len(c.environ); i += 2 {
|
||||||
|
key, value := c.environ[i], c.environ[i+1]
|
||||||
|
keyLen := len(key)
|
||||||
|
if keyLen == 0 {
|
||||||
|
err = errors.New("environ invalid: empty key")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
valueLen := len(value)
|
||||||
|
result := make([]byte, keyLen+valueLen+1)
|
||||||
|
j := 0
|
||||||
|
for ; j < keyLen; j++ {
|
||||||
|
if k := key[j]; k == '=' { // NUL enforced in NewContext
|
||||||
|
err = errors.New("environ invalid: key contains '=' character")
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
result[j] = k
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result[j] = '='
|
||||||
|
copy(result[j+1:], value)
|
||||||
|
environ = append(environ, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
var fs []experimentalsys.FS
|
||||||
|
var guestPaths []string
|
||||||
|
if f, ok := c.fsConfig.(*fsConfig); ok {
|
||||||
|
fs, guestPaths = f.preopens()
|
||||||
|
}
|
||||||
|
|
||||||
|
var listeners []*net.TCPListener
|
||||||
|
if n := c.sockConfig; n != nil {
|
||||||
|
if listeners, err = n.BuildTCPListeners(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return internalsys.NewContext(
|
||||||
|
math.MaxUint32,
|
||||||
|
c.args,
|
||||||
|
environ,
|
||||||
|
c.stdin,
|
||||||
|
c.stdout,
|
||||||
|
c.stderr,
|
||||||
|
c.randSource,
|
||||||
|
c.walltime, c.walltimeResolution,
|
||||||
|
c.nanotime, c.nanotimeResolution,
|
||||||
|
c.nanosleep, c.osyield,
|
||||||
|
fs, guestPaths,
|
||||||
|
listeners,
|
||||||
|
)
|
||||||
|
}
|
||||||
35
vendor/github.com/tetratelabs/wazero/experimental/checkpoint.go
generated
vendored
Normal file
35
vendor/github.com/tetratelabs/wazero/experimental/checkpoint.go
generated
vendored
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
package experimental
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/tetratelabs/wazero/internal/expctxkeys"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Snapshot holds the execution state at the time of a Snapshotter.Snapshot call.
|
||||||
|
type Snapshot interface {
|
||||||
|
// Restore sets the Wasm execution state to the capture. Because a host function
|
||||||
|
// calling this is resetting the pointer to the executation stack, the host function
|
||||||
|
// will not be able to return values in the normal way. ret is a slice of values the
|
||||||
|
// host function intends to return from the restored function.
|
||||||
|
Restore(ret []uint64)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Snapshotter allows host functions to snapshot the WebAssembly execution environment.
|
||||||
|
type Snapshotter interface {
|
||||||
|
// Snapshot captures the current execution state.
|
||||||
|
Snapshot() Snapshot
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithSnapshotter enables snapshots.
|
||||||
|
// Passing the returned context to a exported function invocation enables snapshots,
|
||||||
|
// and allows host functions to retrieve the Snapshotter using GetSnapshotter.
|
||||||
|
func WithSnapshotter(ctx context.Context) context.Context {
|
||||||
|
return context.WithValue(ctx, expctxkeys.EnableSnapshotterKey{}, struct{}{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSnapshotter gets the Snapshotter from a host function.
|
||||||
|
// It is only present if WithSnapshotter was called with the function invocation context.
|
||||||
|
func GetSnapshotter(ctx context.Context) Snapshotter {
|
||||||
|
return ctx.Value(expctxkeys.SnapshotterKey{}).(Snapshotter)
|
||||||
|
}
|
||||||
63
vendor/github.com/tetratelabs/wazero/experimental/close.go
generated
vendored
Normal file
63
vendor/github.com/tetratelabs/wazero/experimental/close.go
generated
vendored
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
package experimental
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/tetratelabs/wazero/internal/expctxkeys"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CloseNotifier is a notification hook, invoked when a module is closed.
|
||||||
|
//
|
||||||
|
// Note: This is experimental progress towards #1197, and likely to change. Do
|
||||||
|
// not expose this in shared libraries as it can cause version locks.
|
||||||
|
type CloseNotifier interface {
|
||||||
|
// CloseNotify is a notification that occurs *before* an api.Module is
|
||||||
|
// closed. `exitCode` is zero on success or in the case there was no exit
|
||||||
|
// code.
|
||||||
|
//
|
||||||
|
// Notes:
|
||||||
|
// - This does not return an error because the module will be closed
|
||||||
|
// unconditionally.
|
||||||
|
// - Do not panic from this function as it doing so could cause resource
|
||||||
|
// leaks.
|
||||||
|
// - While this is only called once per module, if configured for
|
||||||
|
// multiple modules, it will be called for each, e.g. on runtime close.
|
||||||
|
CloseNotify(ctx context.Context, exitCode uint32)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ^-- Note: This might need to be a part of the listener or become a part of
|
||||||
|
// host state implementation. For example, if this is used to implement state
|
||||||
|
// cleanup for host modules, possibly something like below would be better, as
|
||||||
|
// it could be implemented in a way that allows concurrent module use.
|
||||||
|
//
|
||||||
|
// // key is like a context key, stateFactory is invoked per instantiate and
|
||||||
|
// // is associated with the key (exposed as `Module.State` similar to go
|
||||||
|
// // context). Using a key is better than the module name because we can
|
||||||
|
// // de-dupe it for host modules that can be instantiated into different
|
||||||
|
// // names. Also, you can make the key package private.
|
||||||
|
// HostModuleBuilder.WithState(key any, stateFactory func() Cleanup)`
|
||||||
|
//
|
||||||
|
// Such a design could work to isolate state only needed for wasip1, for
|
||||||
|
// example the dirent cache. However, if end users use this for different
|
||||||
|
// things, we may need separate designs.
|
||||||
|
//
|
||||||
|
// In summary, the purpose of this iteration is to identify projects that
|
||||||
|
// would use something like this, and then we can figure out which way it
|
||||||
|
// should go.
|
||||||
|
|
||||||
|
// CloseNotifyFunc is a convenience for defining inlining a CloseNotifier.
|
||||||
|
type CloseNotifyFunc func(ctx context.Context, exitCode uint32)
|
||||||
|
|
||||||
|
// CloseNotify implements CloseNotifier.CloseNotify.
|
||||||
|
func (f CloseNotifyFunc) CloseNotify(ctx context.Context, exitCode uint32) {
|
||||||
|
f(ctx, exitCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithCloseNotifier registers the given CloseNotifier into the given
|
||||||
|
// context.Context.
|
||||||
|
func WithCloseNotifier(ctx context.Context, notifier CloseNotifier) context.Context {
|
||||||
|
if notifier != nil {
|
||||||
|
return context.WithValue(ctx, expctxkeys.CloseNotifierKey{}, notifier)
|
||||||
|
}
|
||||||
|
return ctx
|
||||||
|
}
|
||||||
41
vendor/github.com/tetratelabs/wazero/experimental/experimental.go
generated
vendored
Normal file
41
vendor/github.com/tetratelabs/wazero/experimental/experimental.go
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
// Package experimental includes features we aren't yet sure about. These are enabled with context.Context keys.
|
||||||
|
//
|
||||||
|
// Note: All features here may be changed or deleted at any time, so use with caution!
|
||||||
|
package experimental
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/tetratelabs/wazero/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
// InternalModule is an api.Module that exposes additional
|
||||||
|
// information.
|
||||||
|
type InternalModule interface {
|
||||||
|
api.Module
|
||||||
|
|
||||||
|
// NumGlobal returns the count of all globals in the module.
|
||||||
|
NumGlobal() int
|
||||||
|
|
||||||
|
// Global provides a read-only view for a given global index.
|
||||||
|
//
|
||||||
|
// The methods panics if i is out of bounds.
|
||||||
|
Global(i int) api.Global
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProgramCounter is an opaque value representing a specific execution point in
|
||||||
|
// a module. It is meant to be used with Function.SourceOffsetForPC and
|
||||||
|
// StackIterator.
|
||||||
|
type ProgramCounter uint64
|
||||||
|
|
||||||
|
// InternalFunction exposes some information about a function instance.
|
||||||
|
type InternalFunction interface {
|
||||||
|
// Definition provides introspection into the function's names and
|
||||||
|
// signature.
|
||||||
|
Definition() api.FunctionDefinition
|
||||||
|
|
||||||
|
// SourceOffsetForPC resolves a program counter into its corresponding
|
||||||
|
// offset in the Code section of the module this function belongs to.
|
||||||
|
// The source offset is meant to help map the function calls to their
|
||||||
|
// location in the original source files. Returns 0 if the offset cannot
|
||||||
|
// be calculated.
|
||||||
|
SourceOffsetForPC(pc ProgramCounter) uint64
|
||||||
|
}
|
||||||
15
vendor/github.com/tetratelabs/wazero/experimental/features.go
generated
vendored
Normal file
15
vendor/github.com/tetratelabs/wazero/experimental/features.go
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
package experimental
|
||||||
|
|
||||||
|
import "github.com/tetratelabs/wazero/api"
|
||||||
|
|
||||||
|
// CoreFeaturesThreads enables threads instructions ("threads").
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// - The instruction list is too long to enumerate in godoc.
|
||||||
|
// See https://github.com/WebAssembly/threads/blob/main/proposals/threads/Overview.md
|
||||||
|
// - Atomic operations are guest-only until api.Memory or otherwise expose them to host functions.
|
||||||
|
// - On systems without mmap available, the memory will pre-allocate to the maximum size. Many
|
||||||
|
// binaries will use a theroetical maximum like 4GB, so if using such a binary on a system
|
||||||
|
// without mmap, consider editing the binary to reduce the max size setting of memory.
|
||||||
|
const CoreFeaturesThreads = api.CoreFeatureSIMD << 1
|
||||||
19
vendor/github.com/tetratelabs/wazero/experimental/importresolver.go
generated
vendored
Normal file
19
vendor/github.com/tetratelabs/wazero/experimental/importresolver.go
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
package experimental
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/tetratelabs/wazero/api"
|
||||||
|
"github.com/tetratelabs/wazero/internal/expctxkeys"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ImportResolver is an experimental func type that, if set,
|
||||||
|
// will be used as the first step in resolving imports.
|
||||||
|
// See issue 2294.
|
||||||
|
// If the import name is not found, it should return nil.
|
||||||
|
type ImportResolver func(name string) api.Module
|
||||||
|
|
||||||
|
// WithImportResolver returns a new context with the given ImportResolver.
|
||||||
|
func WithImportResolver(ctx context.Context, resolver ImportResolver) context.Context {
|
||||||
|
return context.WithValue(ctx, expctxkeys.ImportResolverKey{}, resolver)
|
||||||
|
}
|
||||||
324
vendor/github.com/tetratelabs/wazero/experimental/listener.go
generated
vendored
Normal file
324
vendor/github.com/tetratelabs/wazero/experimental/listener.go
generated
vendored
Normal file
@@ -0,0 +1,324 @@
|
|||||||
|
package experimental
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/tetratelabs/wazero/api"
|
||||||
|
"github.com/tetratelabs/wazero/internal/expctxkeys"
|
||||||
|
)
|
||||||
|
|
||||||
|
// StackIterator allows iterating on each function of the call stack, starting
|
||||||
|
// from the top. At least one call to Next() is required to start the iteration.
|
||||||
|
//
|
||||||
|
// Note: The iterator provides a view of the call stack at the time of
|
||||||
|
// iteration. As a result, parameter values may be different than the ones their
|
||||||
|
// function was called with.
|
||||||
|
type StackIterator interface {
|
||||||
|
// Next moves the iterator to the next function in the stack. Returns
|
||||||
|
// false if it reached the bottom of the stack.
|
||||||
|
Next() bool
|
||||||
|
// Function describes the function called by the current frame.
|
||||||
|
Function() InternalFunction
|
||||||
|
// ProgramCounter returns the program counter associated with the
|
||||||
|
// function call.
|
||||||
|
ProgramCounter() ProgramCounter
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithFunctionListenerFactory registers a FunctionListenerFactory
|
||||||
|
// with the context.
|
||||||
|
func WithFunctionListenerFactory(ctx context.Context, factory FunctionListenerFactory) context.Context {
|
||||||
|
return context.WithValue(ctx, expctxkeys.FunctionListenerFactoryKey{}, factory)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FunctionListenerFactory returns FunctionListeners to be notified when a
|
||||||
|
// function is called.
|
||||||
|
type FunctionListenerFactory interface {
|
||||||
|
// NewFunctionListener returns a FunctionListener for a defined function.
|
||||||
|
// If nil is returned, no listener will be notified.
|
||||||
|
NewFunctionListener(api.FunctionDefinition) FunctionListener
|
||||||
|
// ^^ A single instance can be returned to avoid instantiating a listener
|
||||||
|
// per function, especially as they may be thousands of functions. Shared
|
||||||
|
// listeners use their FunctionDefinition parameter to clarify.
|
||||||
|
}
|
||||||
|
|
||||||
|
// FunctionListener can be registered for any function via
|
||||||
|
// FunctionListenerFactory to be notified when the function is called.
|
||||||
|
type FunctionListener interface {
|
||||||
|
// Before is invoked before a function is called.
|
||||||
|
//
|
||||||
|
// There is always one corresponding call to After or Abort for each call to
|
||||||
|
// Before. This guarantee allows the listener to maintain an internal stack
|
||||||
|
// to perform correlations between the entry and exit of functions.
|
||||||
|
//
|
||||||
|
// # Params
|
||||||
|
//
|
||||||
|
// - ctx: the context of the caller function which must be the same
|
||||||
|
// instance or parent of the result.
|
||||||
|
// - mod: the calling module.
|
||||||
|
// - def: the function definition.
|
||||||
|
// - params: api.ValueType encoded parameters.
|
||||||
|
// - stackIterator: iterator on the call stack. At least one entry is
|
||||||
|
// guaranteed (the called function), whose Args() will be equal to
|
||||||
|
// params. The iterator will be reused between calls to Before.
|
||||||
|
//
|
||||||
|
// Note: api.Memory is meant for inspection, not modification.
|
||||||
|
// mod can be cast to InternalModule to read non-exported globals.
|
||||||
|
Before(ctx context.Context, mod api.Module, def api.FunctionDefinition, params []uint64, stackIterator StackIterator)
|
||||||
|
|
||||||
|
// After is invoked after a function is called.
|
||||||
|
//
|
||||||
|
// # Params
|
||||||
|
//
|
||||||
|
// - ctx: the context of the caller function.
|
||||||
|
// - mod: the calling module.
|
||||||
|
// - def: the function definition.
|
||||||
|
// - results: api.ValueType encoded results.
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// - api.Memory is meant for inspection, not modification.
|
||||||
|
// - This is not called when a host function panics, or a guest function traps.
|
||||||
|
// See Abort for more details.
|
||||||
|
After(ctx context.Context, mod api.Module, def api.FunctionDefinition, results []uint64)
|
||||||
|
|
||||||
|
// Abort is invoked when a function does not return due to a trap or panic.
|
||||||
|
//
|
||||||
|
// # Params
|
||||||
|
//
|
||||||
|
// - ctx: the context of the caller function.
|
||||||
|
// - mod: the calling module.
|
||||||
|
// - def: the function definition.
|
||||||
|
// - err: the error value representing the reason why the function aborted.
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// - api.Memory is meant for inspection, not modification.
|
||||||
|
Abort(ctx context.Context, mod api.Module, def api.FunctionDefinition, err error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FunctionListenerFunc is a function type implementing the FunctionListener
|
||||||
|
// interface, making it possible to use regular functions and methods as
|
||||||
|
// listeners of function invocation.
|
||||||
|
//
|
||||||
|
// The FunctionListener interface declares two methods (Before and After),
|
||||||
|
// but this type invokes its value only when Before is called. It is best
|
||||||
|
// suites for cases where the host does not need to perform correlation
|
||||||
|
// between the start and end of the function call.
|
||||||
|
type FunctionListenerFunc func(context.Context, api.Module, api.FunctionDefinition, []uint64, StackIterator)
|
||||||
|
|
||||||
|
// Before satisfies the FunctionListener interface, calls f.
|
||||||
|
func (f FunctionListenerFunc) Before(ctx context.Context, mod api.Module, def api.FunctionDefinition, params []uint64, stackIterator StackIterator) {
|
||||||
|
f(ctx, mod, def, params, stackIterator)
|
||||||
|
}
|
||||||
|
|
||||||
|
// After is declared to satisfy the FunctionListener interface, but it does
|
||||||
|
// nothing.
|
||||||
|
func (f FunctionListenerFunc) After(context.Context, api.Module, api.FunctionDefinition, []uint64) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Abort is declared to satisfy the FunctionListener interface, but it does
|
||||||
|
// nothing.
|
||||||
|
func (f FunctionListenerFunc) Abort(context.Context, api.Module, api.FunctionDefinition, error) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// FunctionListenerFactoryFunc is a function type implementing the
|
||||||
|
// FunctionListenerFactory interface, making it possible to use regular
|
||||||
|
// functions and methods as factory of function listeners.
|
||||||
|
type FunctionListenerFactoryFunc func(api.FunctionDefinition) FunctionListener
|
||||||
|
|
||||||
|
// NewFunctionListener satisfies the FunctionListenerFactory interface, calls f.
|
||||||
|
func (f FunctionListenerFactoryFunc) NewFunctionListener(def api.FunctionDefinition) FunctionListener {
|
||||||
|
return f(def)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MultiFunctionListenerFactory constructs a FunctionListenerFactory which
|
||||||
|
// combines the listeners created by each of the factories passed as arguments.
|
||||||
|
//
|
||||||
|
// This function is useful when multiple listeners need to be hooked to a module
|
||||||
|
// because the propagation mechanism based on installing a listener factory in
|
||||||
|
// the context.Context used when instantiating modules allows for a single
|
||||||
|
// listener to be installed.
|
||||||
|
//
|
||||||
|
// The stack iterator passed to the Before method is reset so that each listener
|
||||||
|
// can iterate the call stack independently without impacting the ability of
|
||||||
|
// other listeners to do so.
|
||||||
|
func MultiFunctionListenerFactory(factories ...FunctionListenerFactory) FunctionListenerFactory {
|
||||||
|
multi := make(multiFunctionListenerFactory, len(factories))
|
||||||
|
copy(multi, factories)
|
||||||
|
return multi
|
||||||
|
}
|
||||||
|
|
||||||
|
type multiFunctionListenerFactory []FunctionListenerFactory
|
||||||
|
|
||||||
|
func (multi multiFunctionListenerFactory) NewFunctionListener(def api.FunctionDefinition) FunctionListener {
|
||||||
|
var lstns []FunctionListener
|
||||||
|
for _, factory := range multi {
|
||||||
|
if lstn := factory.NewFunctionListener(def); lstn != nil {
|
||||||
|
lstns = append(lstns, lstn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch len(lstns) {
|
||||||
|
case 0:
|
||||||
|
return nil
|
||||||
|
case 1:
|
||||||
|
return lstns[0]
|
||||||
|
default:
|
||||||
|
return &multiFunctionListener{lstns: lstns}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type multiFunctionListener struct {
|
||||||
|
lstns []FunctionListener
|
||||||
|
stack stackIterator
|
||||||
|
}
|
||||||
|
|
||||||
|
func (multi *multiFunctionListener) Before(ctx context.Context, mod api.Module, def api.FunctionDefinition, params []uint64, si StackIterator) {
|
||||||
|
multi.stack.base = si
|
||||||
|
for _, lstn := range multi.lstns {
|
||||||
|
multi.stack.index = -1
|
||||||
|
lstn.Before(ctx, mod, def, params, &multi.stack)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (multi *multiFunctionListener) After(ctx context.Context, mod api.Module, def api.FunctionDefinition, results []uint64) {
|
||||||
|
for _, lstn := range multi.lstns {
|
||||||
|
lstn.After(ctx, mod, def, results)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (multi *multiFunctionListener) Abort(ctx context.Context, mod api.Module, def api.FunctionDefinition, err error) {
|
||||||
|
for _, lstn := range multi.lstns {
|
||||||
|
lstn.Abort(ctx, mod, def, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type stackIterator struct {
|
||||||
|
base StackIterator
|
||||||
|
index int
|
||||||
|
pcs []uint64
|
||||||
|
fns []InternalFunction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (si *stackIterator) Next() bool {
|
||||||
|
if si.base != nil {
|
||||||
|
si.pcs = si.pcs[:0]
|
||||||
|
si.fns = si.fns[:0]
|
||||||
|
|
||||||
|
for si.base.Next() {
|
||||||
|
si.pcs = append(si.pcs, uint64(si.base.ProgramCounter()))
|
||||||
|
si.fns = append(si.fns, si.base.Function())
|
||||||
|
}
|
||||||
|
|
||||||
|
si.base = nil
|
||||||
|
}
|
||||||
|
si.index++
|
||||||
|
return si.index < len(si.pcs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (si *stackIterator) ProgramCounter() ProgramCounter {
|
||||||
|
return ProgramCounter(si.pcs[si.index])
|
||||||
|
}
|
||||||
|
|
||||||
|
func (si *stackIterator) Function() InternalFunction {
|
||||||
|
return si.fns[si.index]
|
||||||
|
}
|
||||||
|
|
||||||
|
// StackFrame represents a frame on the call stack.
|
||||||
|
type StackFrame struct {
|
||||||
|
Function api.Function
|
||||||
|
Params []uint64
|
||||||
|
Results []uint64
|
||||||
|
PC uint64
|
||||||
|
SourceOffset uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
type internalFunction struct {
|
||||||
|
definition api.FunctionDefinition
|
||||||
|
sourceOffset uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f internalFunction) Definition() api.FunctionDefinition {
|
||||||
|
return f.definition
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f internalFunction) SourceOffsetForPC(pc ProgramCounter) uint64 {
|
||||||
|
return f.sourceOffset
|
||||||
|
}
|
||||||
|
|
||||||
|
// stackFrameIterator is an implementation of the experimental.stackFrameIterator
|
||||||
|
// interface.
|
||||||
|
type stackFrameIterator struct {
|
||||||
|
index int
|
||||||
|
stack []StackFrame
|
||||||
|
fndef []api.FunctionDefinition
|
||||||
|
}
|
||||||
|
|
||||||
|
func (si *stackFrameIterator) Next() bool {
|
||||||
|
si.index++
|
||||||
|
return si.index < len(si.stack)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (si *stackFrameIterator) Function() InternalFunction {
|
||||||
|
return internalFunction{
|
||||||
|
definition: si.fndef[si.index],
|
||||||
|
sourceOffset: si.stack[si.index].SourceOffset,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (si *stackFrameIterator) ProgramCounter() ProgramCounter {
|
||||||
|
return ProgramCounter(si.stack[si.index].PC)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewStackIterator constructs a stack iterator from a list of stack frames.
|
||||||
|
// The top most frame is the last one.
|
||||||
|
func NewStackIterator(stack ...StackFrame) StackIterator {
|
||||||
|
si := &stackFrameIterator{
|
||||||
|
index: -1,
|
||||||
|
stack: make([]StackFrame, len(stack)),
|
||||||
|
fndef: make([]api.FunctionDefinition, len(stack)),
|
||||||
|
}
|
||||||
|
for i := range stack {
|
||||||
|
si.stack[i] = stack[len(stack)-(i+1)]
|
||||||
|
}
|
||||||
|
// The size of function definition is only one pointer which should allow
|
||||||
|
// the compiler to optimize the conversion to api.FunctionDefinition; but
|
||||||
|
// the presence of internal.WazeroOnlyType, despite being defined as an
|
||||||
|
// empty struct, forces a heap allocation that we amortize by caching the
|
||||||
|
// result.
|
||||||
|
for i, frame := range stack {
|
||||||
|
si.fndef[i] = frame.Function.Definition()
|
||||||
|
}
|
||||||
|
return si
|
||||||
|
}
|
||||||
|
|
||||||
|
// BenchmarkFunctionListener implements a benchmark for function listeners.
|
||||||
|
//
|
||||||
|
// The benchmark calls Before and After methods repeatedly using the provided
|
||||||
|
// module an stack frames to invoke the methods.
|
||||||
|
//
|
||||||
|
// The stack frame is a representation of the call stack that the Before method
|
||||||
|
// will be invoked with. The top of the stack is stored at index zero. The stack
|
||||||
|
// must contain at least one frame or the benchmark will fail.
|
||||||
|
func BenchmarkFunctionListener(n int, module api.Module, stack []StackFrame, listener FunctionListener) {
|
||||||
|
if len(stack) == 0 {
|
||||||
|
panic("cannot benchmark function listener with an empty stack")
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
def := stack[0].Function.Definition()
|
||||||
|
params := stack[0].Params
|
||||||
|
results := stack[0].Results
|
||||||
|
stackIterator := &stackIterator{base: NewStackIterator(stack...)}
|
||||||
|
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
stackIterator.index = -1
|
||||||
|
listener.Before(ctx, module, def, params, stackIterator)
|
||||||
|
listener.After(ctx, module, def, results)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: the calls to Abort are not yet tested in internal/testing/enginetest,
|
||||||
|
// but they are validated indirectly in tests which exercise host logging,
|
||||||
|
// like Test_procExit in imports/wasi_snapshot_preview1. Eventually we should
|
||||||
|
// add dedicated tests to validate the behavior of the interpreter and compiler
|
||||||
|
// engines independently.
|
||||||
52
vendor/github.com/tetratelabs/wazero/experimental/memory.go
generated
vendored
Normal file
52
vendor/github.com/tetratelabs/wazero/experimental/memory.go
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
package experimental
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/tetratelabs/wazero/internal/expctxkeys"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MemoryAllocator is a memory allocation hook,
|
||||||
|
// invoked to create a LinearMemory.
|
||||||
|
type MemoryAllocator interface {
|
||||||
|
// Allocate should create a new LinearMemory with the given specification:
|
||||||
|
// cap is the suggested initial capacity for the backing []byte,
|
||||||
|
// and max the maximum length that will ever be requested.
|
||||||
|
//
|
||||||
|
// Notes:
|
||||||
|
// - To back a shared memory, the address of the backing []byte cannot
|
||||||
|
// change. This is checked at runtime. Implementations should document
|
||||||
|
// if the returned LinearMemory meets this requirement.
|
||||||
|
Allocate(cap, max uint64) LinearMemory
|
||||||
|
}
|
||||||
|
|
||||||
|
// MemoryAllocatorFunc is a convenience for defining inlining a MemoryAllocator.
|
||||||
|
type MemoryAllocatorFunc func(cap, max uint64) LinearMemory
|
||||||
|
|
||||||
|
// Allocate implements MemoryAllocator.Allocate.
|
||||||
|
func (f MemoryAllocatorFunc) Allocate(cap, max uint64) LinearMemory {
|
||||||
|
return f(cap, max)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LinearMemory is an expandable []byte that backs a Wasm linear memory.
|
||||||
|
type LinearMemory interface {
|
||||||
|
// Reallocates the linear memory to size bytes in length.
|
||||||
|
//
|
||||||
|
// Notes:
|
||||||
|
// - To back a shared memory, Reallocate can't change the address of the
|
||||||
|
// backing []byte (only its length/capacity may change).
|
||||||
|
// - Reallocate may return nil if fails to grow the LinearMemory. This
|
||||||
|
// condition may or may not be handled gracefully by the Wasm module.
|
||||||
|
Reallocate(size uint64) []byte
|
||||||
|
// Free the backing memory buffer.
|
||||||
|
Free()
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithMemoryAllocator registers the given MemoryAllocator into the given
|
||||||
|
// context.Context. The context must be passed when initializing a module.
|
||||||
|
func WithMemoryAllocator(ctx context.Context, allocator MemoryAllocator) context.Context {
|
||||||
|
if allocator != nil {
|
||||||
|
return context.WithValue(ctx, expctxkeys.MemoryAllocatorKey{}, allocator)
|
||||||
|
}
|
||||||
|
return ctx
|
||||||
|
}
|
||||||
92
vendor/github.com/tetratelabs/wazero/experimental/sys/dir.go
generated
vendored
Normal file
92
vendor/github.com/tetratelabs/wazero/experimental/sys/dir.go
generated
vendored
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
package sys
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/fs"
|
||||||
|
|
||||||
|
"github.com/tetratelabs/wazero/sys"
|
||||||
|
)
|
||||||
|
|
||||||
|
// FileType is fs.FileMode masked on fs.ModeType. For example, zero is a
|
||||||
|
// regular file, fs.ModeDir is a directory and fs.ModeIrregular is unknown.
|
||||||
|
//
|
||||||
|
// Note: This is defined by Linux, not POSIX.
|
||||||
|
type FileType = fs.FileMode
|
||||||
|
|
||||||
|
// Dirent is an entry read from a directory via File.Readdir.
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// - This extends `dirent` defined in POSIX with some fields defined by
|
||||||
|
// Linux. See https://man7.org/linux/man-pages/man3/readdir.3.html and
|
||||||
|
// https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/dirent.h.html
|
||||||
|
// - This has a subset of fields defined in sys.Stat_t. Notably, there is no
|
||||||
|
// field corresponding to Stat_t.Dev because that value will be constant
|
||||||
|
// for all files in a directory. To get the Dev value, call File.Stat on
|
||||||
|
// the directory File.Readdir was called on.
|
||||||
|
type Dirent struct {
|
||||||
|
// Ino is the file serial number, or zero if not available. See Ino for
|
||||||
|
// more details including impact returning a zero value.
|
||||||
|
Ino sys.Inode
|
||||||
|
|
||||||
|
// Name is the base name of the directory entry. Empty is invalid.
|
||||||
|
Name string
|
||||||
|
|
||||||
|
// Type is fs.FileMode masked on fs.ModeType. For example, zero is a
|
||||||
|
// regular file, fs.ModeDir is a directory and fs.ModeIrregular is unknown.
|
||||||
|
//
|
||||||
|
// Note: This is defined by Linux, not POSIX.
|
||||||
|
Type fs.FileMode
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dirent) String() string {
|
||||||
|
return fmt.Sprintf("name=%s, type=%v, ino=%d", d.Name, d.Type, d.Ino)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsDir returns true if the Type is fs.ModeDir.
|
||||||
|
func (d *Dirent) IsDir() bool {
|
||||||
|
return d.Type == fs.ModeDir
|
||||||
|
}
|
||||||
|
|
||||||
|
// DirFile is embeddable to reduce the amount of functions to implement a file.
|
||||||
|
type DirFile struct{}
|
||||||
|
|
||||||
|
// IsAppend implements File.IsAppend
|
||||||
|
func (DirFile) IsAppend() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetAppend implements File.SetAppend
|
||||||
|
func (DirFile) SetAppend(bool) Errno {
|
||||||
|
return EISDIR
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsDir implements File.IsDir
|
||||||
|
func (DirFile) IsDir() (bool, Errno) {
|
||||||
|
return true, 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read implements File.Read
|
||||||
|
func (DirFile) Read([]byte) (int, Errno) {
|
||||||
|
return 0, EISDIR
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pread implements File.Pread
|
||||||
|
func (DirFile) Pread([]byte, int64) (int, Errno) {
|
||||||
|
return 0, EISDIR
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write implements File.Write
|
||||||
|
func (DirFile) Write([]byte) (int, Errno) {
|
||||||
|
return 0, EISDIR
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pwrite implements File.Pwrite
|
||||||
|
func (DirFile) Pwrite([]byte, int64) (int, Errno) {
|
||||||
|
return 0, EISDIR
|
||||||
|
}
|
||||||
|
|
||||||
|
// Truncate implements File.Truncate
|
||||||
|
func (DirFile) Truncate(int64) Errno {
|
||||||
|
return EISDIR
|
||||||
|
}
|
||||||
98
vendor/github.com/tetratelabs/wazero/experimental/sys/errno.go
generated
vendored
Normal file
98
vendor/github.com/tetratelabs/wazero/experimental/sys/errno.go
generated
vendored
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
package sys
|
||||||
|
|
||||||
|
import "strconv"
|
||||||
|
|
||||||
|
// Errno is a subset of POSIX errno used by wazero interfaces. Zero is not an
|
||||||
|
// error. Other values should not be interpreted numerically, rather by constants
|
||||||
|
// prefixed with 'E'.
|
||||||
|
//
|
||||||
|
// See https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/errno.h.html
|
||||||
|
type Errno uint16
|
||||||
|
|
||||||
|
// ^-- Note: This will eventually move to the public /sys package. It is
|
||||||
|
// experimental until we audit the socket related APIs to ensure we have all
|
||||||
|
// the Errno it returns, and we export fs.FS. This is not in /internal/sys as
|
||||||
|
// that would introduce a package cycle.
|
||||||
|
|
||||||
|
// This is a subset of errors to reduce implementation burden. `wasip1` defines
|
||||||
|
// almost all POSIX error numbers, but not all are used in practice. wazero
|
||||||
|
// will add ones needed in POSIX order, as needed by functions that explicitly
|
||||||
|
// document returning them.
|
||||||
|
//
|
||||||
|
// https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-errno-enumu16
|
||||||
|
const (
|
||||||
|
EACCES Errno = iota + 1
|
||||||
|
EAGAIN
|
||||||
|
EBADF
|
||||||
|
EEXIST
|
||||||
|
EFAULT
|
||||||
|
EINTR
|
||||||
|
EINVAL
|
||||||
|
EIO
|
||||||
|
EISDIR
|
||||||
|
ELOOP
|
||||||
|
ENAMETOOLONG
|
||||||
|
ENOENT
|
||||||
|
ENOSYS
|
||||||
|
ENOTDIR
|
||||||
|
ERANGE
|
||||||
|
ENOTEMPTY
|
||||||
|
ENOTSOCK
|
||||||
|
ENOTSUP
|
||||||
|
EPERM
|
||||||
|
EROFS
|
||||||
|
|
||||||
|
// NOTE ENOTCAPABLE is defined in wasip1, but not in POSIX. wasi-libc
|
||||||
|
// converts it to EBADF, ESPIPE or EINVAL depending on the call site.
|
||||||
|
// It isn't known if compilers who don't use ENOTCAPABLE would crash on it.
|
||||||
|
)
|
||||||
|
|
||||||
|
// Error implements error
|
||||||
|
func (e Errno) Error() string {
|
||||||
|
switch e {
|
||||||
|
case 0: // not an error
|
||||||
|
return "success"
|
||||||
|
case EACCES:
|
||||||
|
return "permission denied"
|
||||||
|
case EAGAIN:
|
||||||
|
return "resource unavailable, try again"
|
||||||
|
case EBADF:
|
||||||
|
return "bad file descriptor"
|
||||||
|
case EEXIST:
|
||||||
|
return "file exists"
|
||||||
|
case EFAULT:
|
||||||
|
return "bad address"
|
||||||
|
case EINTR:
|
||||||
|
return "interrupted function"
|
||||||
|
case EINVAL:
|
||||||
|
return "invalid argument"
|
||||||
|
case EIO:
|
||||||
|
return "input/output error"
|
||||||
|
case EISDIR:
|
||||||
|
return "is a directory"
|
||||||
|
case ELOOP:
|
||||||
|
return "too many levels of symbolic links"
|
||||||
|
case ENAMETOOLONG:
|
||||||
|
return "filename too long"
|
||||||
|
case ENOENT:
|
||||||
|
return "no such file or directory"
|
||||||
|
case ENOSYS:
|
||||||
|
return "functionality not supported"
|
||||||
|
case ENOTDIR:
|
||||||
|
return "not a directory or a symbolic link to a directory"
|
||||||
|
case ERANGE:
|
||||||
|
return "result too large"
|
||||||
|
case ENOTEMPTY:
|
||||||
|
return "directory not empty"
|
||||||
|
case ENOTSOCK:
|
||||||
|
return "not a socket"
|
||||||
|
case ENOTSUP:
|
||||||
|
return "not supported (may be the same value as [EOPNOTSUPP])"
|
||||||
|
case EPERM:
|
||||||
|
return "operation not permitted"
|
||||||
|
case EROFS:
|
||||||
|
return "read-only file system"
|
||||||
|
default:
|
||||||
|
return "Errno(" + strconv.Itoa(int(e)) + ")"
|
||||||
|
}
|
||||||
|
}
|
||||||
45
vendor/github.com/tetratelabs/wazero/experimental/sys/error.go
generated
vendored
Normal file
45
vendor/github.com/tetratelabs/wazero/experimental/sys/error.go
generated
vendored
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
package sys
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"io/fs"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// UnwrapOSError returns an Errno or zero if the input is nil.
|
||||||
|
func UnwrapOSError(err error) Errno {
|
||||||
|
if err == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
err = underlyingError(err)
|
||||||
|
switch err {
|
||||||
|
case nil, io.EOF:
|
||||||
|
return 0 // EOF is not a Errno
|
||||||
|
case fs.ErrInvalid:
|
||||||
|
return EINVAL
|
||||||
|
case fs.ErrPermission:
|
||||||
|
return EPERM
|
||||||
|
case fs.ErrExist:
|
||||||
|
return EEXIST
|
||||||
|
case fs.ErrNotExist:
|
||||||
|
return ENOENT
|
||||||
|
case fs.ErrClosed:
|
||||||
|
return EBADF
|
||||||
|
}
|
||||||
|
return errorToErrno(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// underlyingError returns the underlying error if a well-known OS error type.
|
||||||
|
//
|
||||||
|
// This impl is basically the same as os.underlyingError in os/error.go
|
||||||
|
func underlyingError(err error) error {
|
||||||
|
switch err := err.(type) {
|
||||||
|
case *os.PathError:
|
||||||
|
return err.Err
|
||||||
|
case *os.LinkError:
|
||||||
|
return err.Err
|
||||||
|
case *os.SyscallError:
|
||||||
|
return err.Err
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
316
vendor/github.com/tetratelabs/wazero/experimental/sys/file.go
generated
vendored
Normal file
316
vendor/github.com/tetratelabs/wazero/experimental/sys/file.go
generated
vendored
Normal file
@@ -0,0 +1,316 @@
|
|||||||
|
package sys
|
||||||
|
|
||||||
|
import "github.com/tetratelabs/wazero/sys"
|
||||||
|
|
||||||
|
// File is a writeable fs.File bridge backed by syscall functions needed for ABI
|
||||||
|
// including WASI.
|
||||||
|
//
|
||||||
|
// Implementations should embed UnimplementedFile for forward compatibility. Any
|
||||||
|
// unsupported method or parameter should return ENOSYS.
|
||||||
|
//
|
||||||
|
// # Errors
|
||||||
|
//
|
||||||
|
// All methods that can return an error return a Errno, which is zero
|
||||||
|
// on success.
|
||||||
|
//
|
||||||
|
// Restricting to Errno matches current WebAssembly host functions,
|
||||||
|
// which are constrained to well-known error codes. For example, WASI maps syscall
|
||||||
|
// errors to u32 numeric values.
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// - You must call Close to avoid file resource conflicts. For example,
|
||||||
|
// Windows cannot delete the underlying directory while a handle to it
|
||||||
|
// remains open.
|
||||||
|
// - A writable filesystem abstraction is not yet implemented as of Go 1.20.
|
||||||
|
// See https://github.com/golang/go/issues/45757
|
||||||
|
type File interface {
|
||||||
|
// Dev returns the device ID (Stat_t.Dev) of this file, zero if unknown or
|
||||||
|
// an error retrieving it.
|
||||||
|
//
|
||||||
|
// # Errors
|
||||||
|
//
|
||||||
|
// Possible errors are those from Stat, except ENOSYS should not
|
||||||
|
// be returned. Zero should be returned if there is no implementation.
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// - Implementations should cache this result.
|
||||||
|
// - This combined with Ino can implement os.SameFile.
|
||||||
|
Dev() (uint64, Errno)
|
||||||
|
|
||||||
|
// Ino returns the serial number (Stat_t.Ino) of this file, zero if unknown
|
||||||
|
// or an error retrieving it.
|
||||||
|
//
|
||||||
|
// # Errors
|
||||||
|
//
|
||||||
|
// Possible errors are those from Stat, except ENOSYS should not
|
||||||
|
// be returned. Zero should be returned if there is no implementation.
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// - Implementations should cache this result.
|
||||||
|
// - This combined with Dev can implement os.SameFile.
|
||||||
|
Ino() (sys.Inode, Errno)
|
||||||
|
|
||||||
|
// IsDir returns true if this file is a directory or an error there was an
|
||||||
|
// error retrieving this information.
|
||||||
|
//
|
||||||
|
// # Errors
|
||||||
|
//
|
||||||
|
// Possible errors are those from Stat, except ENOSYS should not
|
||||||
|
// be returned. false should be returned if there is no implementation.
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// - Implementations should cache this result.
|
||||||
|
IsDir() (bool, Errno)
|
||||||
|
|
||||||
|
// IsAppend returns true if the file was opened with O_APPEND, or
|
||||||
|
// SetAppend was successfully enabled on this file.
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// - This might not match the underlying state of the file descriptor if
|
||||||
|
// the file was not opened via OpenFile.
|
||||||
|
IsAppend() bool
|
||||||
|
|
||||||
|
// SetAppend toggles the append mode (O_APPEND) of this file.
|
||||||
|
//
|
||||||
|
// # Errors
|
||||||
|
//
|
||||||
|
// A zero Errno is success. The below are expected otherwise:
|
||||||
|
// - ENOSYS: the implementation does not support this function.
|
||||||
|
// - EBADF: the file or directory was closed.
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// - There is no `O_APPEND` for `fcntl` in POSIX, so implementations may
|
||||||
|
// have to re-open the underlying file to apply this. See
|
||||||
|
// https://pubs.opengroup.org/onlinepubs/9699919799/functions/open.html
|
||||||
|
SetAppend(enable bool) Errno
|
||||||
|
|
||||||
|
// Stat is similar to syscall.Fstat.
|
||||||
|
//
|
||||||
|
// # Errors
|
||||||
|
//
|
||||||
|
// A zero Errno is success. The below are expected otherwise:
|
||||||
|
// - ENOSYS: the implementation does not support this function.
|
||||||
|
// - EBADF: the file or directory was closed.
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// - This is like syscall.Fstat and `fstatat` with `AT_FDCWD` in POSIX.
|
||||||
|
// See https://pubs.opengroup.org/onlinepubs/9699919799/functions/stat.html
|
||||||
|
// - A fs.FileInfo backed implementation sets atim, mtim and ctim to the
|
||||||
|
// same value.
|
||||||
|
// - Windows allows you to stat a closed directory.
|
||||||
|
Stat() (sys.Stat_t, Errno)
|
||||||
|
|
||||||
|
// Read attempts to read all bytes in the file into `buf`, and returns the
|
||||||
|
// count read even on error.
|
||||||
|
//
|
||||||
|
// # Errors
|
||||||
|
//
|
||||||
|
// A zero Errno is success. The below are expected otherwise:
|
||||||
|
// - ENOSYS: the implementation does not support this function.
|
||||||
|
// - EBADF: the file or directory was closed or not readable.
|
||||||
|
// - EISDIR: the file was a directory.
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// - This is like io.Reader and `read` in POSIX, preferring semantics of
|
||||||
|
// io.Reader. See https://pubs.opengroup.org/onlinepubs/9699919799/functions/read.html
|
||||||
|
// - Unlike io.Reader, there is no io.EOF returned on end-of-file. To
|
||||||
|
// read the file completely, the caller must repeat until `n` is zero.
|
||||||
|
Read(buf []byte) (n int, errno Errno)
|
||||||
|
|
||||||
|
// Pread attempts to read all bytes in the file into `p`, starting at the
|
||||||
|
// offset `off`, and returns the count read even on error.
|
||||||
|
//
|
||||||
|
// # Errors
|
||||||
|
//
|
||||||
|
// A zero Errno is success. The below are expected otherwise:
|
||||||
|
// - ENOSYS: the implementation does not support this function.
|
||||||
|
// - EBADF: the file or directory was closed or not readable.
|
||||||
|
// - EINVAL: the offset was negative.
|
||||||
|
// - EISDIR: the file was a directory.
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// - This is like io.ReaderAt and `pread` in POSIX, preferring semantics
|
||||||
|
// of io.ReaderAt. See https://pubs.opengroup.org/onlinepubs/9699919799/functions/pread.html
|
||||||
|
// - Unlike io.ReaderAt, there is no io.EOF returned on end-of-file. To
|
||||||
|
// read the file completely, the caller must repeat until `n` is zero.
|
||||||
|
Pread(buf []byte, off int64) (n int, errno Errno)
|
||||||
|
|
||||||
|
// Seek attempts to set the next offset for Read or Write and returns the
|
||||||
|
// resulting absolute offset or an error.
|
||||||
|
//
|
||||||
|
// # Parameters
|
||||||
|
//
|
||||||
|
// The `offset` parameters is interpreted in terms of `whence`:
|
||||||
|
// - io.SeekStart: relative to the start of the file, e.g. offset=0 sets
|
||||||
|
// the next Read or Write to the beginning of the file.
|
||||||
|
// - io.SeekCurrent: relative to the current offset, e.g. offset=16 sets
|
||||||
|
// the next Read or Write 16 bytes past the prior.
|
||||||
|
// - io.SeekEnd: relative to the end of the file, e.g. offset=-1 sets the
|
||||||
|
// next Read or Write to the last byte in the file.
|
||||||
|
//
|
||||||
|
// # Behavior when a directory
|
||||||
|
//
|
||||||
|
// The only supported use case for a directory is seeking to `offset` zero
|
||||||
|
// (`whence` = io.SeekStart). This should have the same behavior as
|
||||||
|
// os.File, which resets any internal state used by Readdir.
|
||||||
|
//
|
||||||
|
// # Errors
|
||||||
|
//
|
||||||
|
// A zero Errno is success. The below are expected otherwise:
|
||||||
|
// - ENOSYS: the implementation does not support this function.
|
||||||
|
// - EBADF: the file or directory was closed or not readable.
|
||||||
|
// - EINVAL: the offset was negative.
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// - This is like io.Seeker and `fseek` in POSIX, preferring semantics
|
||||||
|
// of io.Seeker. See https://pubs.opengroup.org/onlinepubs/9699919799/functions/fseek.html
|
||||||
|
Seek(offset int64, whence int) (newOffset int64, errno Errno)
|
||||||
|
|
||||||
|
// Readdir reads the contents of the directory associated with file and
|
||||||
|
// returns a slice of up to n Dirent values in an arbitrary order. This is
|
||||||
|
// a stateful function, so subsequent calls return any next values.
|
||||||
|
//
|
||||||
|
// If n > 0, Readdir returns at most n entries or an error.
|
||||||
|
// If n <= 0, Readdir returns all remaining entries or an error.
|
||||||
|
//
|
||||||
|
// # Errors
|
||||||
|
//
|
||||||
|
// A zero Errno is success. The below are expected otherwise:
|
||||||
|
// - ENOSYS: the implementation does not support this function.
|
||||||
|
// - EBADF: the file was closed or not a directory.
|
||||||
|
// - ENOENT: the directory could not be read (e.g. deleted).
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// - This is like `Readdir` on os.File, but unlike `readdir` in POSIX.
|
||||||
|
// See https://pubs.opengroup.org/onlinepubs/9699919799/functions/readdir.html
|
||||||
|
// - Unlike os.File, there is no io.EOF returned on end-of-directory. To
|
||||||
|
// read the directory completely, the caller must repeat until the
|
||||||
|
// count read (`len(dirents)`) is less than `n`.
|
||||||
|
// - See /RATIONALE.md for design notes.
|
||||||
|
Readdir(n int) (dirents []Dirent, errno Errno)
|
||||||
|
|
||||||
|
// Write attempts to write all bytes in `p` to the file, and returns the
|
||||||
|
// count written even on error.
|
||||||
|
//
|
||||||
|
// # Errors
|
||||||
|
//
|
||||||
|
// A zero Errno is success. The below are expected otherwise:
|
||||||
|
// - ENOSYS: the implementation does not support this function.
|
||||||
|
// - EBADF: the file was closed, not writeable, or a directory.
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// - This is like io.Writer and `write` in POSIX, preferring semantics of
|
||||||
|
// io.Writer. See https://pubs.opengroup.org/onlinepubs/9699919799/functions/write.html
|
||||||
|
Write(buf []byte) (n int, errno Errno)
|
||||||
|
|
||||||
|
// Pwrite attempts to write all bytes in `p` to the file at the given
|
||||||
|
// offset `off`, and returns the count written even on error.
|
||||||
|
//
|
||||||
|
// # Errors
|
||||||
|
//
|
||||||
|
// A zero Errno is success. The below are expected otherwise:
|
||||||
|
// - ENOSYS: the implementation does not support this function.
|
||||||
|
// - EBADF: the file or directory was closed or not writeable.
|
||||||
|
// - EINVAL: the offset was negative.
|
||||||
|
// - EISDIR: the file was a directory.
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// - This is like io.WriterAt and `pwrite` in POSIX, preferring semantics
|
||||||
|
// of io.WriterAt. See https://pubs.opengroup.org/onlinepubs/9699919799/functions/pwrite.html
|
||||||
|
Pwrite(buf []byte, off int64) (n int, errno Errno)
|
||||||
|
|
||||||
|
// Truncate truncates a file to a specified length.
|
||||||
|
//
|
||||||
|
// # Errors
|
||||||
|
//
|
||||||
|
// A zero Errno is success. The below are expected otherwise:
|
||||||
|
// - ENOSYS: the implementation does not support this function.
|
||||||
|
// - EBADF: the file or directory was closed.
|
||||||
|
// - EINVAL: the `size` is negative.
|
||||||
|
// - EISDIR: the file was a directory.
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// - This is like syscall.Ftruncate and `ftruncate` in POSIX. See
|
||||||
|
// https://pubs.opengroup.org/onlinepubs/9699919799/functions/ftruncate.html
|
||||||
|
// - Windows does not error when calling Truncate on a closed file.
|
||||||
|
Truncate(size int64) Errno
|
||||||
|
|
||||||
|
// Sync synchronizes changes to the file.
|
||||||
|
//
|
||||||
|
// # Errors
|
||||||
|
//
|
||||||
|
// A zero Errno is success. The below are expected otherwise:
|
||||||
|
// - EBADF: the file or directory was closed.
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// - This is like syscall.Fsync and `fsync` in POSIX. See
|
||||||
|
// https://pubs.opengroup.org/onlinepubs/9699919799/functions/fsync.html
|
||||||
|
// - This returns with no error instead of ENOSYS when
|
||||||
|
// unimplemented. This prevents fake filesystems from erring.
|
||||||
|
// - Windows does not error when calling Sync on a closed file.
|
||||||
|
Sync() Errno
|
||||||
|
|
||||||
|
// Datasync synchronizes the data of a file.
|
||||||
|
//
|
||||||
|
// # Errors
|
||||||
|
//
|
||||||
|
// A zero Errno is success. The below are expected otherwise:
|
||||||
|
// - EBADF: the file or directory was closed.
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// - This is like syscall.Fdatasync and `fdatasync` in POSIX. See
|
||||||
|
// https://pubs.opengroup.org/onlinepubs/9699919799/functions/fdatasync.html
|
||||||
|
// - This returns with no error instead of ENOSYS when
|
||||||
|
// unimplemented. This prevents fake filesystems from erring.
|
||||||
|
// - As this is commonly missing, some implementations dispatch to Sync.
|
||||||
|
Datasync() Errno
|
||||||
|
|
||||||
|
// Utimens set file access and modification times of this file, at
|
||||||
|
// nanosecond precision.
|
||||||
|
//
|
||||||
|
// # Parameters
|
||||||
|
//
|
||||||
|
// The `atim` and `mtim` parameters refer to access and modification time
|
||||||
|
// stamps as defined in sys.Stat_t. To retain one or the other, substitute
|
||||||
|
// it with the pseudo-timestamp UTIME_OMIT.
|
||||||
|
//
|
||||||
|
// # Errors
|
||||||
|
//
|
||||||
|
// A zero Errno is success. The below are expected otherwise:
|
||||||
|
// - ENOSYS: the implementation does not support this function.
|
||||||
|
// - EBADF: the file or directory was closed.
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// - This is like syscall.UtimesNano and `futimens` in POSIX. See
|
||||||
|
// https://pubs.opengroup.org/onlinepubs/9699919799/functions/futimens.html
|
||||||
|
// - Windows requires files to be open with O_RDWR, which means you
|
||||||
|
// cannot use this to update timestamps on a directory (EPERM).
|
||||||
|
Utimens(atim, mtim int64) Errno
|
||||||
|
|
||||||
|
// Close closes the underlying file.
|
||||||
|
//
|
||||||
|
// A zero Errno is returned if unimplemented or success.
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// - This is like syscall.Close and `close` in POSIX. See
|
||||||
|
// https://pubs.opengroup.org/onlinepubs/9699919799/functions/close.html
|
||||||
|
Close() Errno
|
||||||
|
}
|
||||||
292
vendor/github.com/tetratelabs/wazero/experimental/sys/fs.go
generated
vendored
Normal file
292
vendor/github.com/tetratelabs/wazero/experimental/sys/fs.go
generated
vendored
Normal file
@@ -0,0 +1,292 @@
|
|||||||
|
package sys
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/fs"
|
||||||
|
|
||||||
|
"github.com/tetratelabs/wazero/sys"
|
||||||
|
)
|
||||||
|
|
||||||
|
// FS is a writeable fs.FS bridge backed by syscall functions needed for ABI
|
||||||
|
// including WASI.
|
||||||
|
//
|
||||||
|
// Implementations should embed UnimplementedFS for forward compatibility. Any
|
||||||
|
// unsupported method or parameter should return ENO
|
||||||
|
//
|
||||||
|
// # Errors
|
||||||
|
//
|
||||||
|
// All methods that can return an error return a Errno, which is zero
|
||||||
|
// on success.
|
||||||
|
//
|
||||||
|
// Restricting to Errno matches current WebAssembly host functions,
|
||||||
|
// which are constrained to well-known error codes. For example, WASI maps syscall
|
||||||
|
// errors to u32 numeric values.
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// A writable filesystem abstraction is not yet implemented as of Go 1.20. See
|
||||||
|
// https://github.com/golang/go/issues/45757
|
||||||
|
type FS interface {
|
||||||
|
// OpenFile opens a file. It should be closed via Close on File.
|
||||||
|
//
|
||||||
|
// # Errors
|
||||||
|
//
|
||||||
|
// A zero Errno is success. The below are expected otherwise:
|
||||||
|
// - ENOSYS: the implementation does not support this function.
|
||||||
|
// - EINVAL: `path` or `flag` is invalid.
|
||||||
|
// - EISDIR: the path was a directory, but flag included O_RDWR or
|
||||||
|
// O_WRONLY
|
||||||
|
// - ENOENT: `path` doesn't exist and `flag` doesn't contain O_CREAT.
|
||||||
|
//
|
||||||
|
// # Constraints on the returned file
|
||||||
|
//
|
||||||
|
// Implementations that can read flags should enforce them regardless of
|
||||||
|
// the type returned. For example, while os.File implements io.Writer,
|
||||||
|
// attempts to write to a directory or a file opened with O_RDONLY fail
|
||||||
|
// with a EBADF.
|
||||||
|
//
|
||||||
|
// Some implementations choose whether to enforce read-only opens, namely
|
||||||
|
// fs.FS. While fs.FS is supported (Adapt), wazero cannot runtime enforce
|
||||||
|
// open flags. Instead, we encourage good behavior and test our built-in
|
||||||
|
// implementations.
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// - This is like os.OpenFile, except the path is relative to this file
|
||||||
|
// system, and Errno is returned instead of os.PathError.
|
||||||
|
// - Implications of permissions when O_CREAT are described in Chmod notes.
|
||||||
|
// - This is like `open` in POSIX. See
|
||||||
|
// https://pubs.opengroup.org/onlinepubs/9699919799/functions/open.html
|
||||||
|
OpenFile(path string, flag Oflag, perm fs.FileMode) (File, Errno)
|
||||||
|
|
||||||
|
// Lstat gets file status without following symbolic links.
|
||||||
|
//
|
||||||
|
// # Errors
|
||||||
|
//
|
||||||
|
// A zero Errno is success. The below are expected otherwise:
|
||||||
|
// - ENOSYS: the implementation does not support this function.
|
||||||
|
// - ENOENT: `path` doesn't exist.
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// - This is like syscall.Lstat, except the `path` is relative to this
|
||||||
|
// file system.
|
||||||
|
// - This is like `lstat` in POSIX. See
|
||||||
|
// https://pubs.opengroup.org/onlinepubs/9699919799/functions/lstat.html
|
||||||
|
// - An fs.FileInfo backed implementation sets atim, mtim and ctim to the
|
||||||
|
// same value.
|
||||||
|
// - When the path is a symbolic link, the stat returned is for the link,
|
||||||
|
// not the file it refers to.
|
||||||
|
Lstat(path string) (sys.Stat_t, Errno)
|
||||||
|
|
||||||
|
// Stat gets file status.
|
||||||
|
//
|
||||||
|
// # Errors
|
||||||
|
//
|
||||||
|
// A zero Errno is success. The below are expected otherwise:
|
||||||
|
// - ENOSYS: the implementation does not support this function.
|
||||||
|
// - ENOENT: `path` doesn't exist.
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// - This is like syscall.Stat, except the `path` is relative to this
|
||||||
|
// file system.
|
||||||
|
// - This is like `stat` in POSIX. See
|
||||||
|
// https://pubs.opengroup.org/onlinepubs/9699919799/functions/stat.html
|
||||||
|
// - An fs.FileInfo backed implementation sets atim, mtim and ctim to the
|
||||||
|
// same value.
|
||||||
|
// - When the path is a symbolic link, the stat returned is for the file
|
||||||
|
// it refers to.
|
||||||
|
Stat(path string) (sys.Stat_t, Errno)
|
||||||
|
|
||||||
|
// Mkdir makes a directory.
|
||||||
|
//
|
||||||
|
// # Errors
|
||||||
|
//
|
||||||
|
// A zero Errno is success. The below are expected otherwise:
|
||||||
|
// - ENOSYS: the implementation does not support this function.
|
||||||
|
// - EINVAL: `path` is invalid.
|
||||||
|
// - EEXIST: `path` exists and is a directory.
|
||||||
|
// - ENOTDIR: `path` exists and is a file.
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// - This is like syscall.Mkdir, except the `path` is relative to this
|
||||||
|
// file system.
|
||||||
|
// - This is like `mkdir` in POSIX. See
|
||||||
|
// https://pubs.opengroup.org/onlinepubs/9699919799/functions/mkdir.html
|
||||||
|
// - Implications of permissions are described in Chmod notes.
|
||||||
|
Mkdir(path string, perm fs.FileMode) Errno
|
||||||
|
|
||||||
|
// Chmod changes the mode of the file.
|
||||||
|
//
|
||||||
|
// # Errors
|
||||||
|
//
|
||||||
|
// A zero Errno is success. The below are expected otherwise:
|
||||||
|
// - ENOSYS: the implementation does not support this function.
|
||||||
|
// - EINVAL: `path` is invalid.
|
||||||
|
// - ENOENT: `path` does not exist.
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// - This is like syscall.Chmod, except the `path` is relative to this
|
||||||
|
// file system.
|
||||||
|
// - This is like `chmod` in POSIX. See
|
||||||
|
// https://pubs.opengroup.org/onlinepubs/9699919799/functions/chmod.html
|
||||||
|
// - Windows ignores the execute bit, and any permissions come back as
|
||||||
|
// group and world. For example, chmod of 0400 reads back as 0444, and
|
||||||
|
// 0700 0666. Also, permissions on directories aren't supported at all.
|
||||||
|
Chmod(path string, perm fs.FileMode) Errno
|
||||||
|
|
||||||
|
// Rename renames file or directory.
|
||||||
|
//
|
||||||
|
// # Errors
|
||||||
|
//
|
||||||
|
// A zero Errno is success. The below are expected otherwise:
|
||||||
|
// - ENOSYS: the implementation does not support this function.
|
||||||
|
// - EINVAL: `from` or `to` is invalid.
|
||||||
|
// - ENOENT: `from` or `to` don't exist.
|
||||||
|
// - ENOTDIR: `from` is a directory and `to` exists as a file.
|
||||||
|
// - EISDIR: `from` is a file and `to` exists as a directory.
|
||||||
|
// - ENOTEMPTY: `both from` and `to` are existing directory, but
|
||||||
|
// `to` is not empty.
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// - This is like syscall.Rename, except the paths are relative to this
|
||||||
|
// file system.
|
||||||
|
// - This is like `rename` in POSIX. See
|
||||||
|
// https://pubs.opengroup.org/onlinepubs/9699919799/functions/rename.html
|
||||||
|
// - Windows doesn't let you overwrite an existing directory.
|
||||||
|
Rename(from, to string) Errno
|
||||||
|
|
||||||
|
// Rmdir removes a directory.
|
||||||
|
//
|
||||||
|
// # Errors
|
||||||
|
//
|
||||||
|
// A zero Errno is success. The below are expected otherwise:
|
||||||
|
// - ENOSYS: the implementation does not support this function.
|
||||||
|
// - EINVAL: `path` is invalid.
|
||||||
|
// - ENOENT: `path` doesn't exist.
|
||||||
|
// - ENOTDIR: `path` exists, but isn't a directory.
|
||||||
|
// - ENOTEMPTY: `path` exists, but isn't empty.
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// - This is like syscall.Rmdir, except the `path` is relative to this
|
||||||
|
// file system.
|
||||||
|
// - This is like `rmdir` in POSIX. See
|
||||||
|
// https://pubs.opengroup.org/onlinepubs/9699919799/functions/rmdir.html
|
||||||
|
// - As of Go 1.19, Windows maps ENOTDIR to ENOENT.
|
||||||
|
Rmdir(path string) Errno
|
||||||
|
|
||||||
|
// Unlink removes a directory entry.
|
||||||
|
//
|
||||||
|
// # Errors
|
||||||
|
//
|
||||||
|
// A zero Errno is success. The below are expected otherwise:
|
||||||
|
// - ENOSYS: the implementation does not support this function.
|
||||||
|
// - EINVAL: `path` is invalid.
|
||||||
|
// - ENOENT: `path` doesn't exist.
|
||||||
|
// - EISDIR: `path` exists, but is a directory.
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// - This is like syscall.Unlink, except the `path` is relative to this
|
||||||
|
// file system.
|
||||||
|
// - This is like `unlink` in POSIX. See
|
||||||
|
// https://pubs.opengroup.org/onlinepubs/9699919799/functions/unlink.html
|
||||||
|
// - On Windows, syscall.Unlink doesn't delete symlink to directory unlike other platforms. Implementations might
|
||||||
|
// want to combine syscall.RemoveDirectory with syscall.Unlink in order to delete such links on Windows.
|
||||||
|
// See https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-removedirectorya
|
||||||
|
Unlink(path string) Errno
|
||||||
|
|
||||||
|
// Link creates a "hard" link from oldPath to newPath, in contrast to a
|
||||||
|
// soft link (via Symlink).
|
||||||
|
//
|
||||||
|
// # Errors
|
||||||
|
//
|
||||||
|
// A zero Errno is success. The below are expected otherwise:
|
||||||
|
// - ENOSYS: the implementation does not support this function.
|
||||||
|
// - EPERM: `oldPath` is invalid.
|
||||||
|
// - ENOENT: `oldPath` doesn't exist.
|
||||||
|
// - EISDIR: `newPath` exists, but is a directory.
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// - This is like syscall.Link, except the `oldPath` is relative to this
|
||||||
|
// file system.
|
||||||
|
// - This is like `link` in POSIX. See
|
||||||
|
// https://pubs.opengroup.org/onlinepubs/9699919799/functions/link.html
|
||||||
|
Link(oldPath, newPath string) Errno
|
||||||
|
|
||||||
|
// Symlink creates a "soft" link from oldPath to newPath, in contrast to a
|
||||||
|
// hard link (via Link).
|
||||||
|
//
|
||||||
|
// # Errors
|
||||||
|
//
|
||||||
|
// A zero Errno is success. The below are expected otherwise:
|
||||||
|
// - ENOSYS: the implementation does not support this function.
|
||||||
|
// - EPERM: `oldPath` or `newPath` is invalid.
|
||||||
|
// - EEXIST: `newPath` exists.
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// - This is like syscall.Symlink, except the `oldPath` is relative to
|
||||||
|
// this file system.
|
||||||
|
// - This is like `symlink` in POSIX. See
|
||||||
|
// https://pubs.opengroup.org/onlinepubs/9699919799/functions/symlink.html
|
||||||
|
// - Only `newPath` is relative to this file system and `oldPath` is kept
|
||||||
|
// as-is. That is because the link is only resolved relative to the
|
||||||
|
// directory when dereferencing it (e.g. ReadLink).
|
||||||
|
// See https://github.com/bytecodealliance/cap-std/blob/v1.0.4/cap-std/src/fs/dir.rs#L404-L409
|
||||||
|
// for how others implement this.
|
||||||
|
// - Symlinks in Windows requires `SeCreateSymbolicLinkPrivilege`.
|
||||||
|
// Otherwise, EPERM results.
|
||||||
|
// See https://learn.microsoft.com/en-us/windows/security/threat-protection/security-policy-settings/create-symbolic-links
|
||||||
|
Symlink(oldPath, linkName string) Errno
|
||||||
|
|
||||||
|
// Readlink reads the contents of a symbolic link.
|
||||||
|
//
|
||||||
|
// # Errors
|
||||||
|
//
|
||||||
|
// A zero Errno is success. The below are expected otherwise:
|
||||||
|
// - ENOSYS: the implementation does not support this function.
|
||||||
|
// - EINVAL: `path` is invalid.
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// - This is like syscall.Readlink, except the path is relative to this
|
||||||
|
// filesystem.
|
||||||
|
// - This is like `readlink` in POSIX. See
|
||||||
|
// https://pubs.opengroup.org/onlinepubs/9699919799/functions/readlink.html
|
||||||
|
// - On Windows, the path separator is different from other platforms,
|
||||||
|
// but to provide consistent results to Wasm, this normalizes to a "/"
|
||||||
|
// separator.
|
||||||
|
Readlink(path string) (string, Errno)
|
||||||
|
|
||||||
|
// Utimens set file access and modification times on a path relative to
|
||||||
|
// this file system, at nanosecond precision.
|
||||||
|
//
|
||||||
|
// # Parameters
|
||||||
|
//
|
||||||
|
// If the path is a symbolic link, the target of expanding that link is
|
||||||
|
// updated.
|
||||||
|
//
|
||||||
|
// The `atim` and `mtim` parameters refer to access and modification time
|
||||||
|
// stamps as defined in sys.Stat_t. To retain one or the other, substitute
|
||||||
|
// it with the pseudo-timestamp UTIME_OMIT.
|
||||||
|
//
|
||||||
|
// # Errors
|
||||||
|
//
|
||||||
|
// A zero Errno is success. The below are expected otherwise:
|
||||||
|
// - ENOSYS: the implementation does not support this function.
|
||||||
|
// - EINVAL: `path` is invalid.
|
||||||
|
// - EEXIST: `path` exists and is a directory.
|
||||||
|
// - ENOTDIR: `path` exists and is a file.
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// - This is like syscall.UtimesNano and `utimensat` with `AT_FDCWD` in
|
||||||
|
// POSIX. See https://pubs.opengroup.org/onlinepubs/9699919799/functions/futimens.html
|
||||||
|
Utimens(path string, atim, mtim int64) Errno
|
||||||
|
}
|
||||||
70
vendor/github.com/tetratelabs/wazero/experimental/sys/oflag.go
generated
vendored
Normal file
70
vendor/github.com/tetratelabs/wazero/experimental/sys/oflag.go
generated
vendored
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
package sys
|
||||||
|
|
||||||
|
// Oflag are flags used for FS.OpenFile. Values, including zero, should not be
|
||||||
|
// interpreted numerically. Instead, use by constants prefixed with 'O_' with
|
||||||
|
// special casing noted below.
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// - O_RDONLY, O_RDWR and O_WRONLY are mutually exclusive, while the other
|
||||||
|
// flags can coexist bitwise.
|
||||||
|
// - This is like `flag` in os.OpenFile and `oflag` in POSIX. See
|
||||||
|
// https://pubs.opengroup.org/onlinepubs/9699919799/functions/open.html
|
||||||
|
type Oflag uint32
|
||||||
|
|
||||||
|
// This is a subset of oflags to reduce implementation burden. `wasip1` splits
|
||||||
|
// these across `oflags` and `fdflags`. We can't rely on the Go `os` package,
|
||||||
|
// as it is missing some values. Any flags added will be defined in POSIX
|
||||||
|
// order, as needed by functions that explicitly document accepting them.
|
||||||
|
//
|
||||||
|
// https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-oflags-flagsu16
|
||||||
|
// https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-fdflags-flagsu16
|
||||||
|
const (
|
||||||
|
// O_RDONLY is like os.O_RDONLY
|
||||||
|
O_RDONLY Oflag = iota
|
||||||
|
|
||||||
|
// O_RDWR is like os.O_RDWR
|
||||||
|
O_RDWR
|
||||||
|
|
||||||
|
// O_WRONLY is like os.O_WRONLY
|
||||||
|
O_WRONLY
|
||||||
|
|
||||||
|
// Define bitflags as they are in POSIX `open`: alphabetically
|
||||||
|
|
||||||
|
// O_APPEND is like os.O_APPEND
|
||||||
|
O_APPEND Oflag = 1 << iota
|
||||||
|
|
||||||
|
// O_CREAT is link os.O_CREATE
|
||||||
|
O_CREAT
|
||||||
|
|
||||||
|
// O_DIRECTORY is defined on some platforms as syscall.O_DIRECTORY.
|
||||||
|
//
|
||||||
|
// Note: This ensures that the opened file is a directory. Those emulating
|
||||||
|
// on platforms that don't support the O_DIRECTORY, can double-check the
|
||||||
|
// result with File.IsDir (or stat) and err if not a directory.
|
||||||
|
O_DIRECTORY
|
||||||
|
|
||||||
|
// O_DSYNC is defined on some platforms as syscall.O_DSYNC.
|
||||||
|
O_DSYNC
|
||||||
|
|
||||||
|
// O_EXCL is defined on some platforms as syscall.O_EXCL.
|
||||||
|
O_EXCL
|
||||||
|
|
||||||
|
// O_NOFOLLOW is defined on some platforms as syscall.O_NOFOLLOW.
|
||||||
|
//
|
||||||
|
// Note: This allows programs to ensure that if the opened file is a
|
||||||
|
// symbolic link, the link itself is opened instead of its target.
|
||||||
|
O_NOFOLLOW
|
||||||
|
|
||||||
|
// O_NONBLOCK is defined on some platforms as syscall.O_NONBLOCK.
|
||||||
|
O_NONBLOCK
|
||||||
|
|
||||||
|
// O_RSYNC is defined on some platforms as syscall.O_RSYNC.
|
||||||
|
O_RSYNC
|
||||||
|
|
||||||
|
// O_SYNC is defined on some platforms as syscall.O_SYNC.
|
||||||
|
O_SYNC
|
||||||
|
|
||||||
|
// O_TRUNC is defined on some platforms as syscall.O_TRUNC.
|
||||||
|
O_TRUNC
|
||||||
|
)
|
||||||
106
vendor/github.com/tetratelabs/wazero/experimental/sys/syscall_errno.go
generated
vendored
Normal file
106
vendor/github.com/tetratelabs/wazero/experimental/sys/syscall_errno.go
generated
vendored
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
//go:build !plan9 && !aix
|
||||||
|
|
||||||
|
package sys
|
||||||
|
|
||||||
|
import "syscall"
|
||||||
|
|
||||||
|
func syscallToErrno(err error) (Errno, bool) {
|
||||||
|
errno, ok := err.(syscall.Errno)
|
||||||
|
if !ok {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
switch errno {
|
||||||
|
case 0:
|
||||||
|
return 0, true
|
||||||
|
case syscall.EACCES:
|
||||||
|
return EACCES, true
|
||||||
|
case syscall.EAGAIN:
|
||||||
|
return EAGAIN, true
|
||||||
|
case syscall.EBADF:
|
||||||
|
return EBADF, true
|
||||||
|
case syscall.EEXIST:
|
||||||
|
return EEXIST, true
|
||||||
|
case syscall.EFAULT:
|
||||||
|
return EFAULT, true
|
||||||
|
case syscall.EINTR:
|
||||||
|
return EINTR, true
|
||||||
|
case syscall.EINVAL:
|
||||||
|
return EINVAL, true
|
||||||
|
case syscall.EIO:
|
||||||
|
return EIO, true
|
||||||
|
case syscall.EISDIR:
|
||||||
|
return EISDIR, true
|
||||||
|
case syscall.ELOOP:
|
||||||
|
return ELOOP, true
|
||||||
|
case syscall.ENAMETOOLONG:
|
||||||
|
return ENAMETOOLONG, true
|
||||||
|
case syscall.ENOENT:
|
||||||
|
return ENOENT, true
|
||||||
|
case syscall.ENOSYS:
|
||||||
|
return ENOSYS, true
|
||||||
|
case syscall.ENOTDIR:
|
||||||
|
return ENOTDIR, true
|
||||||
|
case syscall.ERANGE:
|
||||||
|
return ERANGE, true
|
||||||
|
case syscall.ENOTEMPTY:
|
||||||
|
return ENOTEMPTY, true
|
||||||
|
case syscall.ENOTSOCK:
|
||||||
|
return ENOTSOCK, true
|
||||||
|
case syscall.ENOTSUP:
|
||||||
|
return ENOTSUP, true
|
||||||
|
case syscall.EPERM:
|
||||||
|
return EPERM, true
|
||||||
|
case syscall.EROFS:
|
||||||
|
return EROFS, true
|
||||||
|
default:
|
||||||
|
return EIO, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unwrap is a convenience for runtime.GOOS which define syscall.Errno.
|
||||||
|
func (e Errno) Unwrap() error {
|
||||||
|
switch e {
|
||||||
|
case 0:
|
||||||
|
return nil
|
||||||
|
case EACCES:
|
||||||
|
return syscall.EACCES
|
||||||
|
case EAGAIN:
|
||||||
|
return syscall.EAGAIN
|
||||||
|
case EBADF:
|
||||||
|
return syscall.EBADF
|
||||||
|
case EEXIST:
|
||||||
|
return syscall.EEXIST
|
||||||
|
case EFAULT:
|
||||||
|
return syscall.EFAULT
|
||||||
|
case EINTR:
|
||||||
|
return syscall.EINTR
|
||||||
|
case EINVAL:
|
||||||
|
return syscall.EINVAL
|
||||||
|
case EIO:
|
||||||
|
return syscall.EIO
|
||||||
|
case EISDIR:
|
||||||
|
return syscall.EISDIR
|
||||||
|
case ELOOP:
|
||||||
|
return syscall.ELOOP
|
||||||
|
case ENAMETOOLONG:
|
||||||
|
return syscall.ENAMETOOLONG
|
||||||
|
case ENOENT:
|
||||||
|
return syscall.ENOENT
|
||||||
|
case ENOSYS:
|
||||||
|
return syscall.ENOSYS
|
||||||
|
case ENOTDIR:
|
||||||
|
return syscall.ENOTDIR
|
||||||
|
case ENOTEMPTY:
|
||||||
|
return syscall.ENOTEMPTY
|
||||||
|
case ENOTSOCK:
|
||||||
|
return syscall.ENOTSOCK
|
||||||
|
case ENOTSUP:
|
||||||
|
return syscall.ENOTSUP
|
||||||
|
case EPERM:
|
||||||
|
return syscall.EPERM
|
||||||
|
case EROFS:
|
||||||
|
return syscall.EROFS
|
||||||
|
default:
|
||||||
|
return syscall.EIO
|
||||||
|
}
|
||||||
|
}
|
||||||
13
vendor/github.com/tetratelabs/wazero/experimental/sys/syscall_errno_notwindows.go
generated
vendored
Normal file
13
vendor/github.com/tetratelabs/wazero/experimental/sys/syscall_errno_notwindows.go
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
//go:build !windows
|
||||||
|
|
||||||
|
package sys
|
||||||
|
|
||||||
|
func errorToErrno(err error) Errno {
|
||||||
|
if errno, ok := err.(Errno); ok {
|
||||||
|
return errno
|
||||||
|
}
|
||||||
|
if errno, ok := syscallToErrno(err); ok {
|
||||||
|
return errno
|
||||||
|
}
|
||||||
|
return EIO
|
||||||
|
}
|
||||||
7
vendor/github.com/tetratelabs/wazero/experimental/sys/syscall_errno_unsupported.go
generated
vendored
Normal file
7
vendor/github.com/tetratelabs/wazero/experimental/sys/syscall_errno_unsupported.go
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
//go:build plan9 || aix
|
||||||
|
|
||||||
|
package sys
|
||||||
|
|
||||||
|
func syscallToErrno(err error) (Errno, bool) {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
66
vendor/github.com/tetratelabs/wazero/experimental/sys/syscall_errno_windows.go
generated
vendored
Normal file
66
vendor/github.com/tetratelabs/wazero/experimental/sys/syscall_errno_windows.go
generated
vendored
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
package sys
|
||||||
|
|
||||||
|
import "syscall"
|
||||||
|
|
||||||
|
// These are errors not defined in the syscall package. They are prefixed with
|
||||||
|
// underscore to avoid exporting them.
|
||||||
|
//
|
||||||
|
// See https://learn.microsoft.com/en-us/windows/win32/debug/system-error-codes--0-499-
|
||||||
|
const (
|
||||||
|
// _ERROR_INVALID_HANDLE is a Windows error returned by syscall.Write
|
||||||
|
// instead of syscall.EBADF
|
||||||
|
_ERROR_INVALID_HANDLE = syscall.Errno(6)
|
||||||
|
|
||||||
|
// _ERROR_INVALID_NAME is a Windows error returned by open when a file
|
||||||
|
// path has a trailing slash
|
||||||
|
_ERROR_INVALID_NAME = syscall.Errno(0x7B)
|
||||||
|
|
||||||
|
// _ERROR_NEGATIVE_SEEK is a Windows error returned by os.Truncate
|
||||||
|
// instead of syscall.EINVAL
|
||||||
|
_ERROR_NEGATIVE_SEEK = syscall.Errno(0x83)
|
||||||
|
|
||||||
|
// _ERROR_DIRECTORY is a Windows error returned by syscall.Rmdir
|
||||||
|
// instead of syscall.ENOTDIR
|
||||||
|
_ERROR_DIRECTORY = syscall.Errno(0x10B)
|
||||||
|
|
||||||
|
// _ERROR_NOT_A_REPARSE_POINT is a Windows error returned by os.Readlink
|
||||||
|
// instead of syscall.EINVAL
|
||||||
|
_ERROR_NOT_A_REPARSE_POINT = syscall.Errno(0x1126)
|
||||||
|
|
||||||
|
// _ERROR_INVALID_SOCKET is a Windows error returned by winsock_select
|
||||||
|
// when a given handle is not a socket.
|
||||||
|
_ERROR_INVALID_SOCKET = syscall.Errno(0x2736)
|
||||||
|
)
|
||||||
|
|
||||||
|
func errorToErrno(err error) Errno {
|
||||||
|
switch err := err.(type) {
|
||||||
|
case Errno:
|
||||||
|
return err
|
||||||
|
case syscall.Errno:
|
||||||
|
// Note: In windows, _ERROR_PATH_NOT_FOUND(0x3) maps to syscall.ENOTDIR
|
||||||
|
switch err {
|
||||||
|
case syscall.ERROR_ALREADY_EXISTS:
|
||||||
|
return EEXIST
|
||||||
|
case _ERROR_DIRECTORY:
|
||||||
|
return ENOTDIR
|
||||||
|
case syscall.ERROR_DIR_NOT_EMPTY:
|
||||||
|
return ENOTEMPTY
|
||||||
|
case syscall.ERROR_FILE_EXISTS:
|
||||||
|
return EEXIST
|
||||||
|
case _ERROR_INVALID_HANDLE, _ERROR_INVALID_SOCKET:
|
||||||
|
return EBADF
|
||||||
|
case syscall.ERROR_ACCESS_DENIED:
|
||||||
|
// POSIX read and write functions expect EBADF, not EACCES when not
|
||||||
|
// open for reading or writing.
|
||||||
|
return EBADF
|
||||||
|
case syscall.ERROR_PRIVILEGE_NOT_HELD:
|
||||||
|
return EPERM
|
||||||
|
case _ERROR_NEGATIVE_SEEK, _ERROR_INVALID_NAME, _ERROR_NOT_A_REPARSE_POINT:
|
||||||
|
return EINVAL
|
||||||
|
}
|
||||||
|
errno, _ := syscallToErrno(err)
|
||||||
|
return errno
|
||||||
|
default:
|
||||||
|
return EIO
|
||||||
|
}
|
||||||
|
}
|
||||||
10
vendor/github.com/tetratelabs/wazero/experimental/sys/time.go
generated
vendored
Normal file
10
vendor/github.com/tetratelabs/wazero/experimental/sys/time.go
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
package sys
|
||||||
|
|
||||||
|
import "math"
|
||||||
|
|
||||||
|
// UTIME_OMIT is a special constant for use in updating times via FS.Utimens
|
||||||
|
// or File.Utimens. When used for atim or mtim, the value is retained.
|
||||||
|
//
|
||||||
|
// Note: This may be implemented via a stat when the underlying filesystem
|
||||||
|
// does not support this value.
|
||||||
|
const UTIME_OMIT int64 = math.MinInt64
|
||||||
160
vendor/github.com/tetratelabs/wazero/experimental/sys/unimplemented.go
generated
vendored
Normal file
160
vendor/github.com/tetratelabs/wazero/experimental/sys/unimplemented.go
generated
vendored
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
package sys
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/fs"
|
||||||
|
|
||||||
|
"github.com/tetratelabs/wazero/sys"
|
||||||
|
)
|
||||||
|
|
||||||
|
// UnimplementedFS is an FS that returns ENOSYS for all functions,
|
||||||
|
// This should be embedded to have forward compatible implementations.
|
||||||
|
type UnimplementedFS struct{}
|
||||||
|
|
||||||
|
// OpenFile implements FS.OpenFile
|
||||||
|
func (UnimplementedFS) OpenFile(path string, flag Oflag, perm fs.FileMode) (File, Errno) {
|
||||||
|
return nil, ENOSYS
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lstat implements FS.Lstat
|
||||||
|
func (UnimplementedFS) Lstat(path string) (sys.Stat_t, Errno) {
|
||||||
|
return sys.Stat_t{}, ENOSYS
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stat implements FS.Stat
|
||||||
|
func (UnimplementedFS) Stat(path string) (sys.Stat_t, Errno) {
|
||||||
|
return sys.Stat_t{}, ENOSYS
|
||||||
|
}
|
||||||
|
|
||||||
|
// Readlink implements FS.Readlink
|
||||||
|
func (UnimplementedFS) Readlink(path string) (string, Errno) {
|
||||||
|
return "", ENOSYS
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mkdir implements FS.Mkdir
|
||||||
|
func (UnimplementedFS) Mkdir(path string, perm fs.FileMode) Errno {
|
||||||
|
return ENOSYS
|
||||||
|
}
|
||||||
|
|
||||||
|
// Chmod implements FS.Chmod
|
||||||
|
func (UnimplementedFS) Chmod(path string, perm fs.FileMode) Errno {
|
||||||
|
return ENOSYS
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rename implements FS.Rename
|
||||||
|
func (UnimplementedFS) Rename(from, to string) Errno {
|
||||||
|
return ENOSYS
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rmdir implements FS.Rmdir
|
||||||
|
func (UnimplementedFS) Rmdir(path string) Errno {
|
||||||
|
return ENOSYS
|
||||||
|
}
|
||||||
|
|
||||||
|
// Link implements FS.Link
|
||||||
|
func (UnimplementedFS) Link(_, _ string) Errno {
|
||||||
|
return ENOSYS
|
||||||
|
}
|
||||||
|
|
||||||
|
// Symlink implements FS.Symlink
|
||||||
|
func (UnimplementedFS) Symlink(_, _ string) Errno {
|
||||||
|
return ENOSYS
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unlink implements FS.Unlink
|
||||||
|
func (UnimplementedFS) Unlink(path string) Errno {
|
||||||
|
return ENOSYS
|
||||||
|
}
|
||||||
|
|
||||||
|
// Utimens implements FS.Utimens
|
||||||
|
func (UnimplementedFS) Utimens(path string, atim, mtim int64) Errno {
|
||||||
|
return ENOSYS
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnimplementedFile is a File that returns ENOSYS for all functions,
|
||||||
|
// except where no-op are otherwise documented.
|
||||||
|
//
|
||||||
|
// This should be embedded to have forward compatible implementations.
|
||||||
|
type UnimplementedFile struct{}
|
||||||
|
|
||||||
|
// Dev implements File.Dev
|
||||||
|
func (UnimplementedFile) Dev() (uint64, Errno) {
|
||||||
|
return 0, 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ino implements File.Ino
|
||||||
|
func (UnimplementedFile) Ino() (sys.Inode, Errno) {
|
||||||
|
return 0, 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsDir implements File.IsDir
|
||||||
|
func (UnimplementedFile) IsDir() (bool, Errno) {
|
||||||
|
return false, 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsAppend implements File.IsAppend
|
||||||
|
func (UnimplementedFile) IsAppend() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetAppend implements File.SetAppend
|
||||||
|
func (UnimplementedFile) SetAppend(bool) Errno {
|
||||||
|
return ENOSYS
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stat implements File.Stat
|
||||||
|
func (UnimplementedFile) Stat() (sys.Stat_t, Errno) {
|
||||||
|
return sys.Stat_t{}, ENOSYS
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read implements File.Read
|
||||||
|
func (UnimplementedFile) Read([]byte) (int, Errno) {
|
||||||
|
return 0, ENOSYS
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pread implements File.Pread
|
||||||
|
func (UnimplementedFile) Pread([]byte, int64) (int, Errno) {
|
||||||
|
return 0, ENOSYS
|
||||||
|
}
|
||||||
|
|
||||||
|
// Seek implements File.Seek
|
||||||
|
func (UnimplementedFile) Seek(int64, int) (int64, Errno) {
|
||||||
|
return 0, ENOSYS
|
||||||
|
}
|
||||||
|
|
||||||
|
// Readdir implements File.Readdir
|
||||||
|
func (UnimplementedFile) Readdir(int) (dirents []Dirent, errno Errno) {
|
||||||
|
return nil, ENOSYS
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write implements File.Write
|
||||||
|
func (UnimplementedFile) Write([]byte) (int, Errno) {
|
||||||
|
return 0, ENOSYS
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pwrite implements File.Pwrite
|
||||||
|
func (UnimplementedFile) Pwrite([]byte, int64) (int, Errno) {
|
||||||
|
return 0, ENOSYS
|
||||||
|
}
|
||||||
|
|
||||||
|
// Truncate implements File.Truncate
|
||||||
|
func (UnimplementedFile) Truncate(int64) Errno {
|
||||||
|
return ENOSYS
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sync implements File.Sync
|
||||||
|
func (UnimplementedFile) Sync() Errno {
|
||||||
|
return 0 // not ENOSYS
|
||||||
|
}
|
||||||
|
|
||||||
|
// Datasync implements File.Datasync
|
||||||
|
func (UnimplementedFile) Datasync() Errno {
|
||||||
|
return 0 // not ENOSYS
|
||||||
|
}
|
||||||
|
|
||||||
|
// Utimens implements File.Utimens
|
||||||
|
func (UnimplementedFile) Utimens(int64, int64) Errno {
|
||||||
|
return ENOSYS
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close implements File.Close
|
||||||
|
func (UnimplementedFile) Close() (errno Errno) { return }
|
||||||
213
vendor/github.com/tetratelabs/wazero/fsconfig.go
generated
vendored
Normal file
213
vendor/github.com/tetratelabs/wazero/fsconfig.go
generated
vendored
Normal file
@@ -0,0 +1,213 @@
|
|||||||
|
package wazero
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/fs"
|
||||||
|
|
||||||
|
experimentalsys "github.com/tetratelabs/wazero/experimental/sys"
|
||||||
|
"github.com/tetratelabs/wazero/internal/sys"
|
||||||
|
"github.com/tetratelabs/wazero/internal/sysfs"
|
||||||
|
)
|
||||||
|
|
||||||
|
// FSConfig configures filesystem paths the embedding host allows the wasm
|
||||||
|
// guest to access. Unconfigured paths are not allowed, so functions like
|
||||||
|
// `path_open` result in unsupported errors (e.g. syscall.ENOSYS).
|
||||||
|
//
|
||||||
|
// # Guest Path
|
||||||
|
//
|
||||||
|
// `guestPath` is the name of the path the guest should use a filesystem for, or
|
||||||
|
// empty for any files.
|
||||||
|
//
|
||||||
|
// All `guestPath` paths are normalized, specifically removing any leading or
|
||||||
|
// trailing slashes. This means "/", "./" or "." all coerce to empty "".
|
||||||
|
//
|
||||||
|
// Multiple `guestPath` values can be configured, but the last longest match
|
||||||
|
// wins. For example, if "tmp", then "" were added, a request to open
|
||||||
|
// "tmp/foo.txt" use the filesystem associated with "tmp" even though a wider
|
||||||
|
// path, "" (all files), was added later.
|
||||||
|
//
|
||||||
|
// A `guestPath` of "." coerces to the empty string "" because the current
|
||||||
|
// directory is handled by the guest. In other words, the guest resolves ites
|
||||||
|
// current directory prior to requesting files.
|
||||||
|
//
|
||||||
|
// More notes on `guestPath`
|
||||||
|
// - Working directories are typically tracked in wasm, though possible some
|
||||||
|
// relative paths are requested. For example, TinyGo may attempt to resolve
|
||||||
|
// a path "../.." in unit tests.
|
||||||
|
// - Zig uses the first path name it sees as the initial working directory of
|
||||||
|
// the process.
|
||||||
|
//
|
||||||
|
// # Scope
|
||||||
|
//
|
||||||
|
// Configuration here is module instance scoped. This means you can use the
|
||||||
|
// same configuration for multiple calls to Runtime.InstantiateModule. Each
|
||||||
|
// module will have a different file descriptor table. Any errors accessing
|
||||||
|
// resources allowed here are deferred to instantiation time of each module.
|
||||||
|
//
|
||||||
|
// Any host resources present at the time of configuration, but deleted before
|
||||||
|
// Runtime.InstantiateModule will trap/panic when the guest wasm initializes or
|
||||||
|
// calls functions like `fd_read`.
|
||||||
|
//
|
||||||
|
// # Windows
|
||||||
|
//
|
||||||
|
// While wazero supports Windows as a platform, all known compilers use POSIX
|
||||||
|
// conventions at runtime. For example, even when running on Windows, paths
|
||||||
|
// used by wasm are separated by forward slash (/), not backslash (\).
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// - This is an interface for decoupling, not third-party implementations.
|
||||||
|
// All implementations are in wazero.
|
||||||
|
// - FSConfig is immutable. Each WithXXX function returns a new instance
|
||||||
|
// including the corresponding change.
|
||||||
|
// - RATIONALE.md includes design background and relationship to WebAssembly
|
||||||
|
// System Interfaces (WASI).
|
||||||
|
type FSConfig interface {
|
||||||
|
// WithDirMount assigns a directory at `dir` to any paths beginning at
|
||||||
|
// `guestPath`.
|
||||||
|
//
|
||||||
|
// For example, `dirPath` as / (or c:\ in Windows), makes the entire host
|
||||||
|
// volume writeable to the path on the guest. The `guestPath` is always a
|
||||||
|
// POSIX style path, slash (/) delimited, even if run on Windows.
|
||||||
|
//
|
||||||
|
// If the same `guestPath` was assigned before, this overrides its value,
|
||||||
|
// retaining the original precedence. See the documentation of FSConfig for
|
||||||
|
// more details on `guestPath`.
|
||||||
|
//
|
||||||
|
// # Isolation
|
||||||
|
//
|
||||||
|
// The guest will have full access to this directory including escaping it
|
||||||
|
// via relative path lookups like "../../". Full access includes operations
|
||||||
|
// such as creating or deleting files, limited to any host level access
|
||||||
|
// controls.
|
||||||
|
//
|
||||||
|
// # os.DirFS
|
||||||
|
//
|
||||||
|
// This configuration optimizes for WASI compatibility which is sometimes
|
||||||
|
// at odds with the behavior of os.DirFS. Hence, this will not behave
|
||||||
|
// exactly the same as os.DirFS. See /RATIONALE.md for more.
|
||||||
|
WithDirMount(dir, guestPath string) FSConfig
|
||||||
|
|
||||||
|
// WithReadOnlyDirMount assigns a directory at `dir` to any paths
|
||||||
|
// beginning at `guestPath`.
|
||||||
|
//
|
||||||
|
// This is the same as WithDirMount except only read operations are
|
||||||
|
// permitted. However, escaping the directory via relative path lookups
|
||||||
|
// like "../../" is still allowed.
|
||||||
|
WithReadOnlyDirMount(dir, guestPath string) FSConfig
|
||||||
|
|
||||||
|
// WithFSMount assigns a fs.FS file system for any paths beginning at
|
||||||
|
// `guestPath`.
|
||||||
|
//
|
||||||
|
// If the same `guestPath` was assigned before, this overrides its value,
|
||||||
|
// retaining the original precedence. See the documentation of FSConfig for
|
||||||
|
// more details on `guestPath`.
|
||||||
|
//
|
||||||
|
// # Isolation
|
||||||
|
//
|
||||||
|
// fs.FS does not restrict the ability to overwrite returned files via
|
||||||
|
// io.Writer. Moreover, os.DirFS documentation includes important notes
|
||||||
|
// about isolation, which also applies to fs.Sub. As of Go 1.19, the
|
||||||
|
// built-in file-systems are not jailed (chroot). See
|
||||||
|
// https://github.com/golang/go/issues/42322
|
||||||
|
//
|
||||||
|
// # os.DirFS
|
||||||
|
//
|
||||||
|
// Due to limited control and functionality available in os.DirFS, we
|
||||||
|
// advise using WithDirMount instead. There will be behavior differences
|
||||||
|
// between os.DirFS and WithDirMount, as the latter biases towards what's
|
||||||
|
// expected from WASI implementations.
|
||||||
|
//
|
||||||
|
// # Custom fs.FileInfo
|
||||||
|
//
|
||||||
|
// The underlying implementation supports data not usually in fs.FileInfo
|
||||||
|
// when `info.Sys` returns *sys.Stat_t. For example, a custom fs.FS can use
|
||||||
|
// this approach to generate or mask sys.Inode data. Such a filesystem
|
||||||
|
// needs to decorate any functions that can return fs.FileInfo:
|
||||||
|
//
|
||||||
|
// - `Stat` as defined on `fs.File` (always)
|
||||||
|
// - `Readdir` as defined on `os.File` (if defined)
|
||||||
|
//
|
||||||
|
// See sys.NewStat_t for examples.
|
||||||
|
WithFSMount(fs fs.FS, guestPath string) FSConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
type fsConfig struct {
|
||||||
|
// fs are the currently configured filesystems.
|
||||||
|
fs []experimentalsys.FS
|
||||||
|
// guestPaths are the user-supplied names of the filesystems, retained for
|
||||||
|
// error messages and fmt.Stringer.
|
||||||
|
guestPaths []string
|
||||||
|
// guestPathToFS are the normalized paths to the currently configured
|
||||||
|
// filesystems, used for de-duplicating.
|
||||||
|
guestPathToFS map[string]int
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewFSConfig returns a FSConfig that can be used for configuring module instantiation.
|
||||||
|
func NewFSConfig() FSConfig {
|
||||||
|
return &fsConfig{guestPathToFS: map[string]int{}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// clone makes a deep copy of this module config.
|
||||||
|
func (c *fsConfig) clone() *fsConfig {
|
||||||
|
ret := *c // copy except slice and maps which share a ref
|
||||||
|
ret.fs = make([]experimentalsys.FS, 0, len(c.fs))
|
||||||
|
ret.fs = append(ret.fs, c.fs...)
|
||||||
|
ret.guestPaths = make([]string, 0, len(c.guestPaths))
|
||||||
|
ret.guestPaths = append(ret.guestPaths, c.guestPaths...)
|
||||||
|
ret.guestPathToFS = make(map[string]int, len(c.guestPathToFS))
|
||||||
|
for key, value := range c.guestPathToFS {
|
||||||
|
ret.guestPathToFS[key] = value
|
||||||
|
}
|
||||||
|
return &ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithDirMount implements FSConfig.WithDirMount
|
||||||
|
func (c *fsConfig) WithDirMount(dir, guestPath string) FSConfig {
|
||||||
|
return c.WithSysFSMount(sysfs.DirFS(dir), guestPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithReadOnlyDirMount implements FSConfig.WithReadOnlyDirMount
|
||||||
|
func (c *fsConfig) WithReadOnlyDirMount(dir, guestPath string) FSConfig {
|
||||||
|
return c.WithSysFSMount(&sysfs.ReadFS{FS: sysfs.DirFS(dir)}, guestPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithFSMount implements FSConfig.WithFSMount
|
||||||
|
func (c *fsConfig) WithFSMount(fs fs.FS, guestPath string) FSConfig {
|
||||||
|
var adapted experimentalsys.FS
|
||||||
|
if fs != nil {
|
||||||
|
adapted = &sysfs.AdaptFS{FS: fs}
|
||||||
|
}
|
||||||
|
return c.WithSysFSMount(adapted, guestPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithSysFSMount implements sysfs.FSConfig
|
||||||
|
func (c *fsConfig) WithSysFSMount(fs experimentalsys.FS, guestPath string) FSConfig {
|
||||||
|
if _, ok := fs.(experimentalsys.UnimplementedFS); ok {
|
||||||
|
return c // don't add fake paths.
|
||||||
|
}
|
||||||
|
cleaned := sys.StripPrefixesAndTrailingSlash(guestPath)
|
||||||
|
ret := c.clone()
|
||||||
|
if i, ok := ret.guestPathToFS[cleaned]; ok {
|
||||||
|
ret.fs[i] = fs
|
||||||
|
ret.guestPaths[i] = guestPath
|
||||||
|
} else if fs != nil {
|
||||||
|
ret.guestPathToFS[cleaned] = len(ret.fs)
|
||||||
|
ret.fs = append(ret.fs, fs)
|
||||||
|
ret.guestPaths = append(ret.guestPaths, guestPath)
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// preopens returns the possible nil index-correlated preopened filesystems
|
||||||
|
// with guest paths.
|
||||||
|
func (c *fsConfig) preopens() ([]experimentalsys.FS, []string) {
|
||||||
|
preopenCount := len(c.fs)
|
||||||
|
if preopenCount == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
fs := make([]experimentalsys.FS, len(c.fs))
|
||||||
|
copy(fs, c.fs)
|
||||||
|
guestPaths := make([]string, len(c.guestPaths))
|
||||||
|
copy(guestPaths, c.guestPaths)
|
||||||
|
return fs, guestPaths
|
||||||
|
}
|
||||||
97
vendor/github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1/args.go
generated
vendored
Normal file
97
vendor/github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1/args.go
generated
vendored
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
package wasi_snapshot_preview1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/tetratelabs/wazero/api"
|
||||||
|
"github.com/tetratelabs/wazero/experimental/sys"
|
||||||
|
"github.com/tetratelabs/wazero/internal/wasip1"
|
||||||
|
"github.com/tetratelabs/wazero/internal/wasm"
|
||||||
|
)
|
||||||
|
|
||||||
|
// argsGet is the WASI function named ArgsGetName that reads command-line
|
||||||
|
// argument data.
|
||||||
|
//
|
||||||
|
// # Parameters
|
||||||
|
//
|
||||||
|
// - argv: offset to begin writing argument offsets in uint32 little-endian
|
||||||
|
// encoding to api.Memory
|
||||||
|
// - argsSizesGet result argc * 4 bytes are written to this offset
|
||||||
|
// - argvBuf: offset to write the null terminated arguments to api.Memory
|
||||||
|
// - argsSizesGet result argv_len bytes are written to this offset
|
||||||
|
//
|
||||||
|
// Result (Errno)
|
||||||
|
//
|
||||||
|
// The return value is ErrnoSuccess except the following error conditions:
|
||||||
|
// - sys.EFAULT: there is not enough memory to write results
|
||||||
|
//
|
||||||
|
// For example, if argsSizesGet wrote argc=2 and argvLen=5 for arguments:
|
||||||
|
// "a" and "bc" parameters argv=7 and argvBuf=1, this function writes the below
|
||||||
|
// to api.Memory:
|
||||||
|
//
|
||||||
|
// argvLen uint32le uint32le
|
||||||
|
// +----------------+ +--------+ +--------+
|
||||||
|
// | | | | | |
|
||||||
|
// []byte{?, 'a', 0, 'b', 'c', 0, ?, 1, 0, 0, 0, 3, 0, 0, 0, ?}
|
||||||
|
// argvBuf --^ ^ ^
|
||||||
|
// argv --| |
|
||||||
|
// offset that begins "a" --+ |
|
||||||
|
// offset that begins "bc" --+
|
||||||
|
//
|
||||||
|
// See argsSizesGet
|
||||||
|
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#args_get
|
||||||
|
// See https://en.wikipedia.org/wiki/Null-terminated_string
|
||||||
|
var argsGet = newHostFunc(wasip1.ArgsGetName, argsGetFn, []api.ValueType{i32, i32}, "argv", "argv_buf")
|
||||||
|
|
||||||
|
func argsGetFn(_ context.Context, mod api.Module, params []uint64) sys.Errno {
|
||||||
|
sysCtx := mod.(*wasm.ModuleInstance).Sys
|
||||||
|
argv, argvBuf := uint32(params[0]), uint32(params[1])
|
||||||
|
return writeOffsetsAndNullTerminatedValues(mod.Memory(), sysCtx.Args(), argv, argvBuf, sysCtx.ArgsSize())
|
||||||
|
}
|
||||||
|
|
||||||
|
// argsSizesGet is the WASI function named ArgsSizesGetName that reads
|
||||||
|
// command-line argument sizes.
|
||||||
|
//
|
||||||
|
// # Parameters
|
||||||
|
//
|
||||||
|
// - resultArgc: offset to write the argument count to api.Memory
|
||||||
|
// - resultArgvLen: offset to write the null-terminated argument length to
|
||||||
|
// api.Memory
|
||||||
|
//
|
||||||
|
// Result (Errno)
|
||||||
|
//
|
||||||
|
// The return value is ErrnoSuccess except the following error conditions:
|
||||||
|
// - sys.EFAULT: there is not enough memory to write results
|
||||||
|
//
|
||||||
|
// For example, if args are "a", "bc" and parameters resultArgc=1 and
|
||||||
|
// resultArgvLen=6, this function writes the below to api.Memory:
|
||||||
|
//
|
||||||
|
// uint32le uint32le
|
||||||
|
// +--------+ +--------+
|
||||||
|
// | | | |
|
||||||
|
// []byte{?, 2, 0, 0, 0, ?, 5, 0, 0, 0, ?}
|
||||||
|
// resultArgc --^ ^
|
||||||
|
// 2 args --+ |
|
||||||
|
// resultArgvLen --|
|
||||||
|
// len([]byte{'a',0,'b',c',0}) --+
|
||||||
|
//
|
||||||
|
// See argsGet
|
||||||
|
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#args_sizes_get
|
||||||
|
// See https://en.wikipedia.org/wiki/Null-terminated_string
|
||||||
|
var argsSizesGet = newHostFunc(wasip1.ArgsSizesGetName, argsSizesGetFn, []api.ValueType{i32, i32}, "result.argc", "result.argv_len")
|
||||||
|
|
||||||
|
func argsSizesGetFn(_ context.Context, mod api.Module, params []uint64) sys.Errno {
|
||||||
|
sysCtx := mod.(*wasm.ModuleInstance).Sys
|
||||||
|
mem := mod.Memory()
|
||||||
|
resultArgc, resultArgvLen := uint32(params[0]), uint32(params[1])
|
||||||
|
|
||||||
|
// argc and argv_len offsets are not necessarily sequential, so we have to
|
||||||
|
// write them independently.
|
||||||
|
if !mem.WriteUint32Le(resultArgc, uint32(len(sysCtx.Args()))) {
|
||||||
|
return sys.EFAULT
|
||||||
|
}
|
||||||
|
if !mem.WriteUint32Le(resultArgvLen, sysCtx.ArgsSize()) {
|
||||||
|
return sys.EFAULT
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
116
vendor/github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1/clock.go
generated
vendored
Normal file
116
vendor/github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1/clock.go
generated
vendored
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
package wasi_snapshot_preview1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/tetratelabs/wazero/api"
|
||||||
|
"github.com/tetratelabs/wazero/experimental/sys"
|
||||||
|
"github.com/tetratelabs/wazero/internal/wasip1"
|
||||||
|
"github.com/tetratelabs/wazero/internal/wasm"
|
||||||
|
)
|
||||||
|
|
||||||
|
// clockResGet is the WASI function named ClockResGetName that returns the
|
||||||
|
// resolution of time values returned by clockTimeGet.
|
||||||
|
//
|
||||||
|
// # Parameters
|
||||||
|
//
|
||||||
|
// - id: clock ID to use
|
||||||
|
// - resultResolution: offset to write the resolution to api.Memory
|
||||||
|
// - the resolution is an uint64 little-endian encoding
|
||||||
|
//
|
||||||
|
// Result (Errno)
|
||||||
|
//
|
||||||
|
// The return value is 0 except the following error conditions:
|
||||||
|
// - sys.ENOTSUP: the clock ID is not supported.
|
||||||
|
// - sys.EINVAL: the clock ID is invalid.
|
||||||
|
// - sys.EFAULT: there is not enough memory to write results
|
||||||
|
//
|
||||||
|
// For example, if the resolution is 100ns, this function writes the below to
|
||||||
|
// api.Memory:
|
||||||
|
//
|
||||||
|
// uint64le
|
||||||
|
// +-------------------------------------+
|
||||||
|
// | |
|
||||||
|
// []byte{?, 0x64, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ?}
|
||||||
|
// resultResolution --^
|
||||||
|
//
|
||||||
|
// Note: This is similar to `clock_getres` in POSIX.
|
||||||
|
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-clock_res_getid-clockid---errno-timestamp
|
||||||
|
// See https://linux.die.net/man/3/clock_getres
|
||||||
|
var clockResGet = newHostFunc(wasip1.ClockResGetName, clockResGetFn, []api.ValueType{i32, i32}, "id", "result.resolution")
|
||||||
|
|
||||||
|
func clockResGetFn(_ context.Context, mod api.Module, params []uint64) sys.Errno {
|
||||||
|
sysCtx := mod.(*wasm.ModuleInstance).Sys
|
||||||
|
id, resultResolution := uint32(params[0]), uint32(params[1])
|
||||||
|
|
||||||
|
var resolution uint64 // ns
|
||||||
|
switch id {
|
||||||
|
case wasip1.ClockIDRealtime:
|
||||||
|
resolution = uint64(sysCtx.WalltimeResolution())
|
||||||
|
case wasip1.ClockIDMonotonic:
|
||||||
|
resolution = uint64(sysCtx.NanotimeResolution())
|
||||||
|
default:
|
||||||
|
return sys.EINVAL
|
||||||
|
}
|
||||||
|
|
||||||
|
if !mod.Memory().WriteUint64Le(resultResolution, resolution) {
|
||||||
|
return sys.EFAULT
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// clockTimeGet is the WASI function named ClockTimeGetName that returns
|
||||||
|
// the time value of a name (time.Now).
|
||||||
|
//
|
||||||
|
// # Parameters
|
||||||
|
//
|
||||||
|
// - id: clock ID to use
|
||||||
|
// - precision: maximum lag (exclusive) that the returned time value may have,
|
||||||
|
// compared to its actual value
|
||||||
|
// - resultTimestamp: offset to write the timestamp to api.Memory
|
||||||
|
// - the timestamp is epoch nanos encoded as a little-endian uint64
|
||||||
|
//
|
||||||
|
// Result (Errno)
|
||||||
|
//
|
||||||
|
// The return value is 0 except the following error conditions:
|
||||||
|
// - sys.ENOTSUP: the clock ID is not supported.
|
||||||
|
// - sys.EINVAL: the clock ID is invalid.
|
||||||
|
// - sys.EFAULT: there is not enough memory to write results
|
||||||
|
//
|
||||||
|
// For example, if time.Now returned exactly midnight UTC 2022-01-01
|
||||||
|
// (1640995200000000000), and parameters resultTimestamp=1, this function
|
||||||
|
// writes the below to api.Memory:
|
||||||
|
//
|
||||||
|
// uint64le
|
||||||
|
// +------------------------------------------+
|
||||||
|
// | |
|
||||||
|
// []byte{?, 0x0, 0x0, 0x1f, 0xa6, 0x70, 0xfc, 0xc5, 0x16, ?}
|
||||||
|
// resultTimestamp --^
|
||||||
|
//
|
||||||
|
// Note: This is similar to `clock_gettime` in POSIX.
|
||||||
|
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-clock_time_getid-clockid-precision-timestamp---errno-timestamp
|
||||||
|
// See https://linux.die.net/man/3/clock_gettime
|
||||||
|
var clockTimeGet = newHostFunc(wasip1.ClockTimeGetName, clockTimeGetFn, []api.ValueType{i32, i64, i32}, "id", "precision", "result.timestamp")
|
||||||
|
|
||||||
|
func clockTimeGetFn(_ context.Context, mod api.Module, params []uint64) sys.Errno {
|
||||||
|
sysCtx := mod.(*wasm.ModuleInstance).Sys
|
||||||
|
id := uint32(params[0])
|
||||||
|
// TODO: precision is currently ignored.
|
||||||
|
// precision = params[1]
|
||||||
|
resultTimestamp := uint32(params[2])
|
||||||
|
|
||||||
|
var val int64
|
||||||
|
switch id {
|
||||||
|
case wasip1.ClockIDRealtime:
|
||||||
|
val = sysCtx.WalltimeNanos()
|
||||||
|
case wasip1.ClockIDMonotonic:
|
||||||
|
val = sysCtx.Nanotime()
|
||||||
|
default:
|
||||||
|
return sys.EINVAL
|
||||||
|
}
|
||||||
|
|
||||||
|
if !mod.Memory().WriteUint64Le(resultTimestamp, uint64(val)) {
|
||||||
|
return sys.EFAULT
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
100
vendor/github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1/environ.go
generated
vendored
Normal file
100
vendor/github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1/environ.go
generated
vendored
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
package wasi_snapshot_preview1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/tetratelabs/wazero/api"
|
||||||
|
"github.com/tetratelabs/wazero/experimental/sys"
|
||||||
|
"github.com/tetratelabs/wazero/internal/wasip1"
|
||||||
|
"github.com/tetratelabs/wazero/internal/wasm"
|
||||||
|
)
|
||||||
|
|
||||||
|
// environGet is the WASI function named EnvironGetName that reads
|
||||||
|
// environment variables.
|
||||||
|
//
|
||||||
|
// # Parameters
|
||||||
|
//
|
||||||
|
// - environ: offset to begin writing environment offsets in uint32
|
||||||
|
// little-endian encoding to api.Memory
|
||||||
|
// - environSizesGet result environc * 4 bytes are written to this offset
|
||||||
|
// - environBuf: offset to write the null-terminated variables to api.Memory
|
||||||
|
// - the format is like os.Environ: null-terminated "key=val" entries
|
||||||
|
// - environSizesGet result environLen bytes are written to this offset
|
||||||
|
//
|
||||||
|
// Result (Errno)
|
||||||
|
//
|
||||||
|
// The return value is 0 except the following error conditions:
|
||||||
|
// - sys.EFAULT: there is not enough memory to write results
|
||||||
|
//
|
||||||
|
// For example, if environSizesGet wrote environc=2 and environLen=9 for
|
||||||
|
// environment variables: "a=b", "b=cd" and parameters environ=11 and
|
||||||
|
// environBuf=1, this function writes the below to api.Memory:
|
||||||
|
//
|
||||||
|
// environLen uint32le uint32le
|
||||||
|
// +------------------------------------+ +--------+ +--------+
|
||||||
|
// | | | | | |
|
||||||
|
// []byte{?, 'a', '=', 'b', 0, 'b', '=', 'c', 'd', 0, ?, 1, 0, 0, 0, 5, 0, 0, 0, ?}
|
||||||
|
// environBuf --^ ^ ^
|
||||||
|
// environ offset for "a=b" --+ |
|
||||||
|
// environ offset for "b=cd" --+
|
||||||
|
//
|
||||||
|
// See environSizesGet
|
||||||
|
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#environ_get
|
||||||
|
// See https://en.wikipedia.org/wiki/Null-terminated_string
|
||||||
|
var environGet = newHostFunc(wasip1.EnvironGetName, environGetFn, []api.ValueType{i32, i32}, "environ", "environ_buf")
|
||||||
|
|
||||||
|
func environGetFn(_ context.Context, mod api.Module, params []uint64) sys.Errno {
|
||||||
|
sysCtx := mod.(*wasm.ModuleInstance).Sys
|
||||||
|
environ, environBuf := uint32(params[0]), uint32(params[1])
|
||||||
|
|
||||||
|
return writeOffsetsAndNullTerminatedValues(mod.Memory(), sysCtx.Environ(), environ, environBuf, sysCtx.EnvironSize())
|
||||||
|
}
|
||||||
|
|
||||||
|
// environSizesGet is the WASI function named EnvironSizesGetName that
|
||||||
|
// reads environment variable sizes.
|
||||||
|
//
|
||||||
|
// # Parameters
|
||||||
|
//
|
||||||
|
// - resultEnvironc: offset to write the count of environment variables to
|
||||||
|
// api.Memory
|
||||||
|
// - resultEnvironvLen: offset to write the null-terminated environment
|
||||||
|
// variable length to api.Memory
|
||||||
|
//
|
||||||
|
// Result (Errno)
|
||||||
|
//
|
||||||
|
// The return value is 0 except the following error conditions:
|
||||||
|
// - sys.EFAULT: there is not enough memory to write results
|
||||||
|
//
|
||||||
|
// For example, if environ are "a=b","b=cd" and parameters resultEnvironc=1 and
|
||||||
|
// resultEnvironvLen=6, this function writes the below to api.Memory:
|
||||||
|
//
|
||||||
|
// uint32le uint32le
|
||||||
|
// +--------+ +--------+
|
||||||
|
// | | | |
|
||||||
|
// []byte{?, 2, 0, 0, 0, ?, 9, 0, 0, 0, ?}
|
||||||
|
// resultEnvironc --^ ^
|
||||||
|
// 2 variables --+ |
|
||||||
|
// resultEnvironvLen --|
|
||||||
|
// len([]byte{'a','=','b',0, |
|
||||||
|
// 'b','=','c','d',0}) --+
|
||||||
|
//
|
||||||
|
// See environGet
|
||||||
|
// https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#environ_sizes_get
|
||||||
|
// and https://en.wikipedia.org/wiki/Null-terminated_string
|
||||||
|
var environSizesGet = newHostFunc(wasip1.EnvironSizesGetName, environSizesGetFn, []api.ValueType{i32, i32}, "result.environc", "result.environv_len")
|
||||||
|
|
||||||
|
func environSizesGetFn(_ context.Context, mod api.Module, params []uint64) sys.Errno {
|
||||||
|
sysCtx := mod.(*wasm.ModuleInstance).Sys
|
||||||
|
mem := mod.Memory()
|
||||||
|
resultEnvironc, resultEnvironvLen := uint32(params[0]), uint32(params[1])
|
||||||
|
|
||||||
|
// environc and environv_len offsets are not necessarily sequential, so we
|
||||||
|
// have to write them independently.
|
||||||
|
if !mem.WriteUint32Le(resultEnvironc, uint32(len(sysCtx.Environ()))) {
|
||||||
|
return sys.EFAULT
|
||||||
|
}
|
||||||
|
if !mem.WriteUint32Le(resultEnvironvLen, sysCtx.EnvironSize()) {
|
||||||
|
return sys.EFAULT
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
2010
vendor/github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1/fs.go
generated
vendored
Normal file
2010
vendor/github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1/fs.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
237
vendor/github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1/poll.go
generated
vendored
Normal file
237
vendor/github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1/poll.go
generated
vendored
Normal file
@@ -0,0 +1,237 @@
|
|||||||
|
package wasi_snapshot_preview1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/tetratelabs/wazero/api"
|
||||||
|
"github.com/tetratelabs/wazero/experimental/sys"
|
||||||
|
"github.com/tetratelabs/wazero/internal/fsapi"
|
||||||
|
internalsys "github.com/tetratelabs/wazero/internal/sys"
|
||||||
|
"github.com/tetratelabs/wazero/internal/wasip1"
|
||||||
|
"github.com/tetratelabs/wazero/internal/wasm"
|
||||||
|
)
|
||||||
|
|
||||||
|
// pollOneoff is the WASI function named PollOneoffName that concurrently
|
||||||
|
// polls for the occurrence of a set of events.
|
||||||
|
//
|
||||||
|
// # Parameters
|
||||||
|
//
|
||||||
|
// - in: pointer to the subscriptions (48 bytes each)
|
||||||
|
// - out: pointer to the resulting events (32 bytes each)
|
||||||
|
// - nsubscriptions: count of subscriptions, zero returns sys.EINVAL.
|
||||||
|
// - resultNevents: count of events.
|
||||||
|
//
|
||||||
|
// Result (Errno)
|
||||||
|
//
|
||||||
|
// The return value is 0 except the following error conditions:
|
||||||
|
// - sys.EINVAL: the parameters are invalid
|
||||||
|
// - sys.ENOTSUP: a parameters is valid, but not yet supported.
|
||||||
|
// - sys.EFAULT: there is not enough memory to read the subscriptions or
|
||||||
|
// write results.
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// - Since the `out` pointer nests Errno, the result is always 0.
|
||||||
|
// - This is similar to `poll` in POSIX.
|
||||||
|
//
|
||||||
|
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#poll_oneoff
|
||||||
|
// See https://linux.die.net/man/3/poll
|
||||||
|
var pollOneoff = newHostFunc(
|
||||||
|
wasip1.PollOneoffName, pollOneoffFn,
|
||||||
|
[]api.ValueType{i32, i32, i32, i32},
|
||||||
|
"in", "out", "nsubscriptions", "result.nevents",
|
||||||
|
)
|
||||||
|
|
||||||
|
type event struct {
|
||||||
|
eventType byte
|
||||||
|
userData []byte
|
||||||
|
errno wasip1.Errno
|
||||||
|
}
|
||||||
|
|
||||||
|
func pollOneoffFn(_ context.Context, mod api.Module, params []uint64) sys.Errno {
|
||||||
|
in := uint32(params[0])
|
||||||
|
out := uint32(params[1])
|
||||||
|
nsubscriptions := uint32(params[2])
|
||||||
|
resultNevents := uint32(params[3])
|
||||||
|
|
||||||
|
if nsubscriptions == 0 {
|
||||||
|
return sys.EINVAL
|
||||||
|
}
|
||||||
|
|
||||||
|
mem := mod.Memory()
|
||||||
|
|
||||||
|
// Ensure capacity prior to the read loop to reduce error handling.
|
||||||
|
inBuf, ok := mem.Read(in, nsubscriptions*48)
|
||||||
|
if !ok {
|
||||||
|
return sys.EFAULT
|
||||||
|
}
|
||||||
|
outBuf, ok := mem.Read(out, nsubscriptions*32)
|
||||||
|
// zero-out all buffer before writing
|
||||||
|
clear(outBuf)
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
return sys.EFAULT
|
||||||
|
}
|
||||||
|
|
||||||
|
// Eagerly write the number of events which will equal subscriptions unless
|
||||||
|
// there's a fault in parsing (not processing).
|
||||||
|
if !mod.Memory().WriteUint32Le(resultNevents, nsubscriptions) {
|
||||||
|
return sys.EFAULT
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop through all subscriptions and write their output.
|
||||||
|
|
||||||
|
// Extract FS context, used in the body of the for loop for FS access.
|
||||||
|
fsc := mod.(*wasm.ModuleInstance).Sys.FS()
|
||||||
|
// Slice of events that are processed out of the loop (blocking stdin subscribers).
|
||||||
|
var blockingStdinSubs []*event
|
||||||
|
// The timeout is initialized at max Duration, the loop will find the minimum.
|
||||||
|
var timeout time.Duration = 1<<63 - 1
|
||||||
|
// Count of all the subscriptions that have been already written back to outBuf.
|
||||||
|
// nevents*32 returns at all times the offset where the next event should be written:
|
||||||
|
// this way we ensure that there are no gaps between records.
|
||||||
|
nevents := uint32(0)
|
||||||
|
|
||||||
|
// Layout is subscription_u: Union
|
||||||
|
// https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#subscription_u
|
||||||
|
for i := uint32(0); i < nsubscriptions; i++ {
|
||||||
|
inOffset := i * 48
|
||||||
|
outOffset := nevents * 32
|
||||||
|
|
||||||
|
eventType := inBuf[inOffset+8] // +8 past userdata
|
||||||
|
// +8 past userdata +8 contents_offset
|
||||||
|
argBuf := inBuf[inOffset+8+8:]
|
||||||
|
userData := inBuf[inOffset : inOffset+8]
|
||||||
|
|
||||||
|
evt := &event{
|
||||||
|
eventType: eventType,
|
||||||
|
userData: userData,
|
||||||
|
errno: wasip1.ErrnoSuccess,
|
||||||
|
}
|
||||||
|
|
||||||
|
switch eventType {
|
||||||
|
case wasip1.EventTypeClock: // handle later
|
||||||
|
newTimeout, err := processClockEvent(argBuf)
|
||||||
|
if err != 0 {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Min timeout.
|
||||||
|
if newTimeout < timeout {
|
||||||
|
timeout = newTimeout
|
||||||
|
}
|
||||||
|
// Ack the clock event to the outBuf.
|
||||||
|
writeEvent(outBuf[outOffset:], evt)
|
||||||
|
nevents++
|
||||||
|
case wasip1.EventTypeFdRead:
|
||||||
|
fd := int32(le.Uint32(argBuf))
|
||||||
|
if fd < 0 {
|
||||||
|
return sys.EBADF
|
||||||
|
}
|
||||||
|
if file, ok := fsc.LookupFile(fd); !ok {
|
||||||
|
evt.errno = wasip1.ErrnoBadf
|
||||||
|
writeEvent(outBuf[outOffset:], evt)
|
||||||
|
nevents++
|
||||||
|
} else if fd != internalsys.FdStdin && file.File.IsNonblock() {
|
||||||
|
writeEvent(outBuf[outOffset:], evt)
|
||||||
|
nevents++
|
||||||
|
} else {
|
||||||
|
// if the fd is Stdin, and it is in blocking mode,
|
||||||
|
// do not ack yet, append to a slice for delayed evaluation.
|
||||||
|
blockingStdinSubs = append(blockingStdinSubs, evt)
|
||||||
|
}
|
||||||
|
case wasip1.EventTypeFdWrite:
|
||||||
|
fd := int32(le.Uint32(argBuf))
|
||||||
|
if fd < 0 {
|
||||||
|
return sys.EBADF
|
||||||
|
}
|
||||||
|
if _, ok := fsc.LookupFile(fd); ok {
|
||||||
|
evt.errno = wasip1.ErrnoNotsup
|
||||||
|
} else {
|
||||||
|
evt.errno = wasip1.ErrnoBadf
|
||||||
|
}
|
||||||
|
nevents++
|
||||||
|
writeEvent(outBuf[outOffset:], evt)
|
||||||
|
default:
|
||||||
|
return sys.EINVAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sysCtx := mod.(*wasm.ModuleInstance).Sys
|
||||||
|
if nevents == nsubscriptions {
|
||||||
|
// We already wrote back all the results. We already wrote this number
|
||||||
|
// earlier to offset `resultNevents`.
|
||||||
|
// We only need to observe the timeout (nonzero if there are clock subscriptions)
|
||||||
|
// and return.
|
||||||
|
if timeout > 0 {
|
||||||
|
sysCtx.Nanosleep(int64(timeout))
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there are blocking stdin subscribers, check for data with given timeout.
|
||||||
|
stdin, ok := fsc.LookupFile(internalsys.FdStdin)
|
||||||
|
if !ok {
|
||||||
|
return sys.EBADF
|
||||||
|
}
|
||||||
|
// Wait for the timeout to expire, or for some data to become available on Stdin.
|
||||||
|
|
||||||
|
if stdinReady, errno := stdin.File.Poll(fsapi.POLLIN, int32(timeout.Milliseconds())); errno != 0 {
|
||||||
|
return errno
|
||||||
|
} else if stdinReady {
|
||||||
|
// stdin has data ready to for reading, write back all the events
|
||||||
|
for i := range blockingStdinSubs {
|
||||||
|
evt := blockingStdinSubs[i]
|
||||||
|
evt.errno = 0
|
||||||
|
writeEvent(outBuf[nevents*32:], evt)
|
||||||
|
nevents++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if nevents != nsubscriptions {
|
||||||
|
if !mod.Memory().WriteUint32Le(resultNevents, nevents) {
|
||||||
|
return sys.EFAULT
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// processClockEvent supports only relative name events, as that's what's used
|
||||||
|
// to implement sleep in various compilers including Rust, Zig and TinyGo.
|
||||||
|
func processClockEvent(inBuf []byte) (time.Duration, sys.Errno) {
|
||||||
|
_ /* ID */ = le.Uint32(inBuf[0:8]) // See below
|
||||||
|
timeout := le.Uint64(inBuf[8:16]) // nanos if relative
|
||||||
|
_ /* precision */ = le.Uint64(inBuf[16:24]) // Unused
|
||||||
|
flags := le.Uint16(inBuf[24:32])
|
||||||
|
|
||||||
|
var err sys.Errno
|
||||||
|
// subclockflags has only one flag defined: subscription_clock_abstime
|
||||||
|
switch flags {
|
||||||
|
case 0: // relative time
|
||||||
|
case 1: // subscription_clock_abstime
|
||||||
|
err = sys.ENOTSUP
|
||||||
|
default: // subclockflags has only one flag defined.
|
||||||
|
err = sys.EINVAL
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != 0 {
|
||||||
|
return 0, err
|
||||||
|
} else {
|
||||||
|
// https://linux.die.net/man/3/clock_settime says relative timers are
|
||||||
|
// unaffected. Since this function only supports relative timeout, we can
|
||||||
|
// skip name ID validation and use a single sleep function.
|
||||||
|
|
||||||
|
return time.Duration(timeout), 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// writeEvent writes the event corresponding to the processed subscription.
|
||||||
|
// https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-event-struct
|
||||||
|
func writeEvent(outBuf []byte, evt *event) {
|
||||||
|
copy(outBuf, evt.userData) // userdata
|
||||||
|
outBuf[8] = byte(evt.errno) // uint16, but safe as < 255
|
||||||
|
outBuf[9] = 0
|
||||||
|
le.PutUint32(outBuf[10:], uint32(evt.eventType))
|
||||||
|
// TODO: When FD events are supported, write outOffset+16
|
||||||
|
}
|
||||||
44
vendor/github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1/proc.go
generated
vendored
Normal file
44
vendor/github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1/proc.go
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
package wasi_snapshot_preview1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/tetratelabs/wazero/api"
|
||||||
|
"github.com/tetratelabs/wazero/internal/wasip1"
|
||||||
|
"github.com/tetratelabs/wazero/internal/wasm"
|
||||||
|
"github.com/tetratelabs/wazero/sys"
|
||||||
|
)
|
||||||
|
|
||||||
|
// procExit is the WASI function named ProcExitName that terminates the
|
||||||
|
// execution of the module with an exit code. The only successful exit code is
|
||||||
|
// zero.
|
||||||
|
//
|
||||||
|
// # Parameters
|
||||||
|
//
|
||||||
|
// - exitCode: exit code.
|
||||||
|
//
|
||||||
|
// See https://github.com/WebAssembly/WASI/blob/main/phases/snapshot/docs.md#proc_exit
|
||||||
|
var procExit = &wasm.HostFunc{
|
||||||
|
ExportName: wasip1.ProcExitName,
|
||||||
|
Name: wasip1.ProcExitName,
|
||||||
|
ParamTypes: []api.ValueType{i32},
|
||||||
|
ParamNames: []string{"rval"},
|
||||||
|
Code: wasm.Code{GoFunc: api.GoModuleFunc(procExitFn)},
|
||||||
|
}
|
||||||
|
|
||||||
|
func procExitFn(ctx context.Context, mod api.Module, params []uint64) {
|
||||||
|
exitCode := uint32(params[0])
|
||||||
|
|
||||||
|
// Ensure other callers see the exit code.
|
||||||
|
_ = mod.CloseWithExitCode(ctx, exitCode)
|
||||||
|
|
||||||
|
// Prevent any code from executing after this function. For example, LLVM
|
||||||
|
// inserts unreachable instructions after calls to exit.
|
||||||
|
// See: https://github.com/emscripten-core/emscripten/issues/12322
|
||||||
|
panic(sys.NewExitError(exitCode))
|
||||||
|
}
|
||||||
|
|
||||||
|
// procRaise is stubbed and will never be supported, as it was removed.
|
||||||
|
//
|
||||||
|
// See https://github.com/WebAssembly/WASI/pull/136
|
||||||
|
var procRaise = stubFunction(wasip1.ProcRaiseName, []api.ValueType{i32}, "sig")
|
||||||
55
vendor/github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1/random.go
generated
vendored
Normal file
55
vendor/github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1/random.go
generated
vendored
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
package wasi_snapshot_preview1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/tetratelabs/wazero/api"
|
||||||
|
"github.com/tetratelabs/wazero/experimental/sys"
|
||||||
|
"github.com/tetratelabs/wazero/internal/wasip1"
|
||||||
|
"github.com/tetratelabs/wazero/internal/wasm"
|
||||||
|
)
|
||||||
|
|
||||||
|
// randomGet is the WASI function named RandomGetName which writes random
|
||||||
|
// data to a buffer.
|
||||||
|
//
|
||||||
|
// # Parameters
|
||||||
|
//
|
||||||
|
// - buf: api.Memory offset to write random values
|
||||||
|
// - bufLen: size of random data in bytes
|
||||||
|
//
|
||||||
|
// Result (Errno)
|
||||||
|
//
|
||||||
|
// The return value is ErrnoSuccess except the following error conditions:
|
||||||
|
// - sys.EFAULT: `buf` or `bufLen` point to an offset out of memory
|
||||||
|
// - sys.EIO: a file system error
|
||||||
|
//
|
||||||
|
// For example, if underlying random source was seeded like
|
||||||
|
// `rand.NewSource(42)`, we expect api.Memory to contain:
|
||||||
|
//
|
||||||
|
// bufLen (5)
|
||||||
|
// +--------------------------+
|
||||||
|
// | |
|
||||||
|
// []byte{?, 0x53, 0x8c, 0x7f, 0x96, 0xb1, ?}
|
||||||
|
// buf --^
|
||||||
|
//
|
||||||
|
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-random_getbuf-pointeru8-bufLen-size---errno
|
||||||
|
var randomGet = newHostFunc(wasip1.RandomGetName, randomGetFn, []api.ValueType{i32, i32}, "buf", "buf_len")
|
||||||
|
|
||||||
|
func randomGetFn(_ context.Context, mod api.Module, params []uint64) sys.Errno {
|
||||||
|
sysCtx := mod.(*wasm.ModuleInstance).Sys
|
||||||
|
randSource := sysCtx.RandSource()
|
||||||
|
buf, bufLen := uint32(params[0]), uint32(params[1])
|
||||||
|
|
||||||
|
randomBytes, ok := mod.Memory().Read(buf, bufLen)
|
||||||
|
if !ok { // out-of-range
|
||||||
|
return sys.EFAULT
|
||||||
|
}
|
||||||
|
|
||||||
|
// We can ignore the returned n as it only != byteCount on error
|
||||||
|
if _, err := io.ReadAtLeast(randSource, randomBytes, int(bufLen)); err != nil {
|
||||||
|
return sys.EIO
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
22
vendor/github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1/sched.go
generated
vendored
Normal file
22
vendor/github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1/sched.go
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
package wasi_snapshot_preview1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/tetratelabs/wazero/api"
|
||||||
|
"github.com/tetratelabs/wazero/experimental/sys"
|
||||||
|
"github.com/tetratelabs/wazero/internal/wasip1"
|
||||||
|
"github.com/tetratelabs/wazero/internal/wasm"
|
||||||
|
)
|
||||||
|
|
||||||
|
// schedYield is the WASI function named SchedYieldName which temporarily
|
||||||
|
// yields execution of the calling thread.
|
||||||
|
//
|
||||||
|
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-sched_yield---errno
|
||||||
|
var schedYield = newHostFunc(wasip1.SchedYieldName, schedYieldFn, nil)
|
||||||
|
|
||||||
|
func schedYieldFn(_ context.Context, mod api.Module, _ []uint64) sys.Errno {
|
||||||
|
sysCtx := mod.(*wasm.ModuleInstance).Sys
|
||||||
|
sysCtx.Osyield()
|
||||||
|
return 0
|
||||||
|
}
|
||||||
188
vendor/github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1/sock.go
generated
vendored
Normal file
188
vendor/github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1/sock.go
generated
vendored
Normal file
@@ -0,0 +1,188 @@
|
|||||||
|
package wasi_snapshot_preview1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/tetratelabs/wazero/api"
|
||||||
|
"github.com/tetratelabs/wazero/experimental/sys"
|
||||||
|
socketapi "github.com/tetratelabs/wazero/internal/sock"
|
||||||
|
"github.com/tetratelabs/wazero/internal/sysfs"
|
||||||
|
"github.com/tetratelabs/wazero/internal/wasip1"
|
||||||
|
"github.com/tetratelabs/wazero/internal/wasm"
|
||||||
|
)
|
||||||
|
|
||||||
|
// sockAccept is the WASI function named SockAcceptName which accepts a new
|
||||||
|
// incoming connection.
|
||||||
|
//
|
||||||
|
// See: https://github.com/WebAssembly/WASI/blob/0ba0c5e2e37625ca5a6d3e4255a998dfaa3efc52/phases/snapshot/docs.md#sock_accept
|
||||||
|
// and https://github.com/WebAssembly/WASI/pull/458
|
||||||
|
var sockAccept = newHostFunc(
|
||||||
|
wasip1.SockAcceptName,
|
||||||
|
sockAcceptFn,
|
||||||
|
[]wasm.ValueType{i32, i32, i32},
|
||||||
|
"fd", "flags", "result.fd",
|
||||||
|
)
|
||||||
|
|
||||||
|
func sockAcceptFn(_ context.Context, mod api.Module, params []uint64) (errno sys.Errno) {
|
||||||
|
mem := mod.Memory()
|
||||||
|
fsc := mod.(*wasm.ModuleInstance).Sys.FS()
|
||||||
|
|
||||||
|
fd := int32(params[0])
|
||||||
|
flags := uint32(params[1])
|
||||||
|
resultFd := uint32(params[2])
|
||||||
|
nonblock := flags&uint32(wasip1.FD_NONBLOCK) != 0
|
||||||
|
|
||||||
|
var connFD int32
|
||||||
|
if connFD, errno = fsc.SockAccept(fd, nonblock); errno == 0 {
|
||||||
|
mem.WriteUint32Le(resultFd, uint32(connFD))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// sockRecv is the WASI function named SockRecvName which receives a
|
||||||
|
// message from a socket.
|
||||||
|
//
|
||||||
|
// See: https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-sock_recvfd-fd-ri_data-iovec_array-ri_flags-riflags---errno-size-roflags
|
||||||
|
var sockRecv = newHostFunc(
|
||||||
|
wasip1.SockRecvName,
|
||||||
|
sockRecvFn,
|
||||||
|
[]wasm.ValueType{i32, i32, i32, i32, i32, i32},
|
||||||
|
"fd", "ri_data", "ri_data_len", "ri_flags", "result.ro_datalen", "result.ro_flags",
|
||||||
|
)
|
||||||
|
|
||||||
|
func sockRecvFn(_ context.Context, mod api.Module, params []uint64) sys.Errno {
|
||||||
|
mem := mod.Memory()
|
||||||
|
fsc := mod.(*wasm.ModuleInstance).Sys.FS()
|
||||||
|
|
||||||
|
fd := int32(params[0])
|
||||||
|
riData := uint32(params[1])
|
||||||
|
riDataCount := uint32(params[2])
|
||||||
|
riFlags := uint8(params[3])
|
||||||
|
resultRoDatalen := uint32(params[4])
|
||||||
|
resultRoFlags := uint32(params[5])
|
||||||
|
|
||||||
|
var conn socketapi.TCPConn
|
||||||
|
if e, ok := fsc.LookupFile(fd); !ok {
|
||||||
|
return sys.EBADF // Not open
|
||||||
|
} else if conn, ok = e.File.(socketapi.TCPConn); !ok {
|
||||||
|
return sys.EBADF // Not a conn
|
||||||
|
}
|
||||||
|
|
||||||
|
if riFlags & ^(wasip1.RI_RECV_PEEK|wasip1.RI_RECV_WAITALL) != 0 {
|
||||||
|
return sys.ENOTSUP
|
||||||
|
}
|
||||||
|
|
||||||
|
if riFlags&wasip1.RI_RECV_PEEK != 0 {
|
||||||
|
// Each record in riData is of the form:
|
||||||
|
// type iovec struct { buf *uint8; bufLen uint32 }
|
||||||
|
// This means that the first `uint32` is a `buf *uint8`.
|
||||||
|
firstIovecBufAddr, ok := mem.ReadUint32Le(riData)
|
||||||
|
if !ok {
|
||||||
|
return sys.EINVAL
|
||||||
|
}
|
||||||
|
// Read bufLen
|
||||||
|
firstIovecBufLen, ok := mem.ReadUint32Le(riData + 4)
|
||||||
|
if !ok {
|
||||||
|
return sys.EINVAL
|
||||||
|
}
|
||||||
|
firstIovecBuf, ok := mem.Read(firstIovecBufAddr, firstIovecBufLen)
|
||||||
|
if !ok {
|
||||||
|
return sys.EINVAL
|
||||||
|
}
|
||||||
|
n, err := conn.Recvfrom(firstIovecBuf, sysfs.MSG_PEEK)
|
||||||
|
if err != 0 {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
mem.WriteUint32Le(resultRoDatalen, uint32(n))
|
||||||
|
mem.WriteUint16Le(resultRoFlags, 0)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// If riFlags&wasip1.RECV_WAITALL != 0 then we should
|
||||||
|
// do a blocking operation until all data has been retrieved;
|
||||||
|
// otherwise we are able to return earlier.
|
||||||
|
// For simplicity, we currently wait all regardless the flag.
|
||||||
|
bufSize, errno := readv(mem, riData, riDataCount, conn.Read)
|
||||||
|
if errno != 0 {
|
||||||
|
return errno
|
||||||
|
}
|
||||||
|
mem.WriteUint32Le(resultRoDatalen, bufSize)
|
||||||
|
mem.WriteUint16Le(resultRoFlags, 0)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// sockSend is the WASI function named SockSendName which sends a message
|
||||||
|
// on a socket.
|
||||||
|
//
|
||||||
|
// See: https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-sock_sendfd-fd-si_data-ciovec_array-si_flags-siflags---errno-size
|
||||||
|
var sockSend = newHostFunc(
|
||||||
|
wasip1.SockSendName,
|
||||||
|
sockSendFn,
|
||||||
|
[]wasm.ValueType{i32, i32, i32, i32, i32},
|
||||||
|
"fd", "si_data", "si_data_len", "si_flags", "result.so_datalen",
|
||||||
|
)
|
||||||
|
|
||||||
|
func sockSendFn(_ context.Context, mod api.Module, params []uint64) sys.Errno {
|
||||||
|
mem := mod.Memory()
|
||||||
|
fsc := mod.(*wasm.ModuleInstance).Sys.FS()
|
||||||
|
|
||||||
|
fd := int32(params[0])
|
||||||
|
siData := uint32(params[1])
|
||||||
|
siDataCount := uint32(params[2])
|
||||||
|
siFlags := uint32(params[3])
|
||||||
|
resultSoDatalen := uint32(params[4])
|
||||||
|
|
||||||
|
if siFlags != 0 {
|
||||||
|
return sys.ENOTSUP
|
||||||
|
}
|
||||||
|
|
||||||
|
var conn socketapi.TCPConn
|
||||||
|
if e, ok := fsc.LookupFile(fd); !ok {
|
||||||
|
return sys.EBADF // Not open
|
||||||
|
} else if conn, ok = e.File.(socketapi.TCPConn); !ok {
|
||||||
|
return sys.EBADF // Not a conn
|
||||||
|
}
|
||||||
|
|
||||||
|
bufSize, errno := writev(mem, siData, siDataCount, conn.Write)
|
||||||
|
if errno != 0 {
|
||||||
|
return errno
|
||||||
|
}
|
||||||
|
mem.WriteUint32Le(resultSoDatalen, bufSize)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// sockShutdown is the WASI function named SockShutdownName which shuts
|
||||||
|
// down socket send and receive channels.
|
||||||
|
//
|
||||||
|
// See: https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-sock_shutdownfd-fd-how-sdflags---errno
|
||||||
|
var sockShutdown = newHostFunc(wasip1.SockShutdownName, sockShutdownFn, []wasm.ValueType{i32, i32}, "fd", "how")
|
||||||
|
|
||||||
|
func sockShutdownFn(_ context.Context, mod api.Module, params []uint64) sys.Errno {
|
||||||
|
fsc := mod.(*wasm.ModuleInstance).Sys.FS()
|
||||||
|
|
||||||
|
fd := int32(params[0])
|
||||||
|
how := uint8(params[1])
|
||||||
|
|
||||||
|
var conn socketapi.TCPConn
|
||||||
|
if e, ok := fsc.LookupFile(fd); !ok {
|
||||||
|
return sys.EBADF // Not open
|
||||||
|
} else if conn, ok = e.File.(socketapi.TCPConn); !ok {
|
||||||
|
return sys.EBADF // Not a conn
|
||||||
|
}
|
||||||
|
|
||||||
|
sysHow := 0
|
||||||
|
|
||||||
|
switch how {
|
||||||
|
case wasip1.SD_RD | wasip1.SD_WR:
|
||||||
|
sysHow = socketapi.SHUT_RD | socketapi.SHUT_WR
|
||||||
|
case wasip1.SD_RD:
|
||||||
|
sysHow = socketapi.SHUT_RD
|
||||||
|
case wasip1.SD_WR:
|
||||||
|
sysHow = socketapi.SHUT_WR
|
||||||
|
default:
|
||||||
|
return sys.EINVAL
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Map this instead of relying on syscall symbols.
|
||||||
|
return conn.Shutdown(sysHow)
|
||||||
|
}
|
||||||
314
vendor/github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1/wasi.go
generated
vendored
Normal file
314
vendor/github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1/wasi.go
generated
vendored
Normal file
@@ -0,0 +1,314 @@
|
|||||||
|
// Package wasi_snapshot_preview1 contains Go-defined functions to access
|
||||||
|
// system calls, such as opening a file, similar to Go's x/sys package. These
|
||||||
|
// are accessible from WebAssembly-defined functions via importing ModuleName.
|
||||||
|
// All WASI functions return a single Errno result: ErrnoSuccess on success.
|
||||||
|
//
|
||||||
|
// e.g. Call Instantiate before instantiating any wasm binary that imports
|
||||||
|
// "wasi_snapshot_preview1", Otherwise, it will error due to missing imports.
|
||||||
|
//
|
||||||
|
// ctx := context.Background()
|
||||||
|
// r := wazero.NewRuntime(ctx)
|
||||||
|
// defer r.Close(ctx) // This closes everything this Runtime created.
|
||||||
|
//
|
||||||
|
// wasi_snapshot_preview1.MustInstantiate(ctx, r)
|
||||||
|
// mod, _ := r.Instantiate(ctx, wasm)
|
||||||
|
//
|
||||||
|
// See https://github.com/WebAssembly/WASI
|
||||||
|
package wasi_snapshot_preview1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/binary"
|
||||||
|
|
||||||
|
"github.com/tetratelabs/wazero"
|
||||||
|
"github.com/tetratelabs/wazero/api"
|
||||||
|
"github.com/tetratelabs/wazero/experimental/sys"
|
||||||
|
"github.com/tetratelabs/wazero/internal/wasip1"
|
||||||
|
"github.com/tetratelabs/wazero/internal/wasm"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ModuleName is the module name WASI functions are exported into.
|
||||||
|
//
|
||||||
|
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md
|
||||||
|
const ModuleName = wasip1.InternalModuleName
|
||||||
|
|
||||||
|
const i32, i64 = wasm.ValueTypeI32, wasm.ValueTypeI64
|
||||||
|
|
||||||
|
var le = binary.LittleEndian
|
||||||
|
|
||||||
|
// MustInstantiate calls Instantiate or panics on error.
|
||||||
|
//
|
||||||
|
// This is a simpler function for those who know the module ModuleName is not
|
||||||
|
// already instantiated, and don't need to unload it.
|
||||||
|
func MustInstantiate(ctx context.Context, r wazero.Runtime) {
|
||||||
|
if _, err := Instantiate(ctx, r); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Instantiate instantiates the ModuleName module into the runtime.
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// - Failure cases are documented on wazero.Runtime InstantiateModule.
|
||||||
|
// - Closing the wazero.Runtime has the same effect as closing the result.
|
||||||
|
func Instantiate(ctx context.Context, r wazero.Runtime) (api.Closer, error) {
|
||||||
|
return NewBuilder(r).Instantiate(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Builder configures the ModuleName module for later use via Compile or Instantiate.
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// - This is an interface for decoupling, not third-party implementations.
|
||||||
|
// All implementations are in wazero.
|
||||||
|
type Builder interface {
|
||||||
|
// Compile compiles the ModuleName module. Call this before Instantiate.
|
||||||
|
//
|
||||||
|
// Note: This has the same effect as the same function on wazero.HostModuleBuilder.
|
||||||
|
Compile(context.Context) (wazero.CompiledModule, error)
|
||||||
|
|
||||||
|
// Instantiate instantiates the ModuleName module and returns a function to close it.
|
||||||
|
//
|
||||||
|
// Note: This has the same effect as the same function on wazero.HostModuleBuilder.
|
||||||
|
Instantiate(context.Context) (api.Closer, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewBuilder returns a new Builder.
|
||||||
|
func NewBuilder(r wazero.Runtime) Builder {
|
||||||
|
return &builder{r}
|
||||||
|
}
|
||||||
|
|
||||||
|
type builder struct{ r wazero.Runtime }
|
||||||
|
|
||||||
|
// hostModuleBuilder returns a new wazero.HostModuleBuilder for ModuleName
|
||||||
|
func (b *builder) hostModuleBuilder() wazero.HostModuleBuilder {
|
||||||
|
ret := b.r.NewHostModuleBuilder(ModuleName)
|
||||||
|
exportFunctions(ret)
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compile implements Builder.Compile
|
||||||
|
func (b *builder) Compile(ctx context.Context) (wazero.CompiledModule, error) {
|
||||||
|
return b.hostModuleBuilder().Compile(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Instantiate implements Builder.Instantiate
|
||||||
|
func (b *builder) Instantiate(ctx context.Context) (api.Closer, error) {
|
||||||
|
return b.hostModuleBuilder().Instantiate(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FunctionExporter exports functions into a wazero.HostModuleBuilder.
|
||||||
|
//
|
||||||
|
// # Notes
|
||||||
|
//
|
||||||
|
// - This is an interface for decoupling, not third-party implementations.
|
||||||
|
// All implementations are in wazero.
|
||||||
|
type FunctionExporter interface {
|
||||||
|
ExportFunctions(wazero.HostModuleBuilder)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewFunctionExporter returns a new FunctionExporter. This is used for the
|
||||||
|
// following two use cases:
|
||||||
|
// - Overriding a builtin function with an alternate implementation.
|
||||||
|
// - Exporting functions to the module "wasi_unstable" for legacy code.
|
||||||
|
//
|
||||||
|
// # Example of overriding default behavior
|
||||||
|
//
|
||||||
|
// // Export the default WASI functions.
|
||||||
|
// wasiBuilder := r.NewHostModuleBuilder(ModuleName)
|
||||||
|
// wasi_snapshot_preview1.NewFunctionExporter().ExportFunctions(wasiBuilder)
|
||||||
|
//
|
||||||
|
// // Subsequent calls to NewFunctionBuilder override built-in exports.
|
||||||
|
// wasiBuilder.NewFunctionBuilder().
|
||||||
|
// WithFunc(func(ctx context.Context, mod api.Module, exitCode uint32) {
|
||||||
|
// // your custom logic
|
||||||
|
// }).Export("proc_exit")
|
||||||
|
//
|
||||||
|
// # Example of using the old module name for WASI
|
||||||
|
//
|
||||||
|
// // Instantiate the current WASI functions under the wasi_unstable
|
||||||
|
// // instead of wasi_snapshot_preview1.
|
||||||
|
// wasiBuilder := r.NewHostModuleBuilder("wasi_unstable")
|
||||||
|
// wasi_snapshot_preview1.NewFunctionExporter().ExportFunctions(wasiBuilder)
|
||||||
|
// _, err := wasiBuilder.Instantiate(testCtx, r)
|
||||||
|
func NewFunctionExporter() FunctionExporter {
|
||||||
|
return &functionExporter{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type functionExporter struct{}
|
||||||
|
|
||||||
|
// ExportFunctions implements FunctionExporter.ExportFunctions
|
||||||
|
func (functionExporter) ExportFunctions(builder wazero.HostModuleBuilder) {
|
||||||
|
exportFunctions(builder)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ## Translation notes
|
||||||
|
// ### String
|
||||||
|
// WebAssembly 1.0 has no string type, so any string input parameter expands to two uint32 parameters: offset
|
||||||
|
// and length.
|
||||||
|
//
|
||||||
|
// ### iovec_array
|
||||||
|
// `iovec_array` is encoded as two uin32le values (i32): offset and count.
|
||||||
|
//
|
||||||
|
// ### Result
|
||||||
|
// Each result besides Errno is always an uint32 parameter. WebAssembly 1.0 can have up to one result,
|
||||||
|
// which is already used by Errno. This forces other results to be parameters. A result parameter is a memory
|
||||||
|
// offset to write the result to. As memory offsets are uint32, each parameter representing a result is uint32.
|
||||||
|
//
|
||||||
|
// ### Errno
|
||||||
|
// The WASI specification is sometimes ambiguous resulting in some runtimes interpreting the same function ways.
|
||||||
|
// Errno mappings are not defined in WASI, yet, so these mappings are best efforts by maintainers. When in doubt
|
||||||
|
// about portability, first look at /RATIONALE.md and if needed an issue on
|
||||||
|
// https://github.com/WebAssembly/WASI/issues
|
||||||
|
//
|
||||||
|
// ## Memory
|
||||||
|
// In WebAssembly 1.0 (20191205), there may be up to one Memory per store, which means api.Memory is always the
|
||||||
|
// wasm.Store Memories index zero: `store.Memories[0].Buffer`
|
||||||
|
//
|
||||||
|
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md
|
||||||
|
// See https://github.com/WebAssembly/WASI/issues/215
|
||||||
|
// See https://wwa.w3.org/TR/2019/REC-wasm-core-1-20191205/#memory-instances%E2%91%A0.
|
||||||
|
|
||||||
|
// exportFunctions adds all go functions that implement wasi.
|
||||||
|
// These should be exported in the module named ModuleName.
|
||||||
|
func exportFunctions(builder wazero.HostModuleBuilder) {
|
||||||
|
exporter := builder.(wasm.HostFuncExporter)
|
||||||
|
|
||||||
|
// Note: these are ordered per spec for consistency even if the resulting
|
||||||
|
// map can't guarantee that.
|
||||||
|
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#functions
|
||||||
|
exporter.ExportHostFunc(argsGet)
|
||||||
|
exporter.ExportHostFunc(argsSizesGet)
|
||||||
|
exporter.ExportHostFunc(environGet)
|
||||||
|
exporter.ExportHostFunc(environSizesGet)
|
||||||
|
exporter.ExportHostFunc(clockResGet)
|
||||||
|
exporter.ExportHostFunc(clockTimeGet)
|
||||||
|
exporter.ExportHostFunc(fdAdvise)
|
||||||
|
exporter.ExportHostFunc(fdAllocate)
|
||||||
|
exporter.ExportHostFunc(fdClose)
|
||||||
|
exporter.ExportHostFunc(fdDatasync)
|
||||||
|
exporter.ExportHostFunc(fdFdstatGet)
|
||||||
|
exporter.ExportHostFunc(fdFdstatSetFlags)
|
||||||
|
exporter.ExportHostFunc(fdFdstatSetRights)
|
||||||
|
exporter.ExportHostFunc(fdFilestatGet)
|
||||||
|
exporter.ExportHostFunc(fdFilestatSetSize)
|
||||||
|
exporter.ExportHostFunc(fdFilestatSetTimes)
|
||||||
|
exporter.ExportHostFunc(fdPread)
|
||||||
|
exporter.ExportHostFunc(fdPrestatGet)
|
||||||
|
exporter.ExportHostFunc(fdPrestatDirName)
|
||||||
|
exporter.ExportHostFunc(fdPwrite)
|
||||||
|
exporter.ExportHostFunc(fdRead)
|
||||||
|
exporter.ExportHostFunc(fdReaddir)
|
||||||
|
exporter.ExportHostFunc(fdRenumber)
|
||||||
|
exporter.ExportHostFunc(fdSeek)
|
||||||
|
exporter.ExportHostFunc(fdSync)
|
||||||
|
exporter.ExportHostFunc(fdTell)
|
||||||
|
exporter.ExportHostFunc(fdWrite)
|
||||||
|
exporter.ExportHostFunc(pathCreateDirectory)
|
||||||
|
exporter.ExportHostFunc(pathFilestatGet)
|
||||||
|
exporter.ExportHostFunc(pathFilestatSetTimes)
|
||||||
|
exporter.ExportHostFunc(pathLink)
|
||||||
|
exporter.ExportHostFunc(pathOpen)
|
||||||
|
exporter.ExportHostFunc(pathReadlink)
|
||||||
|
exporter.ExportHostFunc(pathRemoveDirectory)
|
||||||
|
exporter.ExportHostFunc(pathRename)
|
||||||
|
exporter.ExportHostFunc(pathSymlink)
|
||||||
|
exporter.ExportHostFunc(pathUnlinkFile)
|
||||||
|
exporter.ExportHostFunc(pollOneoff)
|
||||||
|
exporter.ExportHostFunc(procExit)
|
||||||
|
exporter.ExportHostFunc(procRaise)
|
||||||
|
exporter.ExportHostFunc(schedYield)
|
||||||
|
exporter.ExportHostFunc(randomGet)
|
||||||
|
exporter.ExportHostFunc(sockAccept)
|
||||||
|
exporter.ExportHostFunc(sockRecv)
|
||||||
|
exporter.ExportHostFunc(sockSend)
|
||||||
|
exporter.ExportHostFunc(sockShutdown)
|
||||||
|
}
|
||||||
|
|
||||||
|
// writeOffsetsAndNullTerminatedValues is used to write NUL-terminated values
|
||||||
|
// for args or environ, given a pre-defined bytesLen (which includes NUL
|
||||||
|
// terminators).
|
||||||
|
func writeOffsetsAndNullTerminatedValues(mem api.Memory, values [][]byte, offsets, bytes, bytesLen uint32) sys.Errno {
|
||||||
|
// The caller may not place bytes directly after offsets, so we have to
|
||||||
|
// read them independently.
|
||||||
|
valuesLen := len(values)
|
||||||
|
offsetsLen := uint32(valuesLen * 4) // uint32Le
|
||||||
|
offsetsBuf, ok := mem.Read(offsets, offsetsLen)
|
||||||
|
if !ok {
|
||||||
|
return sys.EFAULT
|
||||||
|
}
|
||||||
|
bytesBuf, ok := mem.Read(bytes, bytesLen)
|
||||||
|
if !ok {
|
||||||
|
return sys.EFAULT
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop through the values, first writing the location of its data to
|
||||||
|
// offsetsBuf[oI], then its NUL-terminated data at bytesBuf[bI]
|
||||||
|
var oI, bI uint32
|
||||||
|
for _, value := range values {
|
||||||
|
// Go can't guarantee inlining as there's not //go:inline directive.
|
||||||
|
// This inlines uint32 little-endian encoding instead.
|
||||||
|
bytesOffset := bytes + bI
|
||||||
|
offsetsBuf[oI] = byte(bytesOffset)
|
||||||
|
offsetsBuf[oI+1] = byte(bytesOffset >> 8)
|
||||||
|
offsetsBuf[oI+2] = byte(bytesOffset >> 16)
|
||||||
|
offsetsBuf[oI+3] = byte(bytesOffset >> 24)
|
||||||
|
oI += 4 // size of uint32 we just wrote
|
||||||
|
|
||||||
|
// Write the next value to memory with a NUL terminator
|
||||||
|
copy(bytesBuf[bI:], value)
|
||||||
|
bI += uint32(len(value))
|
||||||
|
bytesBuf[bI] = 0 // NUL terminator
|
||||||
|
bI++
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func newHostFunc(
|
||||||
|
name string,
|
||||||
|
goFunc wasiFunc,
|
||||||
|
paramTypes []api.ValueType,
|
||||||
|
paramNames ...string,
|
||||||
|
) *wasm.HostFunc {
|
||||||
|
return &wasm.HostFunc{
|
||||||
|
ExportName: name,
|
||||||
|
Name: name,
|
||||||
|
ParamTypes: paramTypes,
|
||||||
|
ParamNames: paramNames,
|
||||||
|
ResultTypes: []api.ValueType{i32},
|
||||||
|
ResultNames: []string{"errno"},
|
||||||
|
Code: wasm.Code{GoFunc: goFunc},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// wasiFunc special cases that all WASI functions return a single Errno
|
||||||
|
// result. The returned value will be written back to the stack at index zero.
|
||||||
|
type wasiFunc func(ctx context.Context, mod api.Module, params []uint64) sys.Errno
|
||||||
|
|
||||||
|
// Call implements the same method as documented on api.GoModuleFunction.
|
||||||
|
func (f wasiFunc) Call(ctx context.Context, mod api.Module, stack []uint64) {
|
||||||
|
// Write the result back onto the stack
|
||||||
|
errno := f(ctx, mod, stack)
|
||||||
|
if errno != 0 {
|
||||||
|
stack[0] = uint64(wasip1.ToErrno(errno))
|
||||||
|
} else { // special case ass ErrnoSuccess is zero
|
||||||
|
stack[0] = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// stubFunction stubs for GrainLang per #271.
|
||||||
|
func stubFunction(name string, paramTypes []wasm.ValueType, paramNames ...string) *wasm.HostFunc {
|
||||||
|
return &wasm.HostFunc{
|
||||||
|
ExportName: name,
|
||||||
|
Name: name,
|
||||||
|
ParamTypes: paramTypes,
|
||||||
|
ParamNames: paramNames,
|
||||||
|
ResultTypes: []api.ValueType{i32},
|
||||||
|
ResultNames: []string{"errno"},
|
||||||
|
Code: wasm.Code{
|
||||||
|
GoFunc: api.GoModuleFunc(func(_ context.Context, _ api.Module, stack []uint64) { stack[0] = uint64(wasip1.ErrnoNosys) }),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user