Compare commits

...

64 Commits

Author SHA1 Message Date
dependabot[bot]
9259344452 Bump golang.org/x/net from 0.36.0 to 0.38.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.36.0 to 0.38.0.
- [Commits](https://github.com/golang/net/compare/v0.36.0...v0.38.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-version: 0.38.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-28 15:18:33 +01:00
Han Verstraete (OpenFaaS Ltd)
83e804513a Fix faasd CE install script for RHEL-based systems
This change removes the check-update command. This command is not
required and caused the script to exit early if packages are not up to
date.

In addition DNF is now used to install packages. DNF is the successor of
YUM on the latest RHEL-based system.

Signed-off-by: Han Verstraete (OpenFaaS Ltd) <han@openfaas.com>
2025-05-20 17:21:08 +01:00
Han Verstraete (OpenFaaS Ltd)
f409e01aa6 Don't install weak dependencies on RHEL-based systems
Signed-off-by: Han Verstraete (OpenFaaS Ltd) <han@openfaas.com>
2025-05-20 17:21:08 +01:00
Han Verstraete (OpenFaaS Ltd)
e98c949019 Add allowerasing flag to dnf install
Fixes issues with conflicting packages that may occur on some systems.

Signed-off-by: Han Verstraete (OpenFaaS Ltd) <han@openfaas.com>
2025-05-20 13:53:26 +01:00
Han Verstraete (OpenFaaS Ltd)
6f0ac37e3c Add bridge-utils to RHEL packages
Signed-off-by: Han Verstraete (OpenFaaS Ltd) <han@openfaas.com>
2025-05-20 13:29:27 +01:00
Han Verstraete (OpenFaaS Ltd)
0defc22a3f Rename missed has_yum reference to has_dnf
Signed-off-by: Han Verstraete (OpenFaaS Ltd) <han@openfaas.com>
2025-05-20 13:29:27 +01:00
Han Verstraete (OpenFaaS Ltd)
c14d92c5c2 Use full faasd binary path in instructions on RHEL
On RHEL systems the installation path of faasd, /usr/local/bin, is not
in the sudo PATH by default. Use the full path to the faasd binary in
any printed instruction to work around this.

Signed-off-by: Han Verstraete (OpenFaaS Ltd) <han@openfaas.com>
2025-05-14 12:43:33 +01:00
Han Verstraete (OpenFaaS Ltd)
934d326d82 Fix OpenFaaS Edge install script for RHEL-based systems
This change removes the check-update command. This command is not
required and caused the script to exit early if packages are not up to
date.

In addition DNF is now used to install packages. DNF is the successor of
YUM on the latest RHEL-based systems.

Tested on Rocky Linux 8 and 9.

Signed-off-by: Han Verstraete (OpenFaaS Ltd) <han@openfaas.com>
2025-05-14 12:43:33 +01:00
Alex Ellis (OpenFaaS Ltd)
0ea1bd5ffc Invert order of instructions for edge
Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
2025-04-24 16:09:18 +01:00
Alex Ellis (OpenFaaS Ltd)
7f798267b0 Add note on docs
Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
2025-04-24 16:07:57 +01:00
Alex Ellis (OpenFaaS Ltd)
a2254ca1ff Security fix - containerd to 1.7.27
Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
2025-03-18 10:25:34 +00:00
Alex Ellis (OpenFaaS Ltd)
087a299f4c Add service logs command to faasd ce from faasd-pro
A more limited version is added, for continuity.

Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
2025-03-18 10:23:22 +00:00
dependabot[bot]
6dcdab832d Bump golang.org/x/net from 0.24.0 to 0.36.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.24.0 to 0.36.0.
- [Commits](https://github.com/golang/net/compare/v0.24.0...v0.36.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-13 08:36:45 +00:00
Alex Ellis (OpenFaaS Ltd)
57163e27cf Revised README
Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
2025-02-21 10:38:19 +00:00
Alex Ellis (OpenFaaS Ltd)
cced8eb3df OpenFaaS CE EULA is for personal use and limited commercial trial
Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
2025-02-21 09:32:31 +00:00
Alex Ellis (OpenFaaS Ltd)
0d4bfa938c Add script to patch DigitalOcean for journal
Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
2025-02-19 11:26:02 +00:00
Alex Ellis (OpenFaaS Ltd)
120a34cfef Update post-installation message on container downloads
Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
2025-02-19 11:16:06 +00:00
Alex Ellis (OpenFaaS Ltd)
ae4d0a97f8 Add directive back into install-edge.sh
Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
2025-02-19 11:12:03 +00:00
Alex Ellis (OpenFaaS Ltd)
ef68994a5c Install script - suppress interactive messages
Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
2025-02-19 11:09:36 +00:00
Alex Ellis (OpenFaaS Ltd)
43e51c51bb Show instructions for manual license keys
Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
2025-02-19 11:08:19 +00:00
Alex Ellis (OpenFaaS Ltd)
695d80076c Suppress question about autosave for iptables
Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
2025-02-19 11:03:00 +00:00
Alex Ellis (OpenFaaS Ltd)
51f3f87ba1 Add iptables-persistent for openfaas-edge on Debian-like OSes
Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
2025-02-19 11:01:38 +00:00
Alex Ellis (OpenFaaS Ltd)
e2758be25e Fix file permission
Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
2025-02-18 21:17:07 +00:00
Alex Ellis (OpenFaaS Ltd)
7ad5c17e7c Clarify usage in a Small Business Environment
Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
2025-02-17 17:25:17 +00:00
Alex Ellis
983dacb15c
Create config.yml
Signed-off-by: Alex Ellis <alexellis2@gmail.com>
2025-01-30 10:50:30 +00:00
Alex Ellis
96abaaf102
Create issue.md
Signed-off-by: Alex Ellis <alexellis2@gmail.com>
2025-01-30 10:37:32 +00:00
Alex Ellis (OpenFaaS Ltd)
d7e0bebe25 Fix for proxy exiting early
When a proxied core service was accessed before it was ready
to accept a connection, due to a start-up, restart, etc of
a core service, then the proxy exited instead of continuing
to accept new connections.

This meant having to restart faasd and hope the race condition
worked itself out, or that no incoming requests were made.

Tested with Grafana, which seemed to manifest the issue
the most.

Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
2025-01-30 10:00:14 +00:00
Alex Ellis (OpenFaaS Ltd)
ef689d7b62 Fix for update workflow
When terminating a function and replacing it during an update,
there was often an error about task precondition not met
which meant having to try and or wait or being left in an
inconsistent state.

The new flow makes sure "Wait" is called in either code path
and allows for a custom gap between the SIGTERM and SIGKILL
through the grace_period env var - set as a Go duration.

Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
2025-01-21 17:20:30 +00:00
Alex Ellis (OpenFaaS Ltd)
854ec5836d Remove unused context
Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
2025-01-21 16:03:17 +00:00
Alex Ellis (OpenFaaS Ltd)
4ab5f60b9d Reduce logging from log streaming command
Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
2025-01-21 12:58:00 +00:00
Alex Ellis (OpenFaaS Ltd)
a8b61f2086 Upgrade various core components
Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
2025-01-21 12:54:54 +00:00
Alex Ellis (OpenFaaS Ltd)
68335e2016 Update images for Go 1.23
Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
2024-12-13 08:22:44 +00:00
Alex Ellis (OpenFaaS Ltd)
404af1c4d9 Fix #363 with format for max memory
Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
2024-11-22 08:47:07 +00:00
Alex Ellis (OpenFaaS Ltd)
055e57ec5f Clarify EULA for CE components
Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
2024-11-21 16:39:57 +00:00
Alex Ellis (OpenFaaS Ltd)
6bb1222ebb Switch to newest gateway version and Prometheus v3
Fixes: #371

Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
2024-11-21 16:37:56 +00:00
Alex Ellis (OpenFaaS Ltd)
599ae5415f Force BINLOCATION to arkade install
Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
2024-09-25 11:18:56 +01:00
Alex Ellis (OpenFaaS Ltd)
0d74cac072 Kill existing services before installing faasd edge
Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
2024-09-25 10:22:45 +01:00
Alex Ellis (OpenFaaS Ltd)
c2b802cbf9 Stop edge installer on error
Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
2024-09-25 10:15:32 +01:00
Alex Ellis (OpenFaaS Ltd)
bd0e1d7718 Update support for Oracle Linux for edge installer
Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
2024-09-25 10:15:00 +01:00
Alex Ellis (OpenFaaS Ltd)
bfc87ff432 Ensure which is available for ym
Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
2024-09-25 09:48:48 +01:00
Alex Ellis (OpenFaaS Ltd)
032716e3e9 Update OpenFaaS Edge metrics
Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
2024-09-24 15:34:26 +01:00
Alex Ellis (OpenFaaS Ltd)
c813b0810b Notes in install-edge script
Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
2024-09-23 14:51:49 +01:00
Alex Ellis (OpenFaaS Ltd)
fb36d2e5aa Update notes on OpenFaaS edge
Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
2024-09-23 14:17:49 +01:00
Alex Ellis (OpenFaaS Ltd)
038eb91191 Update script URL for edge
Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
2024-09-23 14:11:45 +01:00
Alex Ellis (OpenFaaS Ltd)
5576382d96 Install OS package via faasd-pro script
These packages need to be sourced by other means when
installing into an airgap, and you can set SKIP_OS=1 to avoid
using the Internet.

Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
2024-09-23 09:34:41 +01:00
Alex Ellis (OpenFaaS Ltd)
7ca2621c98 Add notes about other OS packages for faasd-pro
Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
2024-09-20 09:42:36 +01:00
Alex Ellis (OpenFaaS Ltd)
a154fd1bc0 Add Pro to README
Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
2024-09-18 16:36:45 +01:00
Alex Ellis (OpenFaaS Ltd)
6b1e49a2a5 Ensure scaling up from zero works in faasd CE
Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
2024-09-18 16:33:20 +01:00
Alex Ellis (OpenFaaS Ltd)
5344a32472 Ensure scaling up from zero works in faasd CE
Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
2024-09-18 15:45:13 +01:00
Alex Ellis (OpenFaaS Ltd)
e59e3f0cb6 Add pro installer for sponsors
Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
2024-09-18 15:42:38 +01:00
Alex Ellis (OpenFaaS Ltd)
2adc1350d4 Fix import
Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
2024-09-17 15:34:45 +01:00
Alex Ellis (OpenFaaS Ltd)
5b633cc017 Remove newlines from log lines, which are not required
Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
2024-09-17 11:18:07 +01:00
Alex Ellis (OpenFaaS Ltd)
1c1bfa6759 Upgrades to containerd, fix deprecations upstream
* Fixes upstream deprecations for containerd
* Fixes deprecations in ioutil package usage
* Break out separate files for function handlers
* Upgrades containerd to 1.7.22
* Fixes default namespace functionality
* Pre-deploy checks as per license agreement
* Removes extra log messages for payload in HTTP handlers, you
can enable FAAS_DEBUG=1 in the CLI instead to see this from
the client's perspective
* Add additional Google DNS server 8.8.4.4 for functions

Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
2024-09-17 11:13:53 +01:00
Alex Ellis (OpenFaaS Ltd)
93f41ca35d Clarify coverage of OpenFaaS CE EULA
faasd has always been covered by the OpenFaaS CE EULA, the
presence of the document in the faas repo does not mean it
only applies to a single repository.

faasd is OpenFaaS, they are not different products.

OpenFaaS CE requires a commercial license for use as has been
explained on the website and in the docs.

https://www.openfaas.com/pricing
https://docs.openfaas.com/openfaas-pro/introduction/#comparison

This EULA Addendum permits explit personal usage and small
business environments to commercial usage of faasd only, with
OpenFaaS CE, but does not cover OpenFaaS CE deployed to
Kubernetes or K3s, or OpenShift.

For questions or comments, reach out to contact@openfaas.com

Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
2024-09-17 08:37:39 +01:00
dependabot[bot]
0172c996b8 Bump github.com/opencontainers/runc from 1.1.12 to 1.1.14
Bumps [github.com/opencontainers/runc](https://github.com/opencontainers/runc) from 1.1.12 to 1.1.14.
- [Release notes](https://github.com/opencontainers/runc/releases)
- [Changelog](https://github.com/opencontainers/runc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/opencontainers/runc/compare/v1.1.12...v1.1.14)

---
updated-dependencies:
- dependency-name: github.com/opencontainers/runc
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-09 15:31:40 +01:00
Alex Ellis (OpenFaaS Ltd)
4162db43ff Fix check for arch in verify_system
Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
2024-06-12 10:54:18 +01:00
Alex Ellis (OpenFaaS Ltd)
e4848cd829 Remove armhf/armv7 support from faasd
See notes in: #364

Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
2024-06-12 10:19:41 +01:00
Alex Ellis (OpenFaaS Ltd)
7dbaeef3d8 Return error from proxy
Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
2024-06-12 10:02:05 +01:00
Alex Ellis (OpenFaaS Ltd)
887c18befa Close connection if unable to dial upstream
Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
2024-06-12 10:02:05 +01:00
dependabot[bot]
f6167e72a9 Bump golang.org/x/net from 0.22.0 to 0.23.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.22.0 to 0.23.0.
- [Commits](https://github.com/golang/net/compare/v0.22.0...v0.23.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-23 10:35:50 +01:00
Alex Ellis (OpenFaaS Ltd)
c12505a63f Update intro, and build with Go 1.22
Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
2024-03-27 09:09:12 +00:00
Alex Ellis (OpenFaaS Ltd)
ffac4063b6 Updates for go.mod
Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
2024-03-20 09:41:37 +01:00
wangqiang
dd31784824 Fix snapshot key error
When obtaining the container information fails, the key for deleting the snapshot is incorrect.

Signed-off-by: wangqiang <shivaqiang@qq.com>
2024-03-20 09:40:17 +01:00
dependabot[bot]
70b0929cf2 Bump google.golang.org/protobuf from 1.31.0 to 1.33.0
Bumps google.golang.org/protobuf from 1.31.0 to 1.33.0.

---
updated-dependencies:
- dependency-name: google.golang.org/protobuf
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-14 14:50:22 +00:00
869 changed files with 50482 additions and 32768 deletions

1
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@ -0,0 +1 @@
blank_issues_enabled: false

69
.github/ISSUE_TEMPLATE/issue.md vendored Normal file
View File

@ -0,0 +1,69 @@
---
name: Report an issue
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
## Due diligence
<!-- Due dilligence -->
## My actions before raising this issue
Before you ask for help or support, make sure that you've [consulted the manual for faasd](https://openfaas.gumroad.com/l/serverless-for-everyone-else). We can't answer questions that are already covered by the manual.
<!-- How is this affecting you? What task are you trying to accomplish? -->
## Why do you need this?
<!-- Attempts to mask or hide this may result in the issue being closed -->
## Who is this for?
What company is this for? Are you listed in the [ADOPTERS.md](https://github.com/openfaas/faas/blob/master/ADOPTERS.md) file?
<!--- Provide a general summary of the issue in the Title above -->
## Expected Behaviour
<!--- If you're describing a bug, tell us what should happen -->
<!--- If you're suggesting a change/improvement, tell us how it should work -->
## Current Behaviour
<!--- If describing a bug, tell us what happens instead of the expected behavior -->
<!--- If suggesting a change/improvement, explain the difference from current behavior -->
## List All Possible Solutions and Workarounds
<!--- Suggest a fix/reason for the bug, or ideas how to implement -->
<!--- the addition or change -->
<!--- Is there a workaround which could avoid making changes? -->
## Which Solution Do You Recommend?
<!--- Pick your preferred solution, if you were to implement and maintain this change -->
## Steps to Reproduce (for bugs)
<!--- Provide a link to a live example, or an unambiguous set of steps to -->
<!--- reproduce this bug. Include code to reproduce, if relevant -->
1.
2.
3.
4.
## Your Environment
* OS and architecture:
* Versions:
```sh
go version
containerd -version
uname -a
cat /etc/os-release
faasd version
```

View File

@ -16,9 +16,9 @@ jobs:
with: with:
fetch-depth: 1 fetch-depth: 1
- name: Install Go - name: Install Go
uses: actions/setup-go@v2 uses: actions/setup-go@v5
with: with:
go-version: 1.21.x go-version: 1.22.x
- name: test - name: test
run: make test run: make test

View File

@ -13,13 +13,13 @@ jobs:
with: with:
fetch-depth: 1 fetch-depth: 1
- name: Install Go - name: Install Go
uses: actions/setup-go@v2 uses: actions/setup-go@v5
with: with:
go-version: 1.21.x go-version: 1.22.x
- name: Make publish - name: Make publish
run: make publish run: make publish
- name: Upload release binaries - name: Upload release binaries
uses: alexellis/upload-assets@0.4.0 uses: alexellis/upload-assets@0.4.1
env: env:
GITHUB_TOKEN: ${{ github.token }} GITHUB_TOKEN: ${{ github.token }}
with: with:

View File

@ -11,7 +11,7 @@ jobs:
steps: steps:
- uses: actions/checkout@master - uses: actions/checkout@master
- uses: alexellis/setup-arkade@v2 - uses: alexellis/setup-arkade@v3
- name: Verify chart images - name: Verify chart images
id: verify_images id: verify_images
run: | run: |

22
EULA.md Normal file
View File

@ -0,0 +1,22 @@
1.1 EULA Addendum for faasd Community Edition (CE). This EULA Addendum for faasd is part of the [OpenFaaS Community Edition (CE) EULA](https://github.com/openfaas/faas/blob/master/EULA.md).
1.2 Agreement Parties. This Agreement is between OpenFaaS Ltd (the "Licensor") and you (the "Licensee").
1.3 Governing Law. This Agreement shall be governed by, and construed in accordance with, the laws of England and Wales.
1.4 OpenFaaS Edge (faasd-pro). OpenFaaS Edge (faasd-pro) is a separate commercial product that is fully licensed under the OpenFaaS Pro EULA.
2.1 Grant of License for faasd CE. faasd CE may be installed once per year for a single 60-day trial period in a commercial setting for the sole purpose of evaluation and testing. This trial does not include any support or warranty, and it terminates automatically at the end of the 60-day period unless a separate commercial license is obtained.
2.2 Personal (Non-Commercial) Use. faasd CE may be used by an individual for personal, non-commercial projects, provided that the user is not acting on behalf of any company, corporation, or other legal entity.
2.3 Restrictions.
(a) No redistribution, resale, or sublicensing of faasd CE is permitted.
(b) The License granted under this Addendum is non-transferable.
(c) Any continued commercial usage beyond the 60-day trial requires a separate commercial license from the Licensor.
2.4 Warranty Disclaimer. faasd CE is provided "as is," without warranty of any kind. No support or guarantee is included during the 60-day trial or for personal use.
2.5 Termination. If the terms of this Addendum are violated, the License granted hereunder terminates immediately. The Licensee must discontinue all use of faasd CE and destroy any copies in their possession.
2.6 Contact Information. For additional rights, commercial licenses, or support inquiries, please contact the Licensor at contact@openfaas.com.

View File

@ -1,8 +1,10 @@
License for faasd contributions from OpenFaaS Ltd - 2017, 2029-2024, see: EULA.md
Only third-party contributions to source code are licensed MIT:
MIT License MIT License
Copyright (c) 2020 Alex Ellis
Copyright (c) 2020 OpenFaaS Ltd Copyright (c) 2020 OpenFaaS Ltd
Copyright (c) 2020 OpenFaas Author(s)
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View File

@ -1,7 +1,7 @@
Version := $(shell git describe --tags --dirty) Version := $(shell git describe --tags --dirty)
GitCommit := $(shell git rev-parse HEAD) GitCommit := $(shell git rev-parse HEAD)
LDFLAGS := "-s -w -X main.Version=$(Version) -X main.GitCommit=$(GitCommit)" LDFLAGS := "-s -w -X github.com/openfaas/faasd/pkg.Version=$(Version) -X github.com/openfaas/faasd/pkg.GitCommit=$(GitCommit)"
CONTAINERD_VER := 1.7.0 CONTAINERD_VER := 1.7.27
CNI_VERSION := v0.9.1 CNI_VERSION := v0.9.1
ARCH := amd64 ARCH := amd64
@ -27,7 +27,6 @@ dist-local:
.PHONY: dist .PHONY: dist
dist: dist:
CGO_ENABLED=0 GOOS=linux go build -mod=vendor -ldflags $(LDFLAGS) -o bin/faasd CGO_ENABLED=0 GOOS=linux go build -mod=vendor -ldflags $(LDFLAGS) -o bin/faasd
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=7 go build -mod=vendor -ldflags $(LDFLAGS) -o bin/faasd-armhf
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -mod=vendor -ldflags $(LDFLAGS) -o bin/faasd-arm64 CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -mod=vendor -ldflags $(LDFLAGS) -o bin/faasd-arm64
.PHONY: hashgen .PHONY: hashgen

152
README.md
View File

@ -1,17 +1,38 @@
# faasd - a lightweight & portable faas engine # faasd - a lightweight and portable version of OpenFaaS
[![Sponsor faasd](https://img.shields.io/static/v1?label=Sponsor&message=%E2%9D%A4&logo=GitHub&link=https://github.com/sponsors/openfaas)](https://github.com/sponsors/openfaas)
[![Build Status](https://github.com/openfaas/faasd/workflows/build/badge.svg?branch=master)](https://github.com/openfaas/faasd/actions)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
![Downloads](https://img.shields.io/github/downloads/openfaas/faasd/total)
faasd is [OpenFaaS](https://github.com/openfaas/) reimagined, but without the cost and complexity of Kubernetes. It runs on a single host with very modest requirements, making it fast and easy to manage. Under the hood it uses [containerd](https://containerd.io/) and [Container Networking Interface (CNI)](https://github.com/containernetworking/cni) along with the same core OpenFaaS components from the main project. faasd is [OpenFaaS](https://github.com/openfaas/) reimagined, but without the cost and complexity of Kubernetes. It runs on a single host with very modest requirements, making it fast and easy to manage. Under the hood it uses [containerd](https://containerd.io/) and [Container Networking Interface (CNI)](https://github.com/containernetworking/cni) along with the same core OpenFaaS components from the main project.
![faasd logo](docs/media/social.png) ![faasd logo](docs/media/social.png)
## Use-cases and tutorials ## Features & Benefits
faasd is just another way to run OpenFaaS, so many things you read in the docs or in blog posts will work the same way. - **Lightweight** - faasd is a single Go binary, which runs as a systemd service making it easy to manage
- **Portable** - it runs on any Linux host with containerd and CNI, on as little as 2x vCPU and 2GB RAM - x86_64 and Arm64 supported
- **Easy to manage** - unlike Kubernetes, its API is stable and requires little maintenance
- **Low cost** - it's licensed per installation, so you can invoke your functions as much as you need, without additional cost
- **Stateful containers** - faasd supports stateful containers with persistent volumes such as PostgreSQL, Grafana, Prometheus, etc
- **Built on OpenFaaS** - uses the same containers that power OpenFaaS on Kubernetes for the Gateway, Queue-Worker, Event Connectors, Dashboards, Scale To Zero, etc
- **Ideal for internal business use** - use it to build internal tools, automate tasks, and integrate with existing systems
- **Deploy it for a customer** - package your functions along with OpenFaaS Edge into a VM image, and deploy it to your customers to run in their own datacenters
faasd does not create the same maintenance burden you'll find with installing, upgrading, and securing a Kubernetes cluster. You can deploy it and walk away, in the worst case, just deploy a new VM and deploy your functions again.
You can learn more about supported OpenFaaS features in the [ROADMAP.md](/docs/ROADMAP.md)
## Getting Started
There are two versions of faasd:
* faasd CE - for non-commercial, personal use only licensed under [the faasd CE EULA](/EULA.md)
* OpenFaaS Edge (faasd-pro) - fully licensed for commercial use
You can install either edition using the instructions in the [OpenFaaS docs](https://docs.openfaas.com/deployment/edge/).
You can request a license for [OpenFaaS Edge using this form](https://forms.gle/g6oKLTG29mDTSk5k9)
## Further resources
There are many blog posts and documentation pages about OpenFaaS on Kubernetes, which also apply to faasd.
Videos and overviews: Videos and overviews:
@ -29,65 +50,32 @@ Use-cases and tutorials:
Additional resources: Additional resources:
* The official handbook - [Serverless For Everyone Else](https://gumroad.com/l/serverless-for-everyone-else) * The official handbook - [Serverless For Everyone Else](https://openfaas.gumroad.com/l/serverless-for-everyone-else)
* For reference: [OpenFaaS docs](https://docs.openfaas.com) * For reference: [OpenFaaS docs](https://docs.openfaas.com)
* For use-cases and tutorials: [OpenFaaS blog](https://openfaas.com/blog/) * For use-cases and tutorials: [OpenFaaS blog](https://openfaas.com/blog/)
* For self-paced learning: [OpenFaaS workshop](https://github.com/openfaas/workshop/) * For self-paced learning: [OpenFaaS workshop](https://github.com/openfaas/workshop/)
### About faasd ### Deployment tutorials
* faasd is a static Golang binary * [Use multipass on Windows, MacOS or Linux](/docs/MULTIPASS.md)
* uses the same core components and ecosystem of OpenFaaS * [Deploy to DigitalOcean with Terraform and TLS](https://www.openfaas.com/blog/faasd-tls-terraform/)
* uses containerd for its runtime and CNI for networking * [Deploy to any IaaS with cloud-init](https://blog.alexellis.io/deploy-serverless-faasd-with-cloud-init/)
* is multi-arch, so works on Intel `x86_64` and ARM out the box * [Deploy faasd to your Raspberry Pi](https://blog.alexellis.io/faasd-for-lightweight-serverless/)
* can run almost any other stateful container through its `docker-compose.yaml` file
Most importantly, it's easy to manage so you can set it up and leave it alone to run your functions. Terraform scripts:
[![demo](https://pbs.twimg.com/media/EPNQz00W4AEwDxM?format=jpg&name=medium)](https://www.youtube.com/watch?v=WX1tZoSXy8E) * [Provision faasd on DigitalOcean with Terraform](docs/bootstrap/README.md)
* [Provision faasd with TLS on DigitalOcean with Terraform](docs/bootstrap/digitalocean-terraform/README.md)
> Demo of faasd running asynchronous functions
Watch the video: [faasd walk-through with cloud-init and Multipass](https://www.youtube.com/watch?v=WX1tZoSXy8E) ### Training / Handbook
### What does faasd deploy? You can find various resources to learn about faasd for free, however the official handbook is the most comprehensive guide to getting started with faasd and OpenFaaS.
* faasd - itself, and its [faas-provider](https://github.com/openfaas/faas-provider) for containerd - CRUD for functions and services, implements the OpenFaaS REST API ["Serverless For Everyone Else"](https://openfaas.gumroad.com/l/serverless-for-everyone-else) is the official handbook and was written to contribute funds towards the upkeep and maintenance of the project.
* [Prometheus](https://github.com/prometheus/prometheus) - for monitoring of services, metrics, scaling and dashboards
* [OpenFaaS Gateway](https://github.com/openfaas/faas/tree/master/gateway) - the UI portal, CLI, and other OpenFaaS tooling can talk to this.
* [OpenFaaS queue-worker for NATS](https://github.com/openfaas/nats-queue-worker) - run your invocations in the background without adding any code. See also: [asynchronous invocations](https://docs.openfaas.com/reference/triggers/#async-nats-streaming)
* [NATS](https://nats.io) for asynchronous processing and queues
faasd relies on industry-standard tools for running containers:
* [CNI](https://github.com/containernetworking/plugins) <a href="https://openfaas.gumroad.com/l/serverless-for-everyone-else">
* [containerd](https://github.com/containerd/containerd)
* [runc](https://github.com/opencontainers/runc)
You can use the standard [faas-cli](https://github.com/openfaas/faas-cli) along with pre-packaged functions from *the Function Store*, or build your own using any OpenFaaS template.
### When should you use faasd over OpenFaaS on Kubernetes?
* To deploy microservices and functions that you can update and monitor remotely
* When you don't have the bandwidth to learn or manage Kubernetes
* To deploy embedded apps in IoT and edge use-cases
* To distribute applications to a customer or client
* You have a cost sensitive project - run faasd on a 1GB VM for 5-10 USD / mo or on your Raspberry Pi
* When you just need a few functions or microservices, without the cost of a cluster
faasd does not create the same maintenance burden you'll find with maintaining, upgrading, and securing a Kubernetes cluster. You can deploy it and walk away, in the worst case, just deploy a new VM and deploy your functions again.
You can learn more about supported OpenFaaS features in the [ROADMAP.md](/docs/ROADMAP.md)
## Learning faasd
The faasd project is MIT licensed and open source, and you will find some documentation, blog posts and videos for free.
However, "Serverless For Everyone Else" is the official handbook and was written to contribute funds towards the upkeep and maintenance of the project.
### The official handbook and docs for faasd
<a href="https://gumroad.com/l/serverless-for-everyone-else">
<img src="https://www.alexellis.io/serverless.png" width="40%"></a> <img src="https://www.alexellis.io/serverless.png" width="40%"></a>
You'll learn how to deploy code in any language, lift and shift Dockerfiles, run requests in queues, write background jobs and to integrate with databases. faasd packages the same code as OpenFaaS, so you get built-in metrics for your HTTP endpoints, a user-friendly CLI, pre-packaged functions and templates from the store and a UI. You'll learn how to deploy code in any language, lift and shift Dockerfiles, run requests in queues, write background jobs and to integrate with databases. faasd packages the same code as OpenFaaS, so you get built-in metrics for your HTTP endpoints, a user-friendly CLI, pre-packaged functions and templates from the store and a UI.
@ -114,58 +102,4 @@ Topics include:
View sample pages, reviews and testimonials on Gumroad: View sample pages, reviews and testimonials on Gumroad:
["Serverless For Everyone Else"](https://gumroad.com/l/serverless-for-everyone-else) ["Serverless For Everyone Else"](https://openfaas.gumroad.com/l/serverless-for-everyone-else)
### Deploy faasd
The easiest way to deploy faasd is with cloud-init, we give several examples below, and post IaaS platforms will accept "user-data" pasted into their UI, or via their API.
For trying it out on MacOS or Windows, we recommend using [multipass](https://multipass.run) to run faasd in a VM.
If you don't use cloud-init, or have already created your Linux server you can use the installation script as per below:
```bash
git clone https://github.com/openfaas/faasd --depth=1
cd faasd
./hack/install.sh
```
> This approach also works for Raspberry Pi
It's recommended that you do not install Docker on the same host as faasd, since 1) they may both use different versions of containerd and 2) docker's networking rules can disrupt faasd's networking. When using faasd - make your faasd server a faasd server, and build container image on your laptop or in a CI pipeline.
#### Deployment tutorials
* [Use multipass on Windows, MacOS or Linux](/docs/MULTIPASS.md)
* [Deploy to DigitalOcean with Terraform and TLS](https://www.openfaas.com/blog/faasd-tls-terraform/)
* [Deploy to any IaaS with cloud-init](https://blog.alexellis.io/deploy-serverless-faasd-with-cloud-init/)
* [Deploy faasd to your Raspberry Pi](https://blog.alexellis.io/faasd-for-lightweight-serverless/)
Terraform scripts:
* [Provision faasd on DigitalOcean with Terraform](docs/bootstrap/README.md)
* [Provision faasd with TLS on DigitalOcean with Terraform](docs/bootstrap/digitalocean-terraform/README.md)
### Function and template store
For community functions see `faas-cli store --help`
For templates built by the community see: `faas-cli template store list`, you can also use the `dockerfile` template if you just want to migrate an existing service without the benefits of using a template.
### Community support
Commercial users and solo business owners should become OpenFaaS GitHub Sponsors to receive regular email updates on changes, tutorials and new features.
If you are learning faasd, or want to share your use-case, you can join the OpenFaaS Slack community.
* [Become an OpenFaaS GitHub Sponsor](https://github.com/sponsors/openfaas/)
* [Join the weekly Office Hours call](https://docs.openfaas.com/community/)
### Backlog, features, design limitations and any known issues
For open backlog items, shipped features, design limitations and any known issues, see [ROADMAP.md](docs/ROADMAP.md)
Want to build a patch without setting up a complete development environment? See [docs/PATCHES.md](docs/PATCHES.md)
Are you looking to hack on faasd? Follow the [developer instructions](docs/DEV.md) for a manual installation, or use the `hack/install.sh` script and pick up from there.

View File

@ -50,55 +50,53 @@ func runInstall(_ *cobra.Command, _ []string) error {
return err return err
} }
err := binExists("/usr/local/bin/", "faasd") if err := binExists("/usr/local/bin/", "faasd"); err != nil {
if err != nil {
return err return err
} }
err = systemd.InstallUnit("faasd-provider", map[string]string{ if err := systemd.InstallUnit("faasd-provider", map[string]string{
"Cwd": faasdProviderWd, "Cwd": faasdProviderWd,
"SecretMountPath": path.Join(faasdwd, "secrets")}) "SecretMountPath": path.Join(faasdwd, "secrets")}); err != nil {
if err != nil {
return err return err
} }
err = systemd.InstallUnit("faasd", map[string]string{"Cwd": faasdwd}) if err := systemd.InstallUnit("faasd", map[string]string{"Cwd": faasdwd}); err != nil {
if err != nil {
return err return err
} }
err = systemd.DaemonReload() if err := systemd.DaemonReload(); err != nil {
if err != nil {
return err return err
} }
err = systemd.Enable("faasd-provider") if err := systemd.Enable("faasd-provider"); err != nil {
if err != nil {
return err return err
} }
err = systemd.Enable("faasd") if err := systemd.Enable("faasd"); err != nil {
if err != nil {
return err return err
} }
err = systemd.Start("faasd-provider") if err := systemd.Start("faasd-provider"); err != nil {
if err != nil {
return err return err
} }
err = systemd.Start("faasd") if err := systemd.Start("faasd"); err != nil {
if err != nil {
return err return err
} }
fmt.Println(`Check status with: fmt.Println(`
The initial setup downloads various container images, which may take a
minute or two depending on your connection.
Check the status of the faasd service with:
sudo journalctl -u faasd --lines 100 -f sudo journalctl -u faasd --lines 100 -f
Login with: Login with:
sudo -E cat /var/lib/faasd/secrets/basic-auth-password | faas-cli login -s`) sudo -E cat /var/lib/faasd/secrets/basic-auth-password | faas-cli login -s`)
fmt.Println("")
return nil return nil
} }

View File

@ -3,7 +3,6 @@ package cmd
import ( import (
"fmt" "fmt"
"io" "io"
"io/ioutil"
"log" "log"
"net/http" "net/http"
"os" "os"
@ -30,25 +29,14 @@ func makeProviderCmd() *cobra.Command {
Short: "Run the faasd-provider", Short: "Run the faasd-provider",
} }
command.Flags().String("pull-policy", "Always", `Set to "Always" to force a pull of images upon deployment, or "IfNotPresent" to try to use a cached image.`)
command.RunE = runProviderE command.RunE = runProviderE
command.PreRunE = preRunE
return command return command
} }
func runProviderE(cmd *cobra.Command, _ []string) error { func runProviderE(cmd *cobra.Command, _ []string) error {
pullPolicy, flagErr := cmd.Flags().GetString("pull-policy")
if flagErr != nil {
return flagErr
}
alwaysPull := false
if pullPolicy == "Always" {
alwaysPull = true
}
config, providerConfig, err := config.ReadFromEnv(types.OsEnv{}) config, providerConfig, err := config.ReadFromEnv(types.OsEnv{})
if err != nil { if err != nil {
return err return err
@ -62,18 +50,15 @@ func runProviderE(cmd *cobra.Command, _ []string) error {
return err return err
} }
writeHostsErr := ioutil.WriteFile(path.Join(wd, "hosts"), if err := os.WriteFile(path.Join(wd, "hosts"),
[]byte(`127.0.0.1 localhost`), workingDirectoryPermission) []byte(`127.0.0.1 localhost`), workingDirectoryPermission); err != nil {
return fmt.Errorf("cannot write hosts file: %s", err)
if writeHostsErr != nil {
return fmt.Errorf("cannot write hosts file: %s", writeHostsErr)
} }
writeResolvErr := ioutil.WriteFile(path.Join(wd, "resolv.conf"), if err := os.WriteFile(path.Join(wd, "resolv.conf"),
[]byte(`nameserver 8.8.8.8`), workingDirectoryPermission) []byte(`nameserver 8.8.8.8
nameserver 8.8.4.4`), workingDirectoryPermission); err != nil {
if writeResolvErr != nil { return fmt.Errorf("cannot write resolv.conf file: %s", err)
return fmt.Errorf("cannot write resolv.conf file: %s", writeResolvErr)
} }
cni, err := cninetwork.InitNetwork() cni, err := cninetwork.InitNetwork()
@ -97,26 +82,26 @@ func runProviderE(cmd *cobra.Command, _ []string) error {
return err return err
} }
alwaysPull := true
bootstrapHandlers := types.FaaSHandlers{ bootstrapHandlers := types.FaaSHandlers{
FunctionProxy: proxy.NewHandlerFunc(*config, invokeResolver, false), FunctionProxy: httpHeaderMiddleware(proxy.NewHandlerFunc(*config, invokeResolver, false)),
DeleteFunction: handlers.MakeDeleteHandler(client, cni), DeleteFunction: httpHeaderMiddleware(handlers.MakeDeleteHandler(client, cni)),
DeployFunction: handlers.MakeDeployHandler(client, cni, baseUserSecretsPath, alwaysPull), DeployFunction: httpHeaderMiddleware(handlers.MakeDeployHandler(client, cni, baseUserSecretsPath, alwaysPull)),
FunctionLister: handlers.MakeReadHandler(client), FunctionLister: httpHeaderMiddleware(handlers.MakeReadHandler(client)),
FunctionStatus: handlers.MakeReplicaReaderHandler(client), FunctionStatus: httpHeaderMiddleware(handlers.MakeReplicaReaderHandler(client)),
ScaleFunction: handlers.MakeReplicaUpdateHandler(client, cni), ScaleFunction: httpHeaderMiddleware(handlers.MakeReplicaUpdateHandler(client, cni)),
UpdateFunction: handlers.MakeUpdateHandler(client, cni, baseUserSecretsPath, alwaysPull), UpdateFunction: httpHeaderMiddleware(handlers.MakeUpdateHandler(client, cni, baseUserSecretsPath, alwaysPull)),
Health: func(w http.ResponseWriter, r *http.Request) {}, Health: httpHeaderMiddleware(func(w http.ResponseWriter, r *http.Request) {}),
Info: handlers.MakeInfoHandler(Version, GitCommit), Info: httpHeaderMiddleware(handlers.MakeInfoHandler(faasd.Version, faasd.GitCommit)),
ListNamespaces: handlers.MakeNamespacesLister(client), ListNamespaces: httpHeaderMiddleware(handlers.MakeNamespacesLister(client)),
Secrets: handlers.MakeSecretHandler(client.NamespaceService(), baseUserSecretsPath), Secrets: httpHeaderMiddleware(handlers.MakeSecretHandler(client.NamespaceService(), baseUserSecretsPath)),
Logs: logs.NewLogHandlerFunc(faasdlogs.New(), config.ReadTimeout), Logs: httpHeaderMiddleware(logs.NewLogHandlerFunc(faasdlogs.New(), config.ReadTimeout)),
MutateNamespace: handlers.MakeMutateNamespace(client), MutateNamespace: httpHeaderMiddleware(handlers.MakeMutateNamespace(client)),
} }
log.Printf("Listening on: 0.0.0.0:%d\n", *config.TCPPort) log.Printf("Listening on: 0.0.0.0:%d", *config.TCPPort)
bootstrap.Serve(cmd.Context(), &bootstrapHandlers, config) bootstrap.Serve(cmd.Context(), &bootstrapHandlers, config)
return nil return nil
} }
/* /*
@ -131,7 +116,7 @@ func moveSecretsToDefaultNamespaceSecrets(baseSecretPath string, defaultNamespac
return err return err
} }
files, err := ioutil.ReadDir(baseSecretPath) files, err := os.ReadDir(baseSecretPath)
if err != nil { if err != nil {
return err return err
} }
@ -178,3 +163,10 @@ func copyFile(src, dst string) error {
return nil return nil
} }
func httpHeaderMiddleware(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("X-OpenFaaS-EULA", "openfaas-ce")
next.ServeHTTP(w, r)
}
}

View File

@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"github.com/morikuni/aec" "github.com/morikuni/aec"
"github.com/openfaas/faasd/pkg"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -16,25 +17,15 @@ func init() {
rootCommand.AddCommand(installCmd) rootCommand.AddCommand(installCmd)
rootCommand.AddCommand(makeProviderCmd()) rootCommand.AddCommand(makeProviderCmd())
rootCommand.AddCommand(collectCmd) rootCommand.AddCommand(collectCmd)
rootCommand.AddCommand(makeServiceCmd())
} }
func RootCommand() *cobra.Command { func RootCommand() *cobra.Command {
return rootCommand return rootCommand
} }
var (
// GitCommit Git Commit SHA
GitCommit string
// Version version of the CLI
Version string
)
// Execute faasd // Execute faasd
func Execute(version, gitCommit string) error { func Execute() error {
// Get Version and GitCommit values from main.go.
Version = version
GitCommit = gitCommit
if err := rootCommand.Execute(); err != nil { if err := rootCommand.Execute(); err != nil {
return err return err
@ -46,12 +37,16 @@ var rootCommand = &cobra.Command{
Use: "faasd", Use: "faasd",
Short: "Start faasd", Short: "Start faasd",
Long: ` Long: `
faasd - Serverless For Everyone Else faasd Community Edition (CE):
Learn how to build, secure, and monitor functions with faasd with Learn how to build, secure, and monitor functions with faasd with
the eBook: the eBook:
https://gumroad.com/l/serverless-for-everyone-else https://openfaas.gumroad.com/l/serverless-for-everyone-else
License: OpenFaaS CE EULA with faasd addendum:
https://github.com/openfaas/faasd/blob/master/EULA.md
`, `,
RunE: runRootCommand, RunE: runRootCommand,
SilenceUsage: true, SilenceUsage: true,
@ -78,7 +73,7 @@ func parseBaseCommand(_ *cobra.Command, _ []string) {
} }
func printVersion() { func printVersion() {
fmt.Printf("faasd version: %s\tcommit: %s\n", GetVersion(), GitCommit) fmt.Printf("faasd Community Edition (CE) version: %s\tcommit: %s\n", pkg.GetVersion(), pkg.GitCommit)
} }
func printLogo() { func printLogo() {
@ -86,14 +81,6 @@ func printLogo() {
fmt.Println(logoText) fmt.Println(logoText)
} }
// GetVersion get latest version
func GetVersion() string {
if len(Version) == 0 {
return "dev"
}
return Version
}
// Logo for version and root command // Logo for version and root command
const Logo = ` __ _ const Logo = ` __ _
/ _| __ _ __ _ ___ __| | / _| __ _ __ _ ___ __| |

22
cmd/service.go Normal file
View File

@ -0,0 +1,22 @@
package cmd
import "github.com/spf13/cobra"
func makeServiceCmd() *cobra.Command {
var command = &cobra.Command{
Use: "service",
Short: "Manage services",
Long: `Manage services created by faasd from the docker-compose.yml file`,
}
command.RunE = runServiceE
command.AddCommand(makeServiceLogsCmd())
return command
}
func runServiceE(cmd *cobra.Command, args []string) error {
return cmd.Help()
}

89
cmd/service_logs.go Normal file
View File

@ -0,0 +1,89 @@
package cmd
import (
"context"
"errors"
"fmt"
"os"
"time"
goexecute "github.com/alexellis/go-execute/v2"
"github.com/spf13/cobra"
)
func makeServiceLogsCmd() *cobra.Command {
var command = &cobra.Command{
Use: "logs",
Short: "View logs for a service",
Long: `View logs for a service created by faasd from the docker-compose.yml file.`,
Example: ` ## View logs for the gateway for the last hour
faasd service logs gateway --since 1h
## View logs for the cron-connector, and tail them
faasd service logs cron-connector -f
`,
}
command.Flags().Duration("since", 10*time.Minute, "How far back in time to include logs")
command.Flags().BoolP("follow", "f", false, "Follow the logs")
command.RunE = runServiceLogsE
command.PreRunE = preRunServiceLogsE
return command
}
func runServiceLogsE(cmd *cobra.Command, args []string) error {
name := args[0]
namespace, _ := cmd.Flags().GetString("namespace")
follow, _ := cmd.Flags().GetBool("follow")
since, _ := cmd.Flags().GetDuration("since")
journalTask := goexecute.ExecTask{
Command: "journalctl",
Args: []string{"-o", "cat", "-t", fmt.Sprintf("%s:%s", namespace, name)},
StreamStdio: true,
}
if follow {
journalTask.Args = append(journalTask.Args, "-f")
}
if since != 0 {
// Calculate the timestamp that is 'age' duration ago
sinceTime := time.Now().Add(-since)
// Format according to journalctl's expected format: "2012-10-30 18:17:16"
formattedTime := sinceTime.Format("2006-01-02 15:04:05")
journalTask.Args = append(journalTask.Args, fmt.Sprintf("--since=%s", formattedTime))
}
res, err := journalTask.Execute(context.Background())
if err != nil {
return err
}
if res.ExitCode != 0 {
return fmt.Errorf("failed to get logs for service %s: %s", name, res.Stderr)
}
return nil
}
func preRunServiceLogsE(cmd *cobra.Command, args []string) error {
if os.Geteuid() != 0 {
return errors.New("this command must be run as root")
}
if len(args) == 0 {
return errors.New("service name is required as an argument")
}
namespace, _ := cmd.Flags().GetString("namespace")
if namespace == "" {
return errors.New("namespace is required")
}
return nil
}

View File

@ -2,7 +2,6 @@ package cmd
import ( import (
"fmt" "fmt"
"io/ioutil"
"log" "log"
"os" "os"
"os/signal" "os/signal"
@ -42,6 +41,7 @@ var upCmd = &cobra.Command{
Use: "up", Use: "up",
Short: "Start faasd", Short: "Start faasd",
RunE: runUp, RunE: runUp,
PreRunE: preRunE,
} }
func runUp(cmd *cobra.Command, _ []string) error { func runUp(cmd *cobra.Command, _ []string) error {
@ -166,7 +166,7 @@ func makeFile(filePath, fileContents string) error {
return nil return nil
} else if os.IsNotExist(err) { } else if os.IsNotExist(err) {
log.Printf("Writing to: %q\n", filePath) log.Printf("Writing to: %q\n", filePath)
return ioutil.WriteFile(filePath, []byte(fileContents), workingDirectoryPermission) return os.WriteFile(filePath, []byte(fileContents), workingDirectoryPermission)
} else { } else {
return err return err
} }
@ -204,3 +204,11 @@ func parseUpFlags(cmd *cobra.Command) (upConfig, error) {
parsed.workingDir = faasdwd parsed.workingDir = faasdwd
return parsed, err return parsed, err
} }
func preRunE(cmd *cobra.Command, _ []string) error {
if err := pkg.ConnectivityCheck(); err != nil {
return fmt.Errorf("the OpenFaaS CE EULA requires Internet access, upgrade to faasd Pro to continue")
}
return nil
}

View File

@ -21,7 +21,7 @@ services:
# - "127.0.0.1:8222:8222" # - "127.0.0.1:8222:8222"
prometheus: prometheus:
image: docker.io/prom/prometheus:v2.49.1 image: docker.io/prom/prometheus:v3.1.0
# nobody # nobody
user: "65534" user: "65534"
volumes: volumes:
@ -39,7 +39,7 @@ services:
- "127.0.0.1:9090:9090" - "127.0.0.1:9090:9090"
gateway: gateway:
image: ghcr.io/openfaas/gateway:0.27.5 image: ghcr.io/openfaas/gateway:0.27.12
environment: environment:
- basic_auth=true - basic_auth=true
- functions_provider_url=http://faasd-provider:8081/ - functions_provider_url=http://faasd-provider:8081/
@ -69,7 +69,7 @@ services:
- "8080:8080" - "8080:8080"
queue-worker: queue-worker:
image: ghcr.io/openfaas/queue-worker:0.14.1 image: ghcr.io/openfaas/queue-worker:0.14.2
environment: environment:
- faas_nats_address=nats - faas_nats_address=nats
- faas_nats_port=4222 - faas_nats_port=4222

View File

@ -57,7 +57,6 @@ curl -sLS https://cli.openfaas.com | sudo sh
#### Install the CNI plugins: #### Install the CNI plugins:
* For PC run `export ARCH=amd64` * For PC run `export ARCH=amd64`
* For RPi/armhf run `export ARCH=arm`
* For arm64 run `export ARCH=arm64` * For arm64 run `export ARCH=arm64`
Then run: Then run:
@ -83,30 +82,17 @@ EOF'
### Get containerd ### Get containerd
You have three options - binaries for PC, binaries for armhf, or build from source.
* Install containerd `x86_64` only * Install containerd `x86_64` only
```bash ```bash
export VER=1.7.0 export VER=1.7.27
curl -sSL https://github.com/containerd/containerd/releases/download/v$VER/containerd-$VER-linux-amd64.tar.gz -o /tmp/containerd.tar.gz \ curl -sSL https://github.com/containerd/containerd/releases/download/v$VER/containerd-$VER-linux-amd64.tar.gz -o /tmp/containerd.tar.gz \
&& sudo tar -xvf /tmp/containerd.tar.gz -C /usr/local/bin/ --strip-components=1 && sudo tar -xvf /tmp/containerd.tar.gz -C /usr/local/bin/ --strip-components=1
containerd -version containerd -version
``` ```
* Or get my containerd binaries for Raspberry Pi (armhf)
Building `containerd` on armhf is extremely slow, so I've provided binaries for you.
```bash
export VER=1.7.0
curl -sSL https://github.com/alexellis/containerd-armhf/releases/download/v$VER/containerd-$VER-linux-armhf.tar.gz
| sudo tar -xvz --strip-components=2 -C /usr/local/bin/
```
* Or clone / build / install [containerd](https://github.com/containerd/containerd) from source: * Or clone / build / install [containerd](https://github.com/containerd/containerd) from source:
```bash ```bash
@ -116,7 +102,7 @@ containerd -version
git clone https://github.com/containerd/containerd git clone https://github.com/containerd/containerd
cd containerd cd containerd
git fetch origin --tags git fetch origin --tags
git checkout v1.7.0 git checkout v1.7.27
make make
sudo make install sudo make install
@ -127,7 +113,7 @@ containerd -version
#### Ensure containerd is running #### Ensure containerd is running
```bash ```bash
curl -sLS https://raw.githubusercontent.com/containerd/containerd/v1.7.0/containerd.service > /tmp/containerd.service curl -sLS https://raw.githubusercontent.com/containerd/containerd/v1.7.27/containerd.service > /tmp/containerd.service
# Extend the timeouts for low-performance VMs # Extend the timeouts for low-performance VMs
echo "[Manager]" | tee -a /tmp/containerd.service echo "[Manager]" | tee -a /tmp/containerd.service
@ -234,9 +220,6 @@ sudo cp bin/faasd /usr/local/bin
# For x86_64 # For x86_64
export SUFFIX="" export SUFFIX=""
# armhf
export SUFFIX="-armhf"
# arm64 # arm64
export SUFFIX="-arm64" export SUFFIX="-arm64"

View File

@ -84,5 +84,5 @@ See the testing instructions on the PR and run through those steps.
Post your results on GitHub to assist the creator of the pull request. Post your results on GitHub to assist the creator of the pull request.
You can see how to get the logs for various components using the [eBook Serverless For Everyone Else](https://gumroad.com/l/serverless-for-everyone-else), or by consulting the [DEV.md](/docs/DEV.md) guide. You can see how to get the logs for various components using the [eBook Serverless For Everyone Else](https://openfaas.gumroad.com/l/serverless-for-everyone-else), or by consulting the [DEV.md](/docs/DEV.md) guide.

View File

@ -1,12 +1,12 @@
# faasd backlog and features # faasd backlog and features
It's important to understand the vision for faasd vs OpenFaaS CE/Pro. It's important to understand the vision and tradeoffs between OpenFaaS Edge (faasd-pro) vs. OpenFaaS on Kubernetes.
faasd is a single-node implementation of OpenFaaS. faasd is a single-node implementation of OpenFaaS.
It is supposed to be a lightweight, low-overhead, way to deploy OpenFaaS functions for functions which do not need planet-scale. It is supposed to be a lightweight, low-overhead, way to deploy OpenFaaS functions for functions which do not need to scale out.
It is not supposed to have multiple replicas, clustering, HA, or auto-scaling. It is not supposed to have multiple replicas, clustering, High Availability (HA), or auto-scaling.
[Learn when to use faasd](https://docs.openfaas.com/deployment/) [Learn when to use faasd](https://docs.openfaas.com/deployment/)
@ -43,12 +43,6 @@ It can scale vertically, and this may be a suitable alternative for many use-cas
Workaround: deploy multiple, dynamically named functions `scraper-1`, `scraper-2`, `scraper-3` and set up a reverse proxy rule to load balance i.e. `scraper.example.com => [/function/scraper-1, /function/scraper-2, /function/scraper-3]`. Workaround: deploy multiple, dynamically named functions `scraper-1`, `scraper-2`, `scraper-3` and set up a reverse proxy rule to load balance i.e. `scraper.example.com => [/function/scraper-1, /function/scraper-2, /function/scraper-3]`.
### Scale from zero may give a non-200
faasd itself does not implement a health check to determine if a function is ready for traffic. Since faasd doesn't support auto-scaling, this is unlikely to affect you.
Workaround: Have your client retry HTTP calls, or don't scale to zero.
### Leaf-node only - no clustering ### Leaf-node only - no clustering
faasd is operates on a leaf-node/single-node model. If this is an issue for you, but you have resource constraints, you will need to use [OpenFaaS CE or Pro on Kubernetes](https://docs.openfaas.com/deployment/). faasd is operates on a leaf-node/single-node model. If this is an issue for you, but you have resource constraints, you will need to use [OpenFaaS CE or Pro on Kubernetes](https://docs.openfaas.com/deployment/).
@ -77,7 +71,7 @@ There is a very detailed chapter on troubleshooting in the eBook [Serverless For
### Your function timed-out at 60 seconds ### Your function timed-out at 60 seconds
This is no longer an issue, see the manual for how to configure a longer timeout, updated 3rd October 2022. See the manual for how to configure a longer timeouts.
### Non 200 HTTP status from the gateway upon reboot ### Non 200 HTTP status from the gateway upon reboot
@ -135,7 +129,7 @@ Won't have:
* [x] Self-install / create systemd service via `faasd install` * [x] Self-install / create systemd service via `faasd install`
* [x] Restart containers upon restart of faasd * [x] Restart containers upon restart of faasd
* [x] Clear / remove containers and tasks with SIGTERM / SIGINT * [x] Clear / remove containers and tasks with SIGTERM / SIGINT
* [x] Determine armhf/arm64 containers to run for gateway * [x] Determine arm64 containers to run for gateway
* [x] Configure `basic_auth` to protect the OpenFaaS gateway and faasd-provider HTTP API * [x] Configure `basic_auth` to protect the OpenFaaS gateway and faasd-provider HTTP API
* [x] Setup custom working directory for faasd `/var/lib/faasd/` * [x] Setup custom working directory for faasd `/var/lib/faasd/`
* [x] Use CNI to create network namespaces and adapters * [x] Use CNI to create network namespaces and adapters
@ -148,4 +142,6 @@ Won't have:
* [x] [Store and retrieve annotations in function spec](https://github.com/openfaas/faasd/pull/86) - in progress * [x] [Store and retrieve annotations in function spec](https://github.com/openfaas/faasd/pull/86) - in progress
* [x] An installer for faasd and dependencies - runc, containerd * [x] An installer for faasd and dependencies - runc, containerd
* [x] Offer a recommendation or implement a strategy for faasd replication/HA * [x] Offer a recommendation or implement a strategy for faasd replication/HA
* [x] [Remove / deprecate armhf / armv7 support](https://github.com/openfaas/faasd/issues/364)
* [x] Add support for CPU/RAM metrics in the UI, CLI and API
* [x] Network segmentation (functions cannot talk to each other or the host)

78
go.mod
View File

@ -1,15 +1,16 @@
module github.com/openfaas/faasd module github.com/openfaas/faasd
go 1.21 go 1.23.0
toolchain go1.23.7
require ( require (
github.com/alexellis/arkade v0.0.0-20240124171646-67314ef9f9c3 github.com/alexellis/arkade v0.0.0-20240320084407-6cf4a641c415
github.com/compose-spec/compose-go v0.0.0-20200528042322-36d8ce368e05 github.com/compose-spec/compose-go v0.0.0-20200528042322-36d8ce368e05
github.com/containerd/containerd v1.7.0 github.com/containerd/containerd v1.7.27
github.com/containerd/go-cni v1.1.9 github.com/containerd/go-cni v1.1.9
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf
github.com/docker/cli v24.0.7+incompatible github.com/docker/cli v24.0.7+incompatible
github.com/docker/distribution v2.8.3+incompatible
github.com/docker/docker v24.0.7+incompatible // indirect github.com/docker/docker v24.0.7+incompatible // indirect
github.com/docker/go-units v0.5.0 github.com/docker/go-units v0.5.0
github.com/gorilla/mux v1.8.1 github.com/gorilla/mux v1.8.1
@ -22,71 +23,78 @@ require (
github.com/spf13/pflag v1.0.5 github.com/spf13/pflag v1.0.5
github.com/vishvananda/netlink v1.2.1-beta.2 github.com/vishvananda/netlink v1.2.1-beta.2
github.com/vishvananda/netns v0.0.4 github.com/vishvananda/netns v0.0.4
golang.org/x/sys v0.16.0 golang.org/x/sys v0.31.0
k8s.io/apimachinery v0.29.1 k8s.io/apimachinery v0.29.3
) )
require github.com/alexellis/go-execute/v2 v2.2.1 require (
github.com/alexellis/go-execute/v2 v2.2.1
github.com/distribution/reference v0.6.0
)
require ( require (
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230106234847-43070de90fa1 // indirect github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 // indirect
github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20230306123547-8075edf89bb0 // indirect github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20230306123547-8075edf89bb0 // indirect
github.com/Microsoft/go-winio v0.6.1 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/Microsoft/hcsshim v0.10.0-rc.7 // indirect github.com/Microsoft/hcsshim v0.11.7 // indirect
github.com/beorn7/perks v1.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/containerd/cgroups v1.1.0 // indirect github.com/containerd/cgroups v1.1.0 // indirect
github.com/containerd/continuity v0.3.0 // indirect github.com/containerd/containerd/api v1.8.0 // indirect
github.com/containerd/continuity v0.4.4 // indirect
github.com/containerd/errdefs v0.3.0 // indirect
github.com/containerd/fifo v1.1.0 // indirect github.com/containerd/fifo v1.1.0 // indirect
github.com/containerd/ttrpc v1.2.1 // indirect github.com/containerd/log v0.1.0 // indirect
github.com/containerd/typeurl/v2 v2.1.0 // indirect github.com/containerd/platforms v0.2.1 // indirect
github.com/containerd/ttrpc v1.2.7 // indirect
github.com/containerd/typeurl/v2 v2.1.1 // indirect
github.com/containernetworking/cni v1.1.2 // indirect github.com/containernetworking/cni v1.1.2 // indirect
github.com/cyphar/filepath-securejoin v0.2.4 // indirect
github.com/distribution/reference v0.5.0 // indirect
github.com/docker/docker-credential-helpers v0.8.0 // indirect github.com/docker/docker-credential-helpers v0.8.0 // indirect
github.com/docker/go-connections v0.4.0 // indirect github.com/docker/go-connections v0.4.0 // indirect
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c // indirect github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c // indirect
github.com/go-logr/logr v1.3.0 // indirect github.com/felixge/httpsnoop v1.0.3 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect
github.com/gogo/protobuf v1.3.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.3 // indirect github.com/golang/protobuf v1.5.4 // indirect
github.com/google/go-cmp v0.6.0 // indirect github.com/google/go-cmp v0.6.0 // indirect
github.com/google/uuid v1.3.0 // indirect github.com/google/uuid v1.4.0 // indirect
github.com/imdario/mergo v0.3.14 // indirect github.com/imdario/mergo v0.3.14 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/klauspost/compress v1.17.4 // indirect github.com/klauspost/compress v1.17.4 // indirect
github.com/kr/text v0.2.0 // indirect github.com/kr/text v0.2.0 // indirect
github.com/mattn/go-shellwords v1.0.12 // indirect github.com/mattn/go-shellwords v1.0.12 // indirect
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/moby/locker v1.0.1 // indirect github.com/moby/locker v1.0.1 // indirect
github.com/moby/sys/mountinfo v0.6.2 // indirect github.com/moby/sys/mountinfo v0.6.2 // indirect
github.com/moby/sys/sequential v0.5.0 // indirect github.com/moby/sys/sequential v0.5.0 // indirect
github.com/moby/sys/signal v0.7.0 // indirect github.com/moby/sys/signal v0.7.0 // indirect
github.com/moby/sys/user v0.3.0 // indirect
github.com/moby/sys/userns v0.1.0 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.0-rc5 // indirect github.com/opencontainers/image-spec v1.1.0 // indirect
github.com/opencontainers/runc v1.1.12 // indirect
github.com/opencontainers/selinux v1.11.0 // indirect github.com/opencontainers/selinux v1.11.0 // indirect
github.com/prometheus/client_golang v1.18.0 // indirect github.com/prometheus/client_golang v1.19.0 // indirect
github.com/prometheus/client_model v0.5.0 // indirect github.com/prometheus/client_model v0.6.0 // indirect
github.com/prometheus/common v0.45.0 // indirect github.com/prometheus/common v0.51.1 // indirect
github.com/prometheus/procfs v0.12.0 // indirect github.com/prometheus/procfs v0.13.0 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect github.com/sirupsen/logrus v1.9.3 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/xeipuuv/gojsonschema v1.2.0 // indirect github.com/xeipuuv/gojsonschema v1.2.0 // indirect
go.opencensus.io v0.24.0 // indirect go.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/otel v1.14.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 // indirect
go.opentelemetry.io/otel/trace v1.14.0 // indirect go.opentelemetry.io/otel v1.21.0 // indirect
golang.org/x/mod v0.14.0 // indirect go.opentelemetry.io/otel/metric v1.21.0 // indirect
golang.org/x/net v0.20.0 // indirect go.opentelemetry.io/otel/trace v1.21.0 // indirect
golang.org/x/sync v0.6.0 // indirect golang.org/x/net v0.38.0 // indirect
golang.org/x/text v0.14.0 // indirect golang.org/x/sync v0.12.0 // indirect
golang.org/x/tools v0.17.0 // indirect golang.org/x/text v0.23.0 // indirect
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect google.golang.org/genproto v0.0.0-20231211222908-989df2bf70f3 // indirect
google.golang.org/grpc v1.56.3 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda // indirect
google.golang.org/protobuf v1.31.0 // indirect google.golang.org/grpc v1.59.0 // indirect
google.golang.org/protobuf v1.35.2 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect
gotest.tools/v3 v3.0.3 // indirect gotest.tools/v3 v3.0.3 // indirect

152
go.sum
View File

@ -1,15 +1,15 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230106234847-43070de90fa1 h1:EKPd1INOIyr5hWOWhvpmQpY6tKjeG0hT1s3AMC/9fic= github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU=
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230106234847-43070de90fa1/go.mod h1:VzwV+t+dZ9j/H867F1M2ziD+yLHtB46oM35FxxMJ4d0= github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20230306123547-8075edf89bb0 h1:59MxjQVfjXsBpLy+dbd2/ELV5ofnUkUZBvWSC85sheA= github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20230306123547-8075edf89bb0 h1:59MxjQVfjXsBpLy+dbd2/ELV5ofnUkUZBvWSC85sheA=
github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20230306123547-8075edf89bb0/go.mod h1:OahwfttHWG6eJ0clwcfBAHoDI6X/LV/15hx/wlMZSrU= github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20230306123547-8075edf89bb0/go.mod h1:OahwfttHWG6eJ0clwcfBAHoDI6X/LV/15hx/wlMZSrU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
github.com/Microsoft/hcsshim v0.10.0-rc.7 h1:HBytQPxcv8Oy4244zbQbe6hnOnx544eL5QPUqhJldz8= github.com/Microsoft/hcsshim v0.11.7 h1:vl/nj3Bar/CvJSYo7gIQPyRWc9f3c6IeSNavBTSZNZQ=
github.com/Microsoft/hcsshim v0.10.0-rc.7/go.mod h1:ILuwjA+kNW+MrN/w5un7n3mTqkwsFu4Bp05/okFUZlE= github.com/Microsoft/hcsshim v0.11.7/go.mod h1:MV8xMfmECjl5HdO7U/3/hFVnkmSBjAjmA09d4bExKcU=
github.com/alexellis/arkade v0.0.0-20240124171646-67314ef9f9c3 h1:JoyZaLGeoRWsJIeyP9y1ayFs+uxZwtpLf0XRC8fcWOM= github.com/alexellis/arkade v0.0.0-20240320084407-6cf4a641c415 h1:mLD1eSfXbmXcwKMP1AsFl01G2U16aC9E22Tcjehyyrw=
github.com/alexellis/arkade v0.0.0-20240124171646-67314ef9f9c3/go.mod h1:Uqijd3uJORh9Q9MxCeER7IynU8kuXkCTnkLvFwr3XNE= github.com/alexellis/arkade v0.0.0-20240320084407-6cf4a641c415/go.mod h1:3sT9Gq9WUFG9Wwz9dFbRRc/2L3yepsA4p272aG2DR6w=
github.com/alexellis/go-execute/v2 v2.2.1 h1:4Ye3jiCKQarstODOEmqDSRCqxMHLkC92Bhse743RdOI= github.com/alexellis/go-execute/v2 v2.2.1 h1:4Ye3jiCKQarstODOEmqDSRCqxMHLkC92Bhse743RdOI=
github.com/alexellis/go-execute/v2 v2.2.1/go.mod h1:FMdRnUTiFAmYXcv23txrp3VYZfLo24nMpiIneWgKHTQ= github.com/alexellis/go-execute/v2 v2.2.1/go.mod h1:FMdRnUTiFAmYXcv23txrp3VYZfLo24nMpiIneWgKHTQ=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
@ -26,35 +26,39 @@ github.com/compose-spec/compose-go v0.0.0-20200528042322-36d8ce368e05 h1:3CoRXfl
github.com/compose-spec/compose-go v0.0.0-20200528042322-36d8ce368e05/go.mod h1:y75QUr1jcR5aFNf3Tj3dhwnujABGz6UaRrZ5qZwF1cc= github.com/compose-spec/compose-go v0.0.0-20200528042322-36d8ce368e05/go.mod h1:y75QUr1jcR5aFNf3Tj3dhwnujABGz6UaRrZ5qZwF1cc=
github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM= github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM=
github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw= github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw=
github.com/containerd/containerd v1.7.0 h1:G/ZQr3gMZs6ZT0qPUZ15znx5QSdQdASW11nXTLTM2Pg= github.com/containerd/containerd v1.7.27 h1:yFyEyojddO3MIGVER2xJLWoCIn+Up4GaHFquP7hsFII=
github.com/containerd/containerd v1.7.0/go.mod h1:QfR7Efgb/6X2BDpTPJRvPTYDE9rsF0FsXX9J8sIs/sc= github.com/containerd/containerd v1.7.27/go.mod h1:xZmPnl75Vc+BLGt4MIfu6bp+fy03gdHAn9bz+FreFR0=
github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg= github.com/containerd/containerd/api v1.8.0 h1:hVTNJKR8fMc/2Tiw60ZRijntNMd1U+JVMyTRdsD2bS0=
github.com/containerd/continuity v0.3.0/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM= github.com/containerd/containerd/api v1.8.0/go.mod h1:dFv4lt6S20wTu/hMcP4350RL87qPWLVa/OHOwmmdnYc=
github.com/containerd/continuity v0.4.4 h1:/fNVfTJ7wIl/YPMHjf+5H32uFhl63JucB34PlCpMKII=
github.com/containerd/continuity v0.4.4/go.mod h1:/lNJvtJKUQStBzpVQ1+rasXO1LAWtUQssk28EZvJ3nE=
github.com/containerd/errdefs v0.3.0 h1:FSZgGOeK4yuT/+DnF07/Olde/q4KBoMsaamhXxIMDp4=
github.com/containerd/errdefs v0.3.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M=
github.com/containerd/fifo v1.1.0 h1:4I2mbh5stb1u6ycIABlBw9zgtlK8viPI9QkQNRQEEmY= github.com/containerd/fifo v1.1.0 h1:4I2mbh5stb1u6ycIABlBw9zgtlK8viPI9QkQNRQEEmY=
github.com/containerd/fifo v1.1.0/go.mod h1:bmC4NWMbXlt2EZ0Hc7Fx7QzTFxgPID13eH0Qu+MAb2o= github.com/containerd/fifo v1.1.0/go.mod h1:bmC4NWMbXlt2EZ0Hc7Fx7QzTFxgPID13eH0Qu+MAb2o=
github.com/containerd/go-cni v1.1.9 h1:ORi7P1dYzCwVM6XPN4n3CbkuOx/NZ2DOqy+SHRdo9rU= github.com/containerd/go-cni v1.1.9 h1:ORi7P1dYzCwVM6XPN4n3CbkuOx/NZ2DOqy+SHRdo9rU=
github.com/containerd/go-cni v1.1.9/go.mod h1:XYrZJ1d5W6E2VOvjffL3IZq0Dz6bsVlERHbekNK90PM= github.com/containerd/go-cni v1.1.9/go.mod h1:XYrZJ1d5W6E2VOvjffL3IZq0Dz6bsVlERHbekNK90PM=
github.com/containerd/ttrpc v1.2.1 h1:VWv/Rzx023TBLv4WQ+9WPXlBG/s3rsRjY3i9AJ2BJdE= github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
github.com/containerd/ttrpc v1.2.1/go.mod h1:sIT6l32Ph/H9cvnJsfXM5drIVzTr5A2flTf1G5tYZak= github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
github.com/containerd/typeurl/v2 v2.1.0 h1:yNAhJvbNEANt7ck48IlEGOxP7YAp6LLpGn5jZACDNIE= github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A=
github.com/containerd/typeurl/v2 v2.1.0/go.mod h1:IDp2JFvbwZ31H8dQbEIY7sDl2L3o3HZj1hsSQlywkQ0= github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw=
github.com/containerd/ttrpc v1.2.7 h1:qIrroQvuOL9HQ1X6KHe2ohc7p+HP/0VE6XPU7elJRqQ=
github.com/containerd/ttrpc v1.2.7/go.mod h1:YCXHsb32f+Sq5/72xHubdiJRQY9inL4a4ZQrAbN1q9o=
github.com/containerd/typeurl/v2 v2.1.1 h1:3Q4Pt7i8nYwy2KmQWIw2+1hTvwTE/6w9FqcttATPO/4=
github.com/containerd/typeurl/v2 v2.1.1/go.mod h1:IDp2JFvbwZ31H8dQbEIY7sDl2L3o3HZj1hsSQlywkQ0=
github.com/containernetworking/cni v1.1.2 h1:wtRGZVv7olUHMOqouPpn3cXJWpJgM6+EUl31EQbXALQ= github.com/containernetworking/cni v1.1.2 h1:wtRGZVv7olUHMOqouPpn3cXJWpJgM6+EUl31EQbXALQ=
github.com/containernetworking/cni v1.1.2/go.mod h1:sDpYKmGVENF3s6uvMvGgldDWeG8dMxakj/u+i9ht9vw= github.com/containernetworking/cni v1.1.2/go.mod h1:sDpYKmGVENF3s6uvMvGgldDWeG8dMxakj/u+i9ht9vw=
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf h1:iW4rZ826su+pqaw19uhpSCzhj44qo35pNgKFGqzDKkU= github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf h1:iW4rZ826su+pqaw19uhpSCzhj44qo35pNgKFGqzDKkU=
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg=
github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0= github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
github.com/docker/cli v24.0.7+incompatible h1:wa/nIwYFW7BVTGa7SWPVyyXU9lgORqUb1xfI36MSkFg= github.com/docker/cli v24.0.7+incompatible h1:wa/nIwYFW7BVTGa7SWPVyyXU9lgORqUb1xfI36MSkFg=
github.com/docker/cli v24.0.7+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/cli v24.0.7+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v24.0.7+incompatible h1:Wo6l37AuwP3JaMnZa226lzVXGA3F9Ig1seQen0cKYlM= github.com/docker/docker v24.0.7+incompatible h1:Wo6l37AuwP3JaMnZa226lzVXGA3F9Ig1seQen0cKYlM=
github.com/docker/docker v24.0.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v24.0.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker-credential-helpers v0.8.0 h1:YQFtbBQb4VrpoPxhFuzEBPQ9E16qz5SpHLS+uswaCp8= github.com/docker/docker-credential-helpers v0.8.0 h1:YQFtbBQb4VrpoPxhFuzEBPQ9E16qz5SpHLS+uswaCp8=
@ -70,11 +74,13 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk=
github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
@ -89,7 +95,6 @@ github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4er
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
@ -100,8 +105,8 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
@ -109,7 +114,6 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
@ -119,8 +123,8 @@ github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLe
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec=
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
@ -142,8 +146,6 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/mattn/go-shellwords v1.0.10/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= github.com/mattn/go-shellwords v1.0.10/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
github.com/mattn/go-shellwords v1.0.12 h1:M2zGm7EW6UQJvDeQxo4T51eKPurbeFbe8WtebGE2xrk= github.com/mattn/go-shellwords v1.0.12 h1:M2zGm7EW6UQJvDeQxo4T51eKPurbeFbe8WtebGE2xrk=
github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg=
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k=
github.com/mitchellh/mapstructure v1.3.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.3.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
@ -155,6 +157,10 @@ github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5
github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo= github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo=
github.com/moby/sys/signal v0.7.0 h1:25RW3d5TnQEoKvRbEKUGay6DCQ46IxAVTT9CUMgmsSI= github.com/moby/sys/signal v0.7.0 h1:25RW3d5TnQEoKvRbEKUGay6DCQ46IxAVTT9CUMgmsSI=
github.com/moby/sys/signal v0.7.0/go.mod h1:GQ6ObYZfqacOwTtlXvcmh9A26dVRul/hbOZn88Kg8Tg= github.com/moby/sys/signal v0.7.0/go.mod h1:GQ6ObYZfqacOwTtlXvcmh9A26dVRul/hbOZn88Kg8Tg=
github.com/moby/sys/user v0.3.0 h1:9ni5DlcW5an3SvRSx4MouotOygvzaXbaSrc/wGDFWPo=
github.com/moby/sys/user v0.3.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs=
github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g=
github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28=
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
@ -173,10 +179,8 @@ github.com/onsi/gomega v1.29.0 h1:KIA/t2t5UBzoirT4H9tsML45GEbo3ouUnBHsCfD2tVg=
github.com/onsi/gomega v1.29.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= github.com/onsi/gomega v1.29.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.1.0-rc5 h1:Ygwkfw9bpDvs+c9E34SdgGOj41dX/cbdlwvlWt0pnFI= github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
github.com/opencontainers/image-spec v1.1.0-rc5/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8= github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
github.com/opencontainers/runc v1.1.12 h1:BOIssBaW1La0/qbNZHXOOa71dZfZEQOzW7dqQf3phss=
github.com/opencontainers/runc v1.1.12/go.mod h1:S+lQwSfncpBha7XTy/5lBwWgm5+y5Ma/O44Ekby9FK8=
github.com/opencontainers/runtime-spec v1.1.0 h1:HHUyrt9mwHUjtasSbXSMvs4cyFxh+Bll4AjJ9odEGpg= github.com/opencontainers/runtime-spec v1.1.0 h1:HHUyrt9mwHUjtasSbXSMvs4cyFxh+Bll4AjJ9odEGpg=
github.com/opencontainers/runtime-spec v1.1.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v1.1.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/selinux v1.11.0 h1:+5Zbo97w3Lbmb3PeqQtpmTkMwsW5nRI3YaLpt7tQ7oU= github.com/opencontainers/selinux v1.11.0 h1:+5Zbo97w3Lbmb3PeqQtpmTkMwsW5nRI3YaLpt7tQ7oU=
@ -188,23 +192,21 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU=
github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= github.com/prometheus/client_model v0.6.0 h1:k1v3CzpSRUTrKMppY35TLwPvxHqBu0bYgxZzqGIgaos=
github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= github.com/prometheus/client_model v0.6.0/go.mod h1:NTQHnmxFpouOD0DpvP4XujX3CdOAGQPoaGhyTchlyt8=
github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM= github.com/prometheus/common v0.51.1 h1:eIjN50Bwglz6a/c3hAgSMcofL3nD+nFQkV6Dd4DsQCw=
github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY= github.com/prometheus/common v0.51.1/go.mod h1:lrWtQx+iDfn2mbH5GUzlH9TSHyfZpHkSiG1W7y3sF2Q=
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.13.0 h1:GqzLlQyfsPbaEHaQkO7tbDlriv/4o5Hudv6OXHGKX7o=
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= github.com/prometheus/procfs v0.13.0/go.mod h1:cd4PFCR54QLnGKPaKGA6l+cfuNXtht43ZKY6tow0Y1g=
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sethvargo/go-password v0.2.0 h1:BTDl4CC/gjf/axHMaDQtw507ogrXLci6XRiLc7i/UHI= github.com/sethvargo/go-password v0.2.0 h1:BTDl4CC/gjf/axHMaDQtw507ogrXLci6XRiLc7i/UHI=
github.com/sethvargo/go-password v0.2.0/go.mod h1:Ym4Mr9JXLBycr02MFuVQ/0JHidNetSgbzutTr3zsYXE= github.com/sethvargo/go-password v0.2.0/go.mod h1:Ym4Mr9JXLBycr02MFuVQ/0JHidNetSgbzutTr3zsYXE=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
@ -241,10 +243,14 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
go.opentelemetry.io/otel v1.14.0 h1:/79Huy8wbf5DnIPhemGB+zEPVwnN6fuQybr/SRXa6hM= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 h1:x8Z78aZx8cOF0+Kkazoc7lwUNMGy0LrzEMxTm4BbTxg=
go.opentelemetry.io/otel v1.14.0/go.mod h1:o4buv+dJzx8rohcUeRmWUZhqupFvzWis188WlggnNeU= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0/go.mod h1:62CPTSry9QZtOaSsE3tOzhx6LzDhHnXJ6xHeMNNiM6Q=
go.opentelemetry.io/otel/trace v1.14.0 h1:wp2Mmvj41tDsyAJXiWDWpfNsOiIyd38fy85pyKcFq/M= go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc=
go.opentelemetry.io/otel/trace v1.14.0/go.mod h1:8avnQLK+CG77yNLUae4ea2JDQ6iT+gozhnZjy/rw9G8= go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo=
go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4=
go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM=
go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc=
go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ=
go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A=
go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
@ -256,8 +262,6 @@ golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvx
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -270,17 +274,16 @@ golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -288,7 +291,6 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -297,20 +299,18 @@ golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
@ -321,8 +321,8 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@ -331,18 +331,18 @@ google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9Ywl
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A= google.golang.org/genproto v0.0.0-20231211222908-989df2bf70f3 h1:1hfbdAfFbkmpg41000wDVqr7jUpK/Yo+LPnIxxGzmkg=
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= google.golang.org/genproto v0.0.0-20231211222908-989df2bf70f3/go.mod h1:5RBcpGRxr25RbDzY5w+dmaqpSEvl8Gwl1x2CICf60ic=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda h1:LI5DOvAxUPMv/50agcLLoo+AdWc1irS9Rzz4vPuD1V4=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/grpc v1.56.3 h1:8I4C0Yq1EjstUzUJzpcRVbuYA2mODtEmpWiQoN/b2nc= google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk=
google.golang.org/grpc v1.56.3/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@ -355,8 +355,8 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io=
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
@ -377,5 +377,5 @@ gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0=
gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
k8s.io/apimachinery v0.29.1 h1:KY4/E6km/wLBguvCZv8cKTeOwwOBqFNjwJIdMkMbbRc= k8s.io/apimachinery v0.29.3 h1:2tbx+5L7RNvqJjn7RIuIKu9XTsIZ9Z5wX2G22XAa5EU=
k8s.io/apimachinery v0.29.1/go.mod h1:6HVkd1FwxIagpYrHSwJlQqZI3G9LfYWRPAkUvLnXTKU= k8s.io/apimachinery v0.29.3/go.mod h1:hx/S4V2PNW4OMg3WizRrHutyB5la0iCUbZym+W0EQIU=

View File

@ -6,12 +6,8 @@
export ARCH="arm64" export ARCH="arm64"
if [ ! -d "/usr/local/go/bin" ]; then if [ ! -d "/usr/local/go/bin" ]; then
echo "Downloading Go.." curl -sLS https://get.arkade.dev | sudo sh
sudo -E arkade system install go
curl -SLsf https://golang.org/dl/go1.16.6.linux-$ARCH.tar.gz --output /tmp/go.tgz
sudo rm -rf /usr/local/go/
sudo mkdir -p /usr/local/go/
sudo tar -xvf /tmp/go.tgz -C /usr/local/go/ --strip-components=1
else else
echo "Go already present, skipping." echo "Go already present, skipping."
fi fi
@ -29,7 +25,7 @@ git clone https://github.com/containerd/containerd
cd containerd cd containerd
git fetch origin --tags git fetch origin --tags
git checkout v1.7.0 git checkout v1.7.27
make make
sudo make install sudo make install

View File

@ -1,37 +0,0 @@
#!/bin/bash
# See pre-reqs:
# https://github.com/alexellis/containerd-arm
export ARCH="arm64"
if [ ! -d "/usr/local/go/bin" ]; then
echo "Downloading Go.."
curl -SLsf https://golang.org/dl/go1.16.6.linux-$ARCH.tar.gz --output /tmp/go.tgz
sudo rm -rf /usr/local/go/
sudo mkdir -p /usr/local/go/
sudo tar -xvf /tmp/go.tgz -C /usr/local/go/ --strip-components=1
else
echo "Go already present, skipping."
fi
export GOPATH=$HOME/go/
export PATH=$PATH:/usr/local/go/bin/
go version
echo "Building containerd"
mkdir -p $GOPATH/src/github.com/containerd
cd $GOPATH/src/github.com/containerd
git clone https://github.com/containerd/containerd
cd containerd
git fetch origin --tags
git checkout v1.7.0
make
sudo make install
sudo containerd --version

View File

@ -7,12 +7,8 @@
export ARCH="arm64" export ARCH="arm64"
if [ ! -d "/usr/local/go/bin" ]; then if [ ! -d "/usr/local/go/bin" ]; then
echo "Downloading Go.." curl -sLS https://get.arkade.dev | sudo sh
sudo -E arkade system install go
curl -SLsf https://golang.org/dl/go1.16.6.linux-$ARCH.tar.gz --output /tmp/go.tgz
sudo rm -rf /usr/local/go/
sudo mkdir -p /usr/local/go/
sudo tar -xvf /tmp/go.tgz -C /usr/local/go/ --strip-components=1
else else
echo "Go already present, skipping." echo "Go already present, skipping."
fi fi
@ -30,7 +26,7 @@ git clone https://github.com/containerd/containerd
cd containerd cd containerd
git fetch origin --tags git fetch origin --tags
git checkout v1.7.0 git checkout v1.7.27
make make
sudo make install sudo make install

48
hack/enable-journal.sh Normal file
View File

@ -0,0 +1,48 @@
#!/bin/bash
# Copyright OpenFaaS Ltd 2025
# This script is for use with Droplets created on DigitalOcean, it will
# ensure that systemd-journald is configured to log to disk and that
# rsyslog is configured to read from systemd-journald.
# Without this change, no logs will be available in the journal, and only
# /var/log/syslog will be populated.
set -e
echo "Checking systemd-journald logs..."
JOURNAL_STATUS=$(journalctl --no-pager -n 10 2>&1)
if echo "$JOURNAL_STATUS" | grep -q "No journal files were found"; then
echo "No journal files found. Fixing logging configuration..."
else
echo "Journald appears to be logging. No changes needed."
exit 0
fi
# Backup original config before making changes
sudo cp /etc/systemd/journald.conf /etc/systemd/journald.conf.bak
# Ensure Storage is persistent
sudo sed -i '/^#Storage=/c\Storage=persistent' /etc/systemd/journald.conf
# Ensure logs are not forwarded only to syslog
sudo sed -i '/^#ForwardToSyslog=/c\ForwardToSyslog=no' /etc/systemd/journald.conf
# Restart systemd-journald
echo "Restarting systemd-journald..."
sudo systemctl restart systemd-journald
# Check if rsyslog already loads imjournal
if ! grep -q 'module(load="imjournal")' /etc/rsyslog.conf; then
echo "Adding imjournal module to rsyslog..."
echo 'module(load="imjournal" StateFile="/var/lib/rsyslog/imjournal.state")' | sudo tee -a /etc/rsyslog.conf
fi
# Restart rsyslog to apply changes
echo "Restarting rsyslog..."
sudo systemctl restart rsyslog
echo "Done. Checking if logs appear in journald..."
journalctl --no-pager -n 10

View File

@ -2,7 +2,7 @@
Description=faasd-provider Description=faasd-provider
[Service] [Service]
MemoryLimit=500M MemoryMax=500M
Environment="secret_mount_path={{.SecretMountPath}}" Environment="secret_mount_path={{.SecretMountPath}}"
Environment="basic_auth=true" Environment="basic_auth=true"
Environment="hosts_dir=/var/lib/faasd" Environment="hosts_dir=/var/lib/faasd"

View File

@ -3,7 +3,7 @@ Description=faasd
After=faasd-provider.service After=faasd-provider.service
[Service] [Service]
MemoryLimit=500M MemoryMax=500M
ExecStart=/usr/local/bin/faasd up ExecStart=/usr/local/bin/faasd up
Restart=on-failure Restart=on-failure
RestartSec=10s RestartSec=10s

132
hack/install-edge.sh Normal file
View File

@ -0,0 +1,132 @@
#!/bin/bash
# Copyright OpenFaaS Ltd 2025
set -e # stop on error
set -o pipefail
export NEEDRESTART_MODE=a
export DEBIAN_FRONTEND=noninteractive
if [ "$EUID" -ne 0 ]; then
echo "Please run as root or with sudo"
exit
fi
has_dnf() {
[ -n "$(command -v dnf)" ]
}
has_apt_get() {
[ -n "$(command -v apt-get)" ]
}
has_pacman() {
[ -n "$(command -v pacman)" ]
}
install_required_packages() {
if $(has_apt_get); then
echo iptables-persistent iptables-persistent/autosave_v4 boolean false | sudo debconf-set-selections
echo iptables-persistent iptables-persistent/autosave_v6 boolean false | sudo debconf-set-selections
# Debian bullseye is missing iptables. Added to required packages
# to get it working in raspberry pi. No such known issues in
# other distros. Hence, adding only to this block.
# reference: https://github.com/openfaas/faasd/pull/237
apt-get update -yq
apt-get install -yq curl runc bridge-utils iptables iptables-persistent
elif $(has_dnf); then
dnf install -y \
--allowerasing \
--setopt=install_weak_deps=False \
curl runc iptables-services bridge-utils which
elif $(has_pacman); then
pacman -Syy
pacman -Sy curl runc bridge-utils
else
fatal "Could not find apt-get, yum, or pacman. Cannot install dependencies on this OS."
exit 1
fi
}
echo "OpenFaaS Edge combines faasd with OpenFaaS Standard"
echo ""
echo ""
echo "1. Installing required OS packages, set SKIP_OS=1 to skip this step"
echo ""
if [ -z "$SKIP_OS" ]; then
install_required_packages
fi
echo ""
echo "2. Downloading OCI image, and installing pre-requisites"
echo ""
if [ ! -x "$(command -v arkade)" ]; then
# For Centos, RHEL, Fedora, Amazon Linux, and Oracle Linux, use BINLOCATION=/usr/bin/
if $(has_dnf); then
BINLOCATION=/usr/bin/
fi
curl -sLS https://get.arkade.dev | BINLOCATION=${BINLOCATION} sh
fi
PATH=$PATH:$HOME/.arkade/bin
tmpdir=$(mktemp -d)
# Ensure all existing services are stopped when installing over an
# existing faasd installation
systemctl stop faasd || :
systemctl stop faasd-provider || :
systemctl stop containerd || :
killall -9 containerd-shim-runc-v2 || :
killall -9 faasd || :
# crane, or docker can also be used to download the OCI image and to extract it
# Rather than the :latest tag, a specific tag can be given
# Use "crane ls ghcr.io/openfaasltd/faasd-pro" to see available tags
${BINLOCATION}arkade oci install --path ${tmpdir} \
ghcr.io/openfaasltd/faasd-pro:latest
cd ${tmpdir}
./install.sh ./
if has_dnf; then
isRhelLike=true
else
isRhelLike=false
fi
binaryName="faasd"
if [ "$isRhelLike" = true ]; then
binaryName="/usr/local/bin/faasd"
fi
echo ""
echo "3.1 Commercial users can create their license key as follows:"
echo ""
echo "sudo mkdir -p /var/lib/faasd/secrets"
echo "sudo nano /var/lib/faasd/secrets/openfaas_license"
echo ""
echo "3.2 For personal, non-commercial use only, GitHub Sponsors of @openfaas (25USD+) can run:"
echo ""
echo "sudo -E ${binaryName} github login"
echo "sudo -E ${binaryName} activate"
echo ""
echo "4. Then perform the final installation steps"
echo ""
echo "sudo -E sh -c \"cd ${tmpdir}/var/lib/faasd && ${binaryName} install\""
echo ""
echo "5. Refer to the complete handbook and supplementary documentation at:"
echo ""
echo "http://store.openfaas.com/l/serverless-for-everyone-else?layout=profile"
echo ""
echo "https://docs.openfaas.com/edge/overview"
echo ""

View File

@ -36,13 +36,19 @@ if [ "$(id -u)" -eq 0 ]; then
fi fi
verify_system() { verify_system() {
arch=$(uname -m)
if [ "$arch" == "armv7l" ]; then
fatal 'faasd requires a 64-bit Operating System, see: https://github.com/openfaas/faasd/issues/364'
fi
if ! [ -d /run/systemd ]; then if ! [ -d /run/systemd ]; then
fatal 'Can not find systemd to use as a process supervisor for faasd' fatal 'Can not find systemd to use as a process supervisor for faasd'
fi fi
} }
has_yum() { has_dnf() {
[ -n "$(command -v yum)" ] [ -n "$(command -v dnf)" ]
} }
has_apt_get() { has_apt_get() {
@ -61,14 +67,16 @@ install_required_packages() {
# reference: https://github.com/openfaas/faasd/pull/237 # reference: https://github.com/openfaas/faasd/pull/237
$SUDO apt-get update -y $SUDO apt-get update -y
$SUDO apt-get install -y curl runc bridge-utils iptables $SUDO apt-get install -y curl runc bridge-utils iptables
elif $(has_yum); then elif $(has_dnf); then
$SUDO yum check-update -y $SUDO dnf install -y \
$SUDO yum install -y curl runc iptables-services --allowerasing \
--setopt=install_weak_deps=False \
curl runc iptables-services bridge-utils
elif $(has_pacman); then elif $(has_pacman); then
$SUDO pacman -Syy $SUDO pacman -Syy
$SUDO pacman -Sy curl runc bridge-utils $SUDO pacman -Sy curl runc bridge-utils
else else
fatal "Could not find apt-get, yum, or pacman. Cannot install dependencies on this OS." fatal "Could not find apt-get, dnf, or pacman. Cannot install dependencies on this OS."
exit 1 exit 1
fi fi
} }
@ -84,19 +92,12 @@ install_cni_plugins() {
} }
install_containerd() { install_containerd() {
CONTAINERD_VER=1.7.0 CONTAINERD_VER=1.7.27
$SUDO systemctl unmask containerd || : $SUDO systemctl unmask containerd || :
arch=$(uname -m) arch=$(uname -m)
if [ $arch == "armv7l" ]; then
$SUDO curl -fSLs "https://github.com/alexellis/containerd-arm/releases/download/v${CONTAINERD_VER}/containerd-${CONTAINERD_VER}-linux-armhf.tar.gz" --output "/tmp/containerd.tar.gz"
$SUDO tar -xvf /tmp/containerd.tar.gz -C /usr/local/bin/
$SUDO curl -fSLs https://raw.githubusercontent.com/containerd/containerd/v${CONTAINERD_VER}/containerd.service --output "/etc/systemd/system/containerd.service"
$SUDO systemctl enable containerd
$SUDO systemctl start containerd
else
$SUDO $ARKADE system install containerd --systemd --version v${CONTAINERD_VER} --progress=false $SUDO $ARKADE system install containerd --systemd --version v${CONTAINERD_VER} --progress=false
fi
sleep 5 sleep 5
} }
@ -110,9 +111,6 @@ install_faasd() {
aarch64) aarch64)
suffix=-arm64 suffix=-arm64
;; ;;
armv7l)
suffix=-armhf
;;
*) *)
echo "Unsupported architecture $arch" echo "Unsupported architecture $arch"
exit 1 exit 1

10
main.go
View File

@ -7,14 +7,6 @@ import (
"github.com/openfaas/faasd/cmd" "github.com/openfaas/faasd/cmd"
) )
// These values will be injected into these variables at the build time.
var (
// GitCommit Git Commit SHA
GitCommit string
// Version version of the CLI
Version string
)
func main() { func main() {
if _, ok := os.LookupEnv("CONTAINER_ID"); ok { if _, ok := os.LookupEnv("CONTAINER_ID"); ok {
@ -31,7 +23,7 @@ func main() {
os.Exit(0) os.Exit(0)
} }
if err := cmd.Execute(Version, GitCommit); err != nil { if err := cmd.Execute(); err != nil {
os.Exit(1) os.Exit(1)
} }
return return

View File

@ -5,7 +5,6 @@ import (
"context" "context"
"fmt" "fmt"
"io" "io"
"io/ioutil"
"log" "log"
"net" "net"
"os" "os"
@ -86,7 +85,7 @@ func InitNetwork() (gocni.CNI, error) {
} }
netConfig := path.Join(CNIConfDir, defaultCNIConfFilename) netConfig := path.Join(CNIConfDir, defaultCNIConfFilename)
if err := ioutil.WriteFile(netConfig, []byte(defaultCNIConf), 644); err != nil { if err := os.WriteFile(netConfig, []byte(defaultCNIConf), 0644); err != nil {
return nil, fmt.Errorf("cannot write network config: %s", defaultCNIConfFilename) return nil, fmt.Errorf("cannot write network config: %s", defaultCNIConfFilename)
} }
@ -151,7 +150,7 @@ func DeleteCNINetwork(ctx context.Context, cni gocni.CNI, client *containerd.Cli
func GetIPAddress(container string, PID uint32) (string, error) { func GetIPAddress(container string, PID uint32) (string, error) {
CNIDir := path.Join(CNIDataDir, defaultNetworkName) CNIDir := path.Join(CNIDataDir, defaultNetworkName)
files, err := ioutil.ReadDir(CNIDir) files, err := os.ReadDir(CNIDir)
if err != nil { if err != nil {
return "", fmt.Errorf("failed to read CNI dir for container %s: %v", container, err) return "", fmt.Errorf("failed to read CNI dir for container %s: %v", container, err)
} }

View File

@ -1,7 +1,6 @@
package cninetwork package cninetwork
import ( import (
"io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
"testing" "testing"
@ -15,7 +14,7 @@ eth1`
PID := uint32(621) PID := uint32(621)
fullPath := filepath.Join(os.TempDir(), fileName) fullPath := filepath.Join(os.TempDir(), fileName)
err := ioutil.WriteFile(fullPath, []byte(body), 0700) err := os.WriteFile(fullPath, []byte(body), 0700)
if err != nil { if err != nil {
t.Fatalf(err.Error()) t.Fatalf(err.Error())
} }
@ -24,7 +23,6 @@ eth1`
}() }()
got, err := isCNIResultForPID(fullPath, container, PID) got, err := isCNIResultForPID(fullPath, container, PID)
if err != nil { if err != nil {
t.Fatalf(err.Error()) t.Fatalf(err.Error())
} }
@ -43,7 +41,7 @@ eth1`
PID := uint32(621) PID := uint32(621)
fullPath := filepath.Join(os.TempDir(), fileName) fullPath := filepath.Join(os.TempDir(), fileName)
err := ioutil.WriteFile(fullPath, []byte(body), 0700) err := os.WriteFile(fullPath, []byte(body), 0700)
if err != nil { if err != nil {
t.Fatalf(err.Error()) t.Fatalf(err.Error())
} }
@ -52,10 +50,10 @@ eth1`
}() }()
got, err := isCNIResultForPID(fullPath, container, PID) got, err := isCNIResultForPID(fullPath, container, PID)
if err != nil { if err != nil {
t.Fatalf(err.Error()) t.Fatalf(err.Error())
} }
want := false want := false
if got != want { if got != want {
t.Fatalf("want %v, but got %v", want, got) t.Fatalf("want %v, but got %v", want, got)

39
pkg/connectivity.go Normal file
View File

@ -0,0 +1,39 @@
package pkg
import (
"fmt"
"io"
"net/http"
"strings"
)
// ConnectivityCheck checks if the controller can reach the
// public Internet via HTTPS.
// A license is required to use OpenFaaS CE for Commercial Use.
func ConnectivityCheck() error {
req, err := http.NewRequest(http.MethodGet, "https://checkip.amazonaws.com", nil)
if err != nil {
return err
}
req.Header.Set("User-Agent", fmt.Sprintf("openfaas-ce/%s faas-netes", Version))
res, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
if req.Body != nil {
defer req.Body.Close()
}
if res.StatusCode != http.StatusOK {
var body []byte
if res.Body != nil {
body, _ = io.ReadAll(res.Body)
}
return fmt.Errorf("unexpected status code checking connectivity: %d, body: %s", res.StatusCode, strings.TrimSpace(string(body)))
}
return nil
}

View File

@ -1,7 +1,6 @@
package pkg package pkg
import ( import (
"io/ioutil"
"log" "log"
"os" "os"
"strings" "strings"
@ -54,7 +53,7 @@ func (l *LocalResolver) rebuild() {
l.Mutex.Lock() l.Mutex.Lock()
defer l.Mutex.Unlock() defer l.Mutex.Unlock()
fileData, fileErr := ioutil.ReadFile(l.Path) fileData, fileErr := os.ReadFile(l.Path)
if fileErr != nil { if fileErr != nil {
log.Printf("resolver rebuild error: %s", fileErr.Error()) log.Printf("resolver rebuild error: %s", fileErr.Error())
return return

View File

@ -105,12 +105,12 @@ func streamLogs(ctx context.Context, cmd *exec.Cmd, out io.ReadCloser, msgs chan
// will ensure `out` is closed and all related resources cleaned up // will ensure `out` is closed and all related resources cleaned up
go func() { go func() {
err := cmd.Wait() if err := cmd.Wait(); err != nil {
log.Println("wait result", err) log.Printf("journalctl exited with error: %s", err)
}
}() }()
defer func() { defer func() {
log.Println("closing journal stream")
close(msgs) close(msgs)
}() }()
@ -176,7 +176,6 @@ func parseEntry(entry map[string]string) (logs.Message, error) {
} }
func logErrOut(out io.ReadCloser) { func logErrOut(out io.ReadCloser) {
defer log.Println("stderr closed")
defer out.Close() defer out.Close()
io.Copy(log.Writer(), out) io.Copy(log.Writer(), out)

View File

@ -4,7 +4,7 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io/ioutil" "io"
"log" "log"
"net/http" "net/http"
@ -29,13 +29,11 @@ func MakeDeleteHandler(client *containerd.Client, cni gocni.CNI) func(w http.Res
defer r.Body.Close() defer r.Body.Close()
body, _ := ioutil.ReadAll(r.Body) body, _ := io.ReadAll(r.Body)
log.Printf("[Delete] request: %s\n", string(body))
req := types.DeleteFunctionRequest{} req := types.DeleteFunctionRequest{}
err := json.Unmarshal(body, &req) if err := json.Unmarshal(body, &req); err != nil {
if err != nil { log.Printf("[Delete] error parsing input: %s", err)
log.Printf("[Delete] error parsing input: %s\n", err)
http.Error(w, err.Error(), http.StatusBadRequest) http.Error(w, err.Error(), http.StatusBadRequest)
return return
@ -63,7 +61,7 @@ func MakeDeleteHandler(client *containerd.Client, cni gocni.CNI) func(w http.Res
function, err := GetFunction(client, name, namespace) function, err := GetFunction(client, name, namespace)
if err != nil { if err != nil {
msg := fmt.Sprintf("service %s not found", name) msg := fmt.Sprintf("function %s.%s not found", name, namespace)
log.Printf("[Delete] %s\n", msg) log.Printf("[Delete] %s\n", msg)
http.Error(w, msg, http.StatusNotFound) http.Error(w, msg, http.StatusNotFound)
return return
@ -85,6 +83,6 @@ func MakeDeleteHandler(client *containerd.Client, cni gocni.CNI) func(w http.Res
return return
} }
log.Printf("[Delete] deleted %s\n", name) log.Printf("[Delete] Removed: %s.%s\n", name, namespace)
} }
} }

View File

@ -4,7 +4,7 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io/ioutil" "io"
"log" "log"
"net/http" "net/http"
"os" "os"
@ -17,7 +17,7 @@ import (
"github.com/containerd/containerd/namespaces" "github.com/containerd/containerd/namespaces"
"github.com/containerd/containerd/oci" "github.com/containerd/containerd/oci"
gocni "github.com/containerd/go-cni" gocni "github.com/containerd/go-cni"
"github.com/docker/distribution/reference" "github.com/distribution/reference"
"github.com/opencontainers/runtime-spec/specs-go" "github.com/opencontainers/runtime-spec/specs-go"
"github.com/openfaas/faas-provider/types" "github.com/openfaas/faas-provider/types"
cninetwork "github.com/openfaas/faasd/pkg/cninetwork" cninetwork "github.com/openfaas/faasd/pkg/cninetwork"
@ -39,13 +39,12 @@ func MakeDeployHandler(client *containerd.Client, cni gocni.CNI, secretMountPath
defer r.Body.Close() defer r.Body.Close()
body, _ := ioutil.ReadAll(r.Body) body, _ := io.ReadAll(r.Body)
log.Printf("[Deploy] request: %s\n", string(body))
req := types.FunctionDeployment{} req := types.FunctionDeployment{}
err := json.Unmarshal(body, &req) err := json.Unmarshal(body, &req)
if err != nil { if err != nil {
log.Printf("[Deploy] - error parsing input: %s\n", err) log.Printf("[Deploy] - error parsing input: %s", err)
http.Error(w, err.Error(), http.StatusBadRequest) http.Error(w, err.Error(), http.StatusBadRequest)
return return
@ -76,10 +75,15 @@ func MakeDeployHandler(client *containerd.Client, cni gocni.CNI, secretMountPath
name := req.Service name := req.Service
ctx := namespaces.WithNamespace(context.Background(), namespace) ctx := namespaces.WithNamespace(context.Background(), namespace)
deployErr := deploy(ctx, req, client, cni, namespaceSecretMountPath, alwaysPull) if err := preDeploy(client, 1); err != nil {
if deployErr != nil { http.Error(w, err.Error(), http.StatusBadRequest)
log.Printf("[Deploy] error deploying %s, error: %s\n", name, deployErr) log.Printf("[Deploy] error deploying %s, error: %s\n", name, err)
http.Error(w, deployErr.Error(), http.StatusBadRequest) return
}
if err := deploy(ctx, req, client, cni, namespaceSecretMountPath, alwaysPull); err != nil {
log.Printf("[Deploy] error deploying %s, error: %s\n", name, err)
http.Error(w, err.Error(), http.StatusBadRequest)
return return
} }
} }
@ -179,8 +183,27 @@ func deploy(ctx context.Context, req types.FunctionDeployment, client *container
} }
// countFunctions returns the number of functions deployed along with a map with a count
// in each namespace
func countFunctions(client *containerd.Client) (int64, int64, error) {
count := int64(0)
namespaceCount := int64(0)
namespaces := ListNamespaces(client)
for _, namespace := range namespaces {
fns, err := ListFunctions(client, namespace)
if err != nil {
return 0, 0, err
}
namespaceCount++
count += int64(len(fns))
}
return count, namespaceCount, nil
}
func buildLabels(request *types.FunctionDeployment) (map[string]string, error) { func buildLabels(request *types.FunctionDeployment) (map[string]string, error) {
// Adapted from faas-swarm/handlers/deploy.go:buildLabels
labels := map[string]string{} labels := map[string]string{}
if request.Labels != nil { if request.Labels != nil {
@ -229,9 +252,8 @@ func createTask(ctx context.Context, container containerd.Container, cni gocni.C
log.Printf("%s has IP: %s.\n", name, ip) log.Printf("%s has IP: %s.\n", name, ip)
_, waitErr := task.Wait(ctx) if _, err := task.Wait(ctx); err != nil {
if waitErr != nil { return errors.Wrapf(err, "Unable to wait for task to start: %s", name)
return errors.Wrapf(waitErr, "Unable to wait for task to start: %s", name)
} }
if startErr := task.Start(ctx); startErr != nil { if startErr := task.Start(ctx); startErr != nil {
@ -315,3 +337,17 @@ func withMemory(mem *specs.LinuxMemory) oci.SpecOpts {
return nil return nil
} }
} }
func preDeploy(client *containerd.Client, additional int64) error {
count, countNs, err := countFunctions(client)
log.Printf("Function count: %d, Namespace count: %d\n", count, countNs)
if err != nil {
return err
} else if count+additional > faasdMaxFunctions {
return fmt.Errorf("the OpenFaaS CE EULA allows %d/%d function(s), upgrade to faasd Pro to continue", faasdMaxFunctions, count+additional)
} else if countNs > faasdMaxNs {
return fmt.Errorf("the OpenFaaS CE EULA allows %d/%d namespace(s), upgrade to faasd Pro to continue", faasdMaxNs, countNs)
}
return nil
}

View File

@ -2,71 +2,17 @@ package handlers
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"log" "log"
"strings" "strings"
"time"
"github.com/opencontainers/runtime-spec/specs-go" "github.com/opencontainers/runtime-spec/specs-go"
"github.com/containerd/containerd" "github.com/containerd/containerd"
"github.com/containerd/containerd/namespaces" "github.com/containerd/containerd/namespaces"
"github.com/openfaas/faasd/pkg"
faasd "github.com/openfaas/faasd/pkg"
"github.com/openfaas/faasd/pkg/cninetwork" "github.com/openfaas/faasd/pkg/cninetwork"
) )
type Function struct {
name string
namespace string
image string
pid uint32
replicas int
IP string
labels map[string]string
annotations map[string]string
secrets []string
envVars map[string]string
envProcess string
memoryLimit int64
createdAt time.Time
}
// ListFunctions returns a map of all functions with running tasks on namespace
func ListFunctions(client *containerd.Client, namespace string) (map[string]*Function, error) {
// Check if namespace exists, and it has the openfaas label
valid, err := validNamespace(client.NamespaceService(), namespace)
if err != nil {
return nil, err
}
if !valid {
return nil, errors.New("namespace not valid")
}
ctx := namespaces.WithNamespace(context.Background(), namespace)
functions := make(map[string]*Function)
containers, err := client.Containers(ctx)
if err != nil {
return functions, err
}
for _, c := range containers {
name := c.ID()
f, err := GetFunction(client, name, namespace)
if err != nil {
log.Printf("skipping %s, error: %s", name, err)
} else {
functions[name] = &f
}
}
return functions, nil
}
// GetFunction returns a function that matches name // GetFunction returns a function that matches name
func GetFunction(client *containerd.Client, name string, namespace string) (Function, error) { func GetFunction(client *containerd.Client, name string, namespace string) (Function, error) {
ctx := namespaces.WithNamespace(context.Background(), namespace) ctx := namespaces.WithNamespace(context.Background(), namespace)
@ -196,44 +142,6 @@ func buildLabelsAndAnnotations(ctrLabels map[string]string) (map[string]string,
return labels, annotations return labels, annotations
} }
func ListNamespaces(client *containerd.Client) []string {
set := []string{}
store := client.NamespaceService()
namespaces, err := store.List(context.Background())
if err != nil {
log.Printf("Error listing namespaces: %s", err.Error())
set = append(set, faasd.DefaultFunctionNamespace)
return set
}
for _, namespace := range namespaces {
labels, err := store.Labels(context.Background(), namespace)
if err != nil {
log.Printf("Error listing label for namespace %s: %s", namespace, err.Error())
continue
}
if _, found := labels[pkg.NamespaceLabel]; found {
set = append(set, namespace)
}
if !findNamespace(faasd.DefaultFunctionNamespace, set) {
set = append(set, faasd.DefaultFunctionNamespace)
}
}
return set
}
func findNamespace(target string, items []string) bool {
for _, n := range items {
if n == target {
return true
}
}
return false
}
func readMemoryLimitFromSpec(spec *specs.Spec) int64 { func readMemoryLimitFromSpec(spec *specs.Spec) int64 {
if spec.Linux == nil || spec.Linux.Resources == nil || spec.Linux.Resources.Memory == nil || spec.Linux.Resources.Memory.Limit == nil { if spec.Linux == nil || spec.Linux.Resources == nil || spec.Linux.Resources.Memory == nil || spec.Linux.Resources.Memory.Limit == nil {
return 0 return 0

View File

@ -0,0 +1,65 @@
package handlers
import (
"context"
"errors"
"log"
"strings"
"time"
"github.com/containerd/containerd"
"github.com/containerd/containerd/namespaces"
)
type Function struct {
name string
namespace string
image string
pid uint32
replicas int
IP string
labels map[string]string
annotations map[string]string
secrets []string
envVars map[string]string
envProcess string
memoryLimit int64
createdAt time.Time
}
// ListFunctions returns a map of all functions with running tasks on namespace
func ListFunctions(client *containerd.Client, namespace string) (map[string]*Function, error) {
// Check if namespace exists, and it has the openfaas label
valid, err := validNamespace(client.NamespaceService(), namespace)
if err != nil {
return nil, err
}
if !valid {
return nil, errors.New("namespace not valid")
}
ctx := namespaces.WithNamespace(context.Background(), namespace)
functions := make(map[string]*Function)
containers, err := client.Containers(ctx)
if err != nil {
return functions, err
}
for _, c := range containers {
name := c.ID()
f, err := GetFunction(client, name, namespace)
if err != nil {
if !strings.Contains(err.Error(), "unable to get IP address for container") {
log.Printf("List functions, skipping: %s, error: %s", name, err)
}
} else {
functions[name] = &f
}
}
return functions, nil
}

View File

@ -12,7 +12,7 @@ const (
OrchestrationIdentifier = "containerd" OrchestrationIdentifier = "containerd"
// ProviderName name of the provider // ProviderName name of the provider
ProviderName = "faasd" ProviderName = "faasd-ce"
) )
// MakeInfoHandler creates handler for /system/info endpoint // MakeInfoHandler creates handler for /system/info endpoint
@ -31,8 +31,8 @@ func MakeInfoHandler(version, sha string) http.HandlerFunc {
}, },
} }
jsonOut, marshalErr := json.Marshal(infoResponse) jsonOut, err := json.Marshal(infoResponse)
if marshalErr != nil { if err != nil {
w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(http.StatusInternalServerError)
return return
} }
@ -42,3 +42,6 @@ func MakeInfoHandler(version, sha string) http.HandlerFunc {
w.Write(jsonOut) w.Write(jsonOut)
} }
} }
const faasdMaxFunctions = 15
const faasdMaxNs = 1

View File

@ -1,10 +1,14 @@
package handlers package handlers
import ( import (
"context"
"encoding/json" "encoding/json"
"log"
"net/http" "net/http"
"github.com/containerd/containerd" "github.com/containerd/containerd"
"github.com/openfaas/faasd/pkg"
faasd "github.com/openfaas/faasd/pkg"
) )
func MakeNamespacesLister(client *containerd.Client) func(w http.ResponseWriter, r *http.Request) { func MakeNamespacesLister(client *containerd.Client) func(w http.ResponseWriter, r *http.Request) {
@ -16,3 +20,43 @@ func MakeNamespacesLister(client *containerd.Client) func(w http.ResponseWriter,
w.Write(body) w.Write(body)
} }
} }
func ListNamespaces(client *containerd.Client) []string {
set := []string{faasd.DefaultFunctionNamespace}
store := client.NamespaceService()
namespaces, err := store.List(context.Background())
if err != nil {
log.Printf("Error listing namespaces: %s", err.Error())
return set
}
for _, namespace := range namespaces {
labels, err := store.Labels(context.Background(), namespace)
if err != nil {
log.Printf("Error listing label for namespace %s: %s", namespace, err.Error())
continue
}
if _, found := labels[pkg.NamespaceLabel]; found {
set = append(set, namespace)
}
}
if len(set) == 0 {
set = append(set, faasd.DefaultFunctionNamespace)
}
return set
}
func findNamespace(target string, items []string) bool {
for _, n := range items {
if n == target {
return true
}
}
return false
}

View File

@ -31,7 +31,7 @@ func MakeReadHandler(client *containerd.Client) func(w http.ResponseWriter, r *h
res := []types.FunctionStatus{} res := []types.FunctionStatus{}
fns, err := ListFunctions(client, lookupNamespace) fns, err := ListFunctions(client, lookupNamespace)
if err != nil { if err != nil {
log.Printf("[Read] error listing functions. Error: %s\n", err) log.Printf("[Read] error listing functions. Error: %s", err)
http.Error(w, err.Error(), http.StatusBadRequest) http.Error(w, err.Error(), http.StatusBadRequest)
return return
} }

View File

@ -4,7 +4,7 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io/ioutil" "io"
"log" "log"
"net/http" "net/http"
@ -27,12 +27,11 @@ func MakeReplicaUpdateHandler(client *containerd.Client, cni gocni.CNI) func(w h
defer r.Body.Close() defer r.Body.Close()
body, _ := ioutil.ReadAll(r.Body) body, _ := io.ReadAll(r.Body)
log.Printf("[Scale] request: %s\n", string(body))
req := types.ScaleServiceRequest{} req := types.ScaleServiceRequest{}
if err := json.Unmarshal(body, &req); err != nil { if err := json.Unmarshal(body, &req); err != nil {
log.Printf("[Scale] error parsing input: %s\n", err) log.Printf("[Scale] error parsing input: %s", err)
http.Error(w, err.Error(), http.StatusBadRequest) http.Error(w, err.Error(), http.StatusBadRequest)
return return
@ -58,7 +57,7 @@ func MakeReplicaUpdateHandler(client *containerd.Client, cni gocni.CNI) func(w h
name := req.ServiceName name := req.ServiceName
if _, err := GetFunction(client, name, namespace); err != nil { if _, err := GetFunction(client, name, namespace); err != nil {
msg := fmt.Sprintf("service %s not found", name) msg := fmt.Sprintf("function: %s.%s not found", name, namespace)
log.Printf("[Scale] %s\n", msg) log.Printf("[Scale] %s\n", msg)
http.Error(w, msg, http.StatusNotFound) http.Error(w, msg, http.StatusNotFound)
return return
@ -97,32 +96,24 @@ func MakeReplicaUpdateHandler(client *containerd.Client, cni gocni.CNI) func(w h
createNewTask := false createNewTask := false
// Scale to zero
if req.Replicas == 0 { if req.Replicas == 0 {
// If a task is running, pause it http.Error(w, "replicas must > 0 for faasd CE", http.StatusBadRequest)
if taskExists && taskStatus.Status == containerd.Running {
if pauseErr := task.Pause(ctx); pauseErr != nil {
wrappedPauseErr := fmt.Errorf("error pausing task %s, error: %s", name, pauseErr)
log.Printf("[Scale] %s\n", wrappedPauseErr.Error())
http.Error(w, wrappedPauseErr.Error(), http.StatusNotFound)
return return
} }
}
}
if taskExists { if taskExists {
if taskStatus != nil { if taskStatus != nil {
if taskStatus.Status == containerd.Paused { if taskStatus.Status == containerd.Paused {
if resumeErr := task.Resume(ctx); resumeErr != nil { if _, err := task.Delete(ctx); err != nil {
log.Printf("[Scale] error resuming task %s, error: %s\n", name, resumeErr) log.Printf("[Scale] error deleting paused task %s, error: %s\n", name, err)
http.Error(w, resumeErr.Error(), http.StatusBadRequest) http.Error(w, err.Error(), http.StatusBadRequest)
return return
} }
} else if taskStatus.Status == containerd.Stopped { } else if taskStatus.Status == containerd.Stopped {
// Stopped tasks cannot be restarted, must be removed, and created again // Stopped tasks cannot be restarted, must be removed, and created again
if _, delErr := task.Delete(ctx); delErr != nil { if _, err := task.Delete(ctx); err != nil {
log.Printf("[Scale] error deleting stopped task %s, error: %s\n", name, delErr) log.Printf("[Scale] error deleting stopped task %s, error: %s\n", name, err)
http.Error(w, delErr.Error(), http.StatusBadRequest) http.Error(w, err.Error(), http.StatusBadRequest)
return return
} }
createNewTask = true createNewTask = true

View File

@ -3,7 +3,7 @@ package handlers
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io/ioutil" "io"
"log" "log"
"net/http" "net/http"
"os" "os"
@ -71,7 +71,7 @@ func listSecrets(store provider.Labeller, w http.ResponseWriter, r *http.Request
} }
if err != nil { if err != nil {
fmt.Printf("Error Occured: %s \n", err) log.Printf("[Secret] Error listing secrets: %s ", err)
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
return return
} }
@ -116,7 +116,7 @@ func createSecret(w http.ResponseWriter, r *http.Request, mountPath string) {
data = []byte(secret.Value) data = []byte(secret.Value)
} }
err = ioutil.WriteFile(path.Join(mountPath, secret.Name), data, secretFilePermission) err = os.WriteFile(path.Join(mountPath, secret.Name), data, secretFilePermission)
if err != nil { if err != nil {
log.Printf("[secret] error %s", err.Error()) log.Printf("[secret] error %s", err.Error())
@ -147,7 +147,7 @@ func deleteSecret(w http.ResponseWriter, r *http.Request, mountPath string) {
func parseSecret(r *http.Request) (types.Secret, error) { func parseSecret(r *http.Request) (types.Secret, error) {
secret := types.Secret{} secret := types.Secret{}
bytesOut, err := ioutil.ReadAll(r.Body) bytesOut, err := io.ReadAll(r.Body)
if err != nil { if err != nil {
return secret, err return secret, err
} }

View File

@ -3,7 +3,7 @@ package handlers
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io/ioutil" "io"
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
"os" "os"
@ -232,7 +232,7 @@ func TestListSecrets(t *testing.T) {
t.Fatalf("want error message: %q, but got %q", tc.err, w.Body.String()) t.Fatalf("want error message: %q, but got %q", tc.err, w.Body.String())
} }
body, err := ioutil.ReadAll(resp.Body) body, err := io.ReadAll(resp.Body)
if err != nil { if err != nil {
t.Fatalf("can't read response of list %v", err) t.Fatalf("can't read response of list %v", err)
} }

View File

@ -4,7 +4,7 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io/ioutil" "io"
"log" "log"
"net/http" "net/http"
@ -28,17 +28,17 @@ func MakeUpdateHandler(client *containerd.Client, cni gocni.CNI, secretMountPath
defer r.Body.Close() defer r.Body.Close()
body, _ := ioutil.ReadAll(r.Body) body, _ := io.ReadAll(r.Body)
log.Printf("[Update] request: %s\n", string(body))
req := types.FunctionDeployment{} req := types.FunctionDeployment{}
err := json.Unmarshal(body, &req) err := json.Unmarshal(body, &req)
if err != nil { if err != nil {
log.Printf("[Update] error parsing input: %s\n", err) log.Printf("[Update] error parsing input: %s", err)
http.Error(w, err.Error(), http.StatusBadRequest) http.Error(w, err.Error(), http.StatusBadRequest)
return return
} }
name := req.Service name := req.Service
namespace := getRequestNamespace(req.Namespace) namespace := getRequestNamespace(req.Namespace)
@ -54,11 +54,17 @@ func MakeUpdateHandler(client *containerd.Client, cni gocni.CNI, secretMountPath
return return
} }
if err := preDeploy(client, int64(0)); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
log.Printf("[Deploy] error deploying %s, error: %s\n", name, err)
return
}
namespaceSecretMountPath := getNamespaceSecretMountPath(secretMountPath, namespace) namespaceSecretMountPath := getNamespaceSecretMountPath(secretMountPath, namespace)
function, err := GetFunction(client, name, namespace) function, err := GetFunction(client, name, namespace)
if err != nil { if err != nil {
msg := fmt.Sprintf("service %s not found", name) msg := fmt.Sprintf("function: %s.%s not found", name, namespace)
log.Printf("[Update] %s\n", msg) log.Printf("[Update] %s\n", msg)
http.Error(w, msg, http.StatusNotFound) http.Error(w, msg, http.StatusNotFound)
return return

View File

@ -75,17 +75,18 @@ func (p *Proxy) Start() error {
// Wait for a connection. // Wait for a connection.
conn, err := l.Accept() conn, err := l.Accept()
if err != nil { if err != nil {
acceptErr := fmt.Errorf("unable to accept on %d, error: %s", log.Printf("Unable to accept on: %d, error: %s",
p.Port, p.Port,
err.Error()) err.Error())
log.Printf("%s", acceptErr.Error()) return err
return acceptErr
} }
upstream, err := net.Dial("tcp", upstreamAddr) upstream, err := net.Dial("tcp", upstreamAddr)
if err != nil { if err != nil {
log.Printf("unable to dial to %s, error: %s", upstreamAddr, err.Error()) conn.Close()
return err
log.Printf("Unable to dial: %s, error: %s", upstreamAddr, err.Error())
continue
} }
go pipe(conn, upstream) go pipe(conn, upstream)

View File

@ -2,7 +2,7 @@ package pkg
import ( import (
"fmt" "fmt"
"io/ioutil" "io"
"log" "log"
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
@ -61,7 +61,7 @@ func Test_Proxy_ToPrivateServer(t *testing.T) {
time.Sleep(time.Millisecond * 100) time.Sleep(time.Millisecond * 100)
} else { } else {
resBody, _ := ioutil.ReadAll(res.Body) resBody, _ := io.ReadAll(res.Body)
if string(resBody) != string(wantBody) { if string(resBody) != string(wantBody) {
t.Errorf("want %s, but got %s in body", string(wantBody), string(resBody)) t.Errorf("want %s, but got %s in body", string(wantBody), string(resBody))
} }

View File

@ -6,6 +6,7 @@ import (
"log" "log"
"os" "os"
"path/filepath" "path/filepath"
"strings"
"sync" "sync"
"time" "time"
@ -45,10 +46,24 @@ func Remove(ctx context.Context, client *containerd.Client, name string) error {
log.Printf("Status of %s is: %s\n", name, status.Status) log.Printf("Status of %s is: %s\n", name, status.Status)
} }
log.Printf("Need to kill task: %s\n", name) var gracePeriod = time.Second * 30
if err = killTask(ctx, t); err != nil { spec, err := t.Spec(ctx)
if err == nil {
for _, p := range spec.Process.Env {
k, v, ok := strings.Cut(p, "=")
if ok && k == "grace_period" {
periodVal, err := time.ParseDuration(v)
if err == nil {
gracePeriod = periodVal
}
}
}
}
if err = killTask(ctx, t, gracePeriod); err != nil {
return fmt.Errorf("error killing task %s, %s, %w", container.ID(), name, err) return fmt.Errorf("error killing task %s, %s, %w", container.ID(), name, err)
} }
} }
if err := container.Delete(ctx, containerd.WithSnapshotCleanup); err != nil { if err := container.Delete(ctx, containerd.WithSnapshotCleanup); err != nil {
@ -57,7 +72,7 @@ func Remove(ctx context.Context, client *containerd.Client, name string) error {
} else { } else {
service := client.SnapshotService("") service := client.SnapshotService("")
key := name + "snapshot" key := name + "-snapshot"
if _, err := client.SnapshotService("").Stat(ctx, key); err == nil { if _, err := client.SnapshotService("").Stat(ctx, key); err == nil {
service.Remove(ctx, key) service.Remove(ctx, key)
} }
@ -66,14 +81,13 @@ func Remove(ctx context.Context, client *containerd.Client, name string) error {
} }
// Adapted from Stellar - https://github.com/stellar // Adapted from Stellar - https://github.com/stellar
func killTask(ctx context.Context, task containerd.Task) error { func killTask(ctx context.Context, task containerd.Task, gracePeriod time.Duration) error {
killTimeout := 30 * time.Second
wg := &sync.WaitGroup{} wg := &sync.WaitGroup{}
wg.Add(1) wg.Add(1)
var err error var err error
waited := false
go func() { go func() {
defer wg.Done() defer wg.Done()
if task != nil { if task != nil {
@ -89,22 +103,39 @@ func killTask(ctx context.Context, task containerd.Task) error {
select { select {
case <-wait: case <-wait:
task.Delete(ctx) waited = true
return return
case <-time.After(killTimeout): case <-time.After(gracePeriod):
log.Printf("Sending SIGKILL to: %s after: %s", task.ID(), gracePeriod.Round(time.Second).String())
if err := task.Kill(ctx, unix.SIGKILL, containerd.WithKillAll); err != nil { if err := task.Kill(ctx, unix.SIGKILL, containerd.WithKillAll); err != nil {
log.Printf("error force killing container task: %s", err) log.Printf("error sending SIGKILL to task: %s", err)
} }
return return
} }
} }
}() }()
wg.Wait() wg.Wait()
if task != nil {
if !waited {
wait, err := task.Wait(ctx)
if err != nil {
log.Printf("error waiting on task after kill: %s", err)
}
<-wait
}
if _, err := task.Delete(ctx); err != nil {
return err
}
}
return err return err
} }
func getResolver(ctx context.Context, configFile *configfile.ConfigFile) (remotes.Resolver, error) { func getResolver(configFile *configfile.ConfigFile) (remotes.Resolver, error) {
// credsFunc is based on https://github.com/moby/buildkit/blob/0b130cca040246d2ddf55117eeff34f546417e40/session/auth/authprovider/authprovider.go#L35 // credsFunc is based on https://github.com/moby/buildkit/blob/0b130cca040246d2ddf55117eeff34f546417e40/session/auth/authprovider/authprovider.go#L35
credFunc := func(host string) (string, string, error) { credFunc := func(host string) (string, string, error) {
if host == "registry-1.docker.io" { if host == "registry-1.docker.io" {
@ -139,7 +170,7 @@ func PrepareImage(ctx context.Context, client *containerd.Client, imageName, sna
if err != nil { if err != nil {
return nil, err return nil, err
} }
resolver, err = getResolver(ctx, configFile) resolver, err = getResolver(configFile)
if err != nil { if err != nil {
return empty, err return empty, err
} }

View File

@ -3,7 +3,6 @@ package pkg
import ( import (
"context" "context"
"fmt" "fmt"
"io/ioutil"
"log" "log"
"os" "os"
"path" "path"
@ -19,7 +18,7 @@ import (
"github.com/containerd/containerd/containers" "github.com/containerd/containerd/containers"
"github.com/containerd/containerd/oci" "github.com/containerd/containerd/oci"
gocni "github.com/containerd/go-cni" gocni "github.com/containerd/go-cni"
"github.com/docker/distribution/reference" "github.com/distribution/reference"
"github.com/openfaas/faasd/pkg/cninetwork" "github.com/openfaas/faasd/pkg/cninetwork"
"github.com/openfaas/faasd/pkg/service" "github.com/openfaas/faasd/pkg/service"
"github.com/pkg/errors" "github.com/pkg/errors"
@ -102,7 +101,7 @@ func (s *Supervisor) Start(svcs []Service) error {
127.0.0.1 localhost 127.0.0.1 localhost
%s faasd-provider`, gw) %s faasd-provider`, gw)
writeHostsErr := ioutil.WriteFile(path.Join(wd, "hosts"), writeHostsErr := os.WriteFile(path.Join(wd, "hosts"),
[]byte(hosts), workingDirectoryPermission) []byte(hosts), workingDirectoryPermission)
if writeHostsErr != nil { if writeHostsErr != nil {
@ -228,7 +227,7 @@ func (s *Supervisor) Start(svcs []Service) error {
) )
if err != nil { if err != nil {
log.Printf("Error creating container: %s\n", err) log.Printf("Error creating container: %s", err)
return err return err
} }
@ -236,7 +235,7 @@ func (s *Supervisor) Start(svcs []Service) error {
task, err := newContainer.NewTask(ctx, cio.BinaryIO("/usr/local/bin/faasd", nil)) task, err := newContainer.NewTask(ctx, cio.BinaryIO("/usr/local/bin/faasd", nil))
if err != nil { if err != nil {
log.Printf("Error creating task: %s\n", err) log.Printf("Error creating task: %s", err)
return err return err
} }
@ -255,7 +254,7 @@ func (s *Supervisor) Start(svcs []Service) error {
log.Printf("%s has IP: %s\n", newContainer.ID(), ip) log.Printf("%s has IP: %s\n", newContainer.ID(), ip)
hosts, err := ioutil.ReadFile("hosts") hosts, err := os.ReadFile("hosts")
if err != nil { if err != nil {
log.Printf("Unable to read hosts file: %s\n", err.Error()) log.Printf("Unable to read hosts file: %s\n", err.Error())
} }
@ -264,12 +263,12 @@ func (s *Supervisor) Start(svcs []Service) error {
%s %s %s %s
`, ip, svc.Name)) `, ip, svc.Name))
if err := ioutil.WriteFile("hosts", hosts, workingDirectoryPermission); err != nil { if err := os.WriteFile("hosts", hosts, workingDirectoryPermission); err != nil {
log.Printf("Error writing file: %s %s\n", "hosts", err) log.Printf("Error writing file: %s %s\n", "hosts", err)
} }
if _, err := task.Wait(ctx); err != nil { if _, err := task.Wait(ctx); err != nil {
log.Printf("Task wait error: %s\n", err) log.Printf("Task wait error: %s", err)
return err return err
} }
@ -277,7 +276,7 @@ func (s *Supervisor) Start(svcs []Service) error {
// log.Println("Exited: ", exitStatusC) // log.Println("Exited: ", exitStatusC)
if err = task.Start(ctx); err != nil { if err = task.Start(ctx); err != nil {
log.Printf("Task start error: %s\n", err) log.Printf("Task start error: %s", err)
return err return err
} }
} }
@ -400,7 +399,7 @@ func LoadComposeFile(wd string, file string) (*compose.Config, error) {
func LoadComposeFileWithArch(wd string, file string, archGetter ArchGetter) (*compose.Config, error) { func LoadComposeFileWithArch(wd string, file string, archGetter ArchGetter) (*compose.Config, error) {
file = path.Join(wd, file) file = path.Join(wd, file)
b, err := ioutil.ReadFile(file) b, err := os.ReadFile(file)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -452,8 +451,6 @@ func GetArchSuffix(getClientArch ArchGetter) (suffix string, err error) {
case "x86_64": case "x86_64":
// no suffix needed // no suffix needed
return "", nil return "", nil
case "armhf", "armv7l":
return "-armhf", nil
case "arm64", "aarch64": case "arm64", "aarch64":
return "-arm64", nil return "-arm64", nil
default: default:

View File

@ -210,18 +210,6 @@ func Test_GetArchSuffix(t *testing.T) {
foundArch: "anything_else", foundArch: "anything_else",
want: "", want: "",
}, },
{
name: "armhf has armhf suffix",
foundOS: "Linux",
foundArch: "armhf",
want: "-armhf",
},
{
name: "armv7l has armhf suffix",
foundOS: "Linux",
foundArch: "armv7l",
want: "-armhf",
},
{ {
name: "arm64 has arm64 suffix", name: "arm64 has arm64 suffix",
foundOS: "Linux", foundOS: "Linux",

View File

@ -1 +1,17 @@
package pkg package pkg
// These values will be injected into these variables at the build time.
var (
// GitCommit Git Commit SHA
GitCommit string
// Version version of the CLI
Version string
)
// GetVersion get latest version
func GetVersion() string {
if len(Version) == 0 {
return "dev"
}
return Version
}

View File

@ -25,11 +25,10 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"reflect" "reflect"
"strconv"
"strings" "strings"
"time" "time"
"unsafe" "unsafe"
securejoin "github.com/cyphar/filepath-securejoin"
) )
var ( var (
@ -389,11 +388,11 @@ func (f *ConsumeFuzzer) GetUint16() (uint16, error) {
} }
func (f *ConsumeFuzzer) GetUint32() (uint32, error) { func (f *ConsumeFuzzer) GetUint32() (uint32, error) {
i, err := f.GetInt() u32, err := f.GetNBytes(4)
if err != nil { if err != nil {
return uint32(0), err return 0, err
} }
return uint32(i), nil return binary.BigEndian.Uint32(u32), nil
} }
func (f *ConsumeFuzzer) GetUint64() (uint64, error) { func (f *ConsumeFuzzer) GetUint64() (uint64, error) {
@ -412,26 +411,27 @@ func (f *ConsumeFuzzer) GetUint64() (uint64, error) {
} }
func (f *ConsumeFuzzer) GetBytes() ([]byte, error) { func (f *ConsumeFuzzer) GetBytes() ([]byte, error) {
if f.position >= f.dataTotal { var length uint32
return nil, errors.New("not enough bytes to create byte array") var err error
} length, err = f.GetUint32()
length, err := f.GetUint32()
if err != nil { if err != nil {
return nil, errors.New("not enough bytes to create byte array") return nil, errors.New("not enough bytes to create byte array")
} }
if f.position+length > MaxTotalLen {
return nil, errors.New("created too large a string")
}
byteBegin := f.position - 1
if byteBegin >= f.dataTotal {
return nil, errors.New("not enough bytes to create byte array")
}
if length == 0 { if length == 0 {
return nil, errors.New("zero-length is not supported") length = 30
} }
if byteBegin+length >= f.dataTotal { bytesLeft := f.dataTotal - f.position
if bytesLeft <= 0 {
return nil, errors.New("not enough bytes to create byte array") return nil, errors.New("not enough bytes to create byte array")
} }
// If the length is the same as bytes left, we will not overflow
// the remaining bytes.
if length != bytesLeft {
length = length % bytesLeft
}
byteBegin := f.position
if byteBegin+length < byteBegin { if byteBegin+length < byteBegin {
return nil, errors.New("numbers overflow") return nil, errors.New("numbers overflow")
} }
@ -482,6 +482,7 @@ func (f *ConsumeFuzzer) FuzzMap(m interface{}) error {
} }
func returnTarBytes(buf []byte) ([]byte, error) { func returnTarBytes(buf []byte) ([]byte, error) {
return buf, nil
// Count files // Count files
var fileCounter int var fileCounter int
tr := tar.NewReader(bytes.NewReader(buf)) tr := tar.NewReader(bytes.NewReader(buf))
@ -504,7 +505,8 @@ func returnTarBytes(buf []byte) ([]byte, error) {
func setTarHeaderFormat(hdr *tar.Header, f *ConsumeFuzzer) error { func setTarHeaderFormat(hdr *tar.Header, f *ConsumeFuzzer) error {
ind, err := f.GetInt() ind, err := f.GetInt()
if err != nil { if err != nil {
return err hdr.Format = tar.FormatGNU
//return nil
} }
switch ind % 4 { switch ind % 4 {
case 0: case 0:
@ -565,71 +567,17 @@ func setTarHeaderTypeflag(hdr *tar.Header, f *ConsumeFuzzer) error {
return nil return nil
} }
func tooSmallFileBody(length uint32) bool {
if length < 2 {
return true
}
if length < 4 {
return true
}
if length < 10 {
return true
}
if length < 100 {
return true
}
if length < 500 {
return true
}
if length < 1000 {
return true
}
if length < 2000 {
return true
}
if length < 4000 {
return true
}
if length < 8000 {
return true
}
if length < 16000 {
return true
}
if length < 32000 {
return true
}
if length < 64000 {
return true
}
if length < 128000 {
return true
}
if length < 264000 {
return true
}
return false
}
func (f *ConsumeFuzzer) createTarFileBody() ([]byte, error) { func (f *ConsumeFuzzer) createTarFileBody() ([]byte, error) {
length, err := f.GetUint32() return f.GetBytes()
/*length, err := f.GetUint32()
if err != nil { if err != nil {
return nil, errors.New("not enough bytes to create byte array") return nil, errors.New("not enough bytes to create byte array")
} }
shouldUseLargeFileBody, err := f.GetBool()
if err != nil {
return nil, errors.New("not enough bytes to check long file body")
}
if shouldUseLargeFileBody && tooSmallFileBody(length) {
return nil, errors.New("File body was too small")
}
// A bit of optimization to attempt to create a file body // A bit of optimization to attempt to create a file body
// when we don't have as many bytes left as "length" // when we don't have as many bytes left as "length"
remainingBytes := f.dataTotal - f.position remainingBytes := f.dataTotal - f.position
if remainingBytes == 0 { if remainingBytes <= 0 {
return nil, errors.New("created too large a string") return nil, errors.New("created too large a string")
} }
if f.position+length > MaxTotalLen { if f.position+length > MaxTotalLen {
@ -649,14 +597,15 @@ func (f *ConsumeFuzzer) createTarFileBody() ([]byte, error) {
return nil, errors.New("numbers overflow") return nil, errors.New("numbers overflow")
} }
f.position = byteBegin + length f.position = byteBegin + length
return f.data[byteBegin:f.position], nil return f.data[byteBegin:f.position], nil*/
} }
// getTarFileName is similar to GetString(), but creates string based // getTarFileName is similar to GetString(), but creates string based
// on the length of f.data to reduce the likelihood of overflowing // on the length of f.data to reduce the likelihood of overflowing
// f.data. // f.data.
func (f *ConsumeFuzzer) getTarFilename() (string, error) { func (f *ConsumeFuzzer) getTarFilename() (string, error) {
length, err := f.GetUint32() return f.GetString()
/*length, err := f.GetUint32()
if err != nil { if err != nil {
return "nil", errors.New("not enough bytes to create string") return "nil", errors.New("not enough bytes to create string")
} }
@ -664,14 +613,9 @@ func (f *ConsumeFuzzer) getTarFilename() (string, error) {
// A bit of optimization to attempt to create a file name // A bit of optimization to attempt to create a file name
// when we don't have as many bytes left as "length" // when we don't have as many bytes left as "length"
remainingBytes := f.dataTotal - f.position remainingBytes := f.dataTotal - f.position
if remainingBytes == 0 { if remainingBytes <= 0 {
return "nil", errors.New("created too large a string") return "nil", errors.New("created too large a string")
} }
if remainingBytes < 50 {
length = length % remainingBytes
} else if f.dataTotal < 500 {
length = length % f.dataTotal
}
if f.position > MaxTotalLen { if f.position > MaxTotalLen {
return "nil", errors.New("created too large a string") return "nil", errors.New("created too large a string")
} }
@ -686,7 +630,12 @@ func (f *ConsumeFuzzer) getTarFilename() (string, error) {
return "nil", errors.New("numbers overflow") return "nil", errors.New("numbers overflow")
} }
f.position = byteBegin + length f.position = byteBegin + length
return string(f.data[byteBegin:f.position]), nil return string(f.data[byteBegin:f.position]), nil*/
}
type TarFile struct {
Hdr *tar.Header
Body []byte
} }
// TarBytes returns valid bytes for a tar archive // TarBytes returns valid bytes for a tar archive
@ -695,28 +644,38 @@ func (f *ConsumeFuzzer) TarBytes() ([]byte, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
var tarFiles []*TarFile
tarFiles = make([]*TarFile, 0)
var buf bytes.Buffer const maxNoOfFiles = 100
tw := tar.NewWriter(&buf)
defer tw.Close()
const maxNoOfFiles = 1000
for i := 0; i < numberOfFiles%maxNoOfFiles; i++ { for i := 0; i < numberOfFiles%maxNoOfFiles; i++ {
filename, err := f.getTarFilename() var filename string
var filebody []byte
var sec, nsec int
var err error
filename, err = f.getTarFilename()
if err != nil { if err != nil {
return returnTarBytes(buf.Bytes()) var sb strings.Builder
sb.WriteString("file-")
sb.WriteString(strconv.Itoa(i))
filename = sb.String()
} }
filebody, err := f.createTarFileBody() filebody, err = f.createTarFileBody()
if err != nil { if err != nil {
return returnTarBytes(buf.Bytes()) var sb strings.Builder
sb.WriteString("filebody-")
sb.WriteString(strconv.Itoa(i))
filebody = []byte(sb.String())
} }
sec, err := f.GetInt()
sec, err = f.GetInt()
if err != nil { if err != nil {
return returnTarBytes(buf.Bytes()) sec = 1672531200 // beginning of 2023
} }
nsec, err := f.GetInt() nsec, err = f.GetInt()
if err != nil { if err != nil {
return returnTarBytes(buf.Bytes()) nsec = 1703980800 // end of 2023
} }
hdr := &tar.Header{ hdr := &tar.Header{
@ -726,21 +685,83 @@ func (f *ConsumeFuzzer) TarBytes() ([]byte, error) {
ModTime: time.Unix(int64(sec), int64(nsec)), ModTime: time.Unix(int64(sec), int64(nsec)),
} }
if err := setTarHeaderTypeflag(hdr, f); err != nil { if err := setTarHeaderTypeflag(hdr, f); err != nil {
return returnTarBytes(buf.Bytes()) return []byte(""), err
} }
if err := setTarHeaderFormat(hdr, f); err != nil { if err := setTarHeaderFormat(hdr, f); err != nil {
return returnTarBytes(buf.Bytes()) return []byte(""), err
} }
if err := tw.WriteHeader(hdr); err != nil { tf := &TarFile{
return returnTarBytes(buf.Bytes()) Hdr: hdr,
Body: filebody,
} }
if _, err := tw.Write(filebody); err != nil { tarFiles = append(tarFiles, tf)
return returnTarBytes(buf.Bytes())
} }
var buf bytes.Buffer
tw := tar.NewWriter(&buf)
defer tw.Close()
for _, tf := range tarFiles {
tw.WriteHeader(tf.Hdr)
tw.Write(tf.Body)
} }
return buf.Bytes(), nil return buf.Bytes(), nil
} }
// This is similar to TarBytes, but it returns a series of
// files instead of raw tar bytes. The advantage of this
// api is that it is cheaper in terms of cpu power to
// modify or check the files in the fuzzer with TarFiles()
// because it avoids creating a tar reader.
func (f *ConsumeFuzzer) TarFiles() ([]*TarFile, error) {
numberOfFiles, err := f.GetInt()
if err != nil {
return nil, err
}
var tarFiles []*TarFile
tarFiles = make([]*TarFile, 0)
const maxNoOfFiles = 100
for i := 0; i < numberOfFiles%maxNoOfFiles; i++ {
filename, err := f.getTarFilename()
if err != nil {
return tarFiles, err
}
filebody, err := f.createTarFileBody()
if err != nil {
return tarFiles, err
}
sec, err := f.GetInt()
if err != nil {
return tarFiles, err
}
nsec, err := f.GetInt()
if err != nil {
return tarFiles, err
}
hdr := &tar.Header{
Name: filename,
Size: int64(len(filebody)),
Mode: 0o600,
ModTime: time.Unix(int64(sec), int64(nsec)),
}
if err := setTarHeaderTypeflag(hdr, f); err != nil {
hdr.Typeflag = tar.TypeReg
}
if err := setTarHeaderFormat(hdr, f); err != nil {
return tarFiles, err // should not happend
}
tf := &TarFile{
Hdr: hdr,
Body: filebody,
}
tarFiles = append(tarFiles, tf)
}
return tarFiles, nil
}
// CreateFiles creates pseudo-random files in rootDir. // CreateFiles creates pseudo-random files in rootDir.
// It creates subdirs and places the files there. // It creates subdirs and places the files there.
// It is the callers responsibility to ensure that // It is the callers responsibility to ensure that
@ -767,10 +788,10 @@ func (f *ConsumeFuzzer) CreateFiles(rootDir string) error {
return errors.New("could not get fileName") return errors.New("could not get fileName")
} }
} }
fullFilePath, err := securejoin.SecureJoin(rootDir, fileName) if strings.Contains(fileName, "..") || (len(fileName) > 0 && fileName[0] == 47) || strings.Contains(fileName, "\\") {
if err != nil { continue
return err
} }
fullFilePath := filepath.Join(rootDir, fileName)
// Find the subdirectory of the file // Find the subdirectory of the file
if subDir := filepath.Dir(fileName); subDir != "" && subDir != "." { if subDir := filepath.Dir(fileName); subDir != "" && subDir != "." {
@ -778,20 +799,14 @@ func (f *ConsumeFuzzer) CreateFiles(rootDir string) error {
if strings.Contains(subDir, "../") || (len(subDir) > 0 && subDir[0] == 47) || strings.Contains(subDir, "\\") { if strings.Contains(subDir, "../") || (len(subDir) > 0 && subDir[0] == 47) || strings.Contains(subDir, "\\") {
continue continue
} }
dirPath, err := securejoin.SecureJoin(rootDir, subDir) dirPath := filepath.Join(rootDir, subDir)
if err != nil {
continue
}
if _, err := os.Stat(dirPath); os.IsNotExist(err) { if _, err := os.Stat(dirPath); os.IsNotExist(err) {
err2 := os.MkdirAll(dirPath, 0o777) err2 := os.MkdirAll(dirPath, 0o777)
if err2 != nil { if err2 != nil {
continue continue
} }
} }
fullFilePath, err = securejoin.SecureJoin(dirPath, fileName) fullFilePath = filepath.Join(dirPath, fileName)
if err != nil {
continue
}
} else { } else {
// Create symlink // Create symlink
createSymlink, err := f.GetBool() createSymlink, err := f.GetBool()

View File

@ -1,7 +1,3 @@
run:
skip-dirs:
- pkg/etw/sample
linters: linters:
enable: enable:
# style # style
@ -20,9 +16,13 @@ linters:
- gofmt # files are gofmt'ed - gofmt # files are gofmt'ed
- gosec # security - gosec # security
- nilerr # returns nil even with non-nil error - nilerr # returns nil even with non-nil error
- thelper # test helpers without t.Helper()
- unparam # unused function params - unparam # unused function params
issues: issues:
exclude-dirs:
- pkg/etw/sample
exclude-rules: exclude-rules:
# err is very often shadowed in nested scopes # err is very often shadowed in nested scopes
- linters: - linters:
@ -69,9 +69,7 @@ linters-settings:
# struct order is often for Win32 compat # struct order is often for Win32 compat
# also, ignore pointer bytes/GC issues for now until performance becomes an issue # also, ignore pointer bytes/GC issues for now until performance becomes an issue
- fieldalignment - fieldalignment
check-shadowing: true
nolintlint: nolintlint:
allow-leading-space: false
require-explanation: true require-explanation: true
require-specific: true require-specific: true
revive: revive:

View File

@ -10,14 +10,14 @@ import (
"io" "io"
"os" "os"
"runtime" "runtime"
"syscall"
"unicode/utf16" "unicode/utf16"
"github.com/Microsoft/go-winio/internal/fs"
"golang.org/x/sys/windows" "golang.org/x/sys/windows"
) )
//sys backupRead(h syscall.Handle, b []byte, bytesRead *uint32, abort bool, processSecurity bool, context *uintptr) (err error) = BackupRead //sys backupRead(h windows.Handle, b []byte, bytesRead *uint32, abort bool, processSecurity bool, context *uintptr) (err error) = BackupRead
//sys backupWrite(h syscall.Handle, b []byte, bytesWritten *uint32, abort bool, processSecurity bool, context *uintptr) (err error) = BackupWrite //sys backupWrite(h windows.Handle, b []byte, bytesWritten *uint32, abort bool, processSecurity bool, context *uintptr) (err error) = BackupWrite
const ( const (
BackupData = uint32(iota + 1) BackupData = uint32(iota + 1)
@ -104,7 +104,7 @@ func (r *BackupStreamReader) Next() (*BackupHeader, error) {
if err := binary.Read(r.r, binary.LittleEndian, name); err != nil { if err := binary.Read(r.r, binary.LittleEndian, name); err != nil {
return nil, err return nil, err
} }
hdr.Name = syscall.UTF16ToString(name) hdr.Name = windows.UTF16ToString(name)
} }
if wsi.StreamID == BackupSparseBlock { if wsi.StreamID == BackupSparseBlock {
if err := binary.Read(r.r, binary.LittleEndian, &hdr.Offset); err != nil { if err := binary.Read(r.r, binary.LittleEndian, &hdr.Offset); err != nil {
@ -205,7 +205,7 @@ func NewBackupFileReader(f *os.File, includeSecurity bool) *BackupFileReader {
// Read reads a backup stream from the file by calling the Win32 API BackupRead(). // Read reads a backup stream from the file by calling the Win32 API BackupRead().
func (r *BackupFileReader) Read(b []byte) (int, error) { func (r *BackupFileReader) Read(b []byte) (int, error) {
var bytesRead uint32 var bytesRead uint32
err := backupRead(syscall.Handle(r.f.Fd()), b, &bytesRead, false, r.includeSecurity, &r.ctx) err := backupRead(windows.Handle(r.f.Fd()), b, &bytesRead, false, r.includeSecurity, &r.ctx)
if err != nil { if err != nil {
return 0, &os.PathError{Op: "BackupRead", Path: r.f.Name(), Err: err} return 0, &os.PathError{Op: "BackupRead", Path: r.f.Name(), Err: err}
} }
@ -220,7 +220,7 @@ func (r *BackupFileReader) Read(b []byte) (int, error) {
// the underlying file. // the underlying file.
func (r *BackupFileReader) Close() error { func (r *BackupFileReader) Close() error {
if r.ctx != 0 { if r.ctx != 0 {
_ = backupRead(syscall.Handle(r.f.Fd()), nil, nil, true, false, &r.ctx) _ = backupRead(windows.Handle(r.f.Fd()), nil, nil, true, false, &r.ctx)
runtime.KeepAlive(r.f) runtime.KeepAlive(r.f)
r.ctx = 0 r.ctx = 0
} }
@ -244,7 +244,7 @@ func NewBackupFileWriter(f *os.File, includeSecurity bool) *BackupFileWriter {
// Write restores a portion of the file using the provided backup stream. // Write restores a portion of the file using the provided backup stream.
func (w *BackupFileWriter) Write(b []byte) (int, error) { func (w *BackupFileWriter) Write(b []byte) (int, error) {
var bytesWritten uint32 var bytesWritten uint32
err := backupWrite(syscall.Handle(w.f.Fd()), b, &bytesWritten, false, w.includeSecurity, &w.ctx) err := backupWrite(windows.Handle(w.f.Fd()), b, &bytesWritten, false, w.includeSecurity, &w.ctx)
if err != nil { if err != nil {
return 0, &os.PathError{Op: "BackupWrite", Path: w.f.Name(), Err: err} return 0, &os.PathError{Op: "BackupWrite", Path: w.f.Name(), Err: err}
} }
@ -259,7 +259,7 @@ func (w *BackupFileWriter) Write(b []byte) (int, error) {
// close the underlying file. // close the underlying file.
func (w *BackupFileWriter) Close() error { func (w *BackupFileWriter) Close() error {
if w.ctx != 0 { if w.ctx != 0 {
_ = backupWrite(syscall.Handle(w.f.Fd()), nil, nil, true, false, &w.ctx) _ = backupWrite(windows.Handle(w.f.Fd()), nil, nil, true, false, &w.ctx)
runtime.KeepAlive(w.f) runtime.KeepAlive(w.f)
w.ctx = 0 w.ctx = 0
} }
@ -271,17 +271,14 @@ func (w *BackupFileWriter) Close() error {
// //
// If the file opened was a directory, it cannot be used with Readdir(). // If the file opened was a directory, it cannot be used with Readdir().
func OpenForBackup(path string, access uint32, share uint32, createmode uint32) (*os.File, error) { func OpenForBackup(path string, access uint32, share uint32, createmode uint32) (*os.File, error) {
winPath, err := syscall.UTF16FromString(path) h, err := fs.CreateFile(path,
if err != nil { fs.AccessMask(access),
return nil, err fs.FileShareMode(share),
}
h, err := syscall.CreateFile(&winPath[0],
access,
share,
nil, nil,
createmode, fs.FileCreationDisposition(createmode),
syscall.FILE_FLAG_BACKUP_SEMANTICS|syscall.FILE_FLAG_OPEN_REPARSE_POINT, fs.FILE_FLAG_BACKUP_SEMANTICS|fs.FILE_FLAG_OPEN_REPARSE_POINT,
0) 0,
)
if err != nil { if err != nil {
err = &os.PathError{Op: "open", Path: path, Err: err} err = &os.PathError{Op: "open", Path: path, Err: err}
return nil, err return nil, err

View File

@ -11,7 +11,6 @@ import (
"path/filepath" "path/filepath"
"strconv" "strconv"
"strings" "strings"
"syscall"
"time" "time"
"github.com/Microsoft/go-winio" "github.com/Microsoft/go-winio"
@ -106,7 +105,7 @@ func BasicInfoHeader(name string, size int64, fileInfo *winio.FileBasicInfo) *ta
hdr.PAXRecords[hdrFileAttributes] = fmt.Sprintf("%d", fileInfo.FileAttributes) hdr.PAXRecords[hdrFileAttributes] = fmt.Sprintf("%d", fileInfo.FileAttributes)
hdr.PAXRecords[hdrCreationTime] = formatPAXTime(time.Unix(0, fileInfo.CreationTime.Nanoseconds())) hdr.PAXRecords[hdrCreationTime] = formatPAXTime(time.Unix(0, fileInfo.CreationTime.Nanoseconds()))
if (fileInfo.FileAttributes & syscall.FILE_ATTRIBUTE_DIRECTORY) != 0 { if (fileInfo.FileAttributes & windows.FILE_ATTRIBUTE_DIRECTORY) != 0 {
hdr.Mode |= cISDIR hdr.Mode |= cISDIR
hdr.Size = 0 hdr.Size = 0
hdr.Typeflag = tar.TypeDir hdr.Typeflag = tar.TypeDir
@ -378,7 +377,7 @@ func WriteTarFileFromBackupStream(t *tar.Writer, r io.Reader, name string, size
// WriteTarFileFromBackupStream. // WriteTarFileFromBackupStream.
func FileInfoFromHeader(hdr *tar.Header) (name string, size int64, fileInfo *winio.FileBasicInfo, err error) { func FileInfoFromHeader(hdr *tar.Header) (name string, size int64, fileInfo *winio.FileBasicInfo, err error) {
name = hdr.Name name = hdr.Name
if hdr.Typeflag == tar.TypeReg || hdr.Typeflag == tar.TypeRegA { if hdr.Typeflag == tar.TypeReg {
size = hdr.Size size = hdr.Size
} }
fileInfo = &winio.FileBasicInfo{ fileInfo = &winio.FileBasicInfo{
@ -396,7 +395,7 @@ func FileInfoFromHeader(hdr *tar.Header) (name string, size int64, fileInfo *win
fileInfo.FileAttributes = uint32(attr) fileInfo.FileAttributes = uint32(attr)
} else { } else {
if hdr.Typeflag == tar.TypeDir { if hdr.Typeflag == tar.TypeDir {
fileInfo.FileAttributes |= syscall.FILE_ATTRIBUTE_DIRECTORY fileInfo.FileAttributes |= windows.FILE_ATTRIBUTE_DIRECTORY
} }
} }
if creationTimeStr, ok := hdr.PAXRecords[hdrCreationTime]; ok { if creationTimeStr, ok := hdr.PAXRecords[hdrCreationTime]; ok {
@ -469,7 +468,7 @@ func WriteBackupStreamFromTarFile(w io.Writer, t *tar.Reader, hdr *tar.Header) (
} }
} }
if hdr.Typeflag == tar.TypeReg || hdr.Typeflag == tar.TypeRegA { if hdr.Typeflag == tar.TypeReg {
bhdr := winio.BackupHeader{ bhdr := winio.BackupHeader{
Id: winio.BackupData, Id: winio.BackupData,
Size: hdr.Size, Size: hdr.Size,

View File

@ -15,26 +15,11 @@ import (
"golang.org/x/sys/windows" "golang.org/x/sys/windows"
) )
//sys cancelIoEx(file syscall.Handle, o *syscall.Overlapped) (err error) = CancelIoEx //sys cancelIoEx(file windows.Handle, o *windows.Overlapped) (err error) = CancelIoEx
//sys createIoCompletionPort(file syscall.Handle, port syscall.Handle, key uintptr, threadCount uint32) (newport syscall.Handle, err error) = CreateIoCompletionPort //sys createIoCompletionPort(file windows.Handle, port windows.Handle, key uintptr, threadCount uint32) (newport windows.Handle, err error) = CreateIoCompletionPort
//sys getQueuedCompletionStatus(port syscall.Handle, bytes *uint32, key *uintptr, o **ioOperation, timeout uint32) (err error) = GetQueuedCompletionStatus //sys getQueuedCompletionStatus(port windows.Handle, bytes *uint32, key *uintptr, o **ioOperation, timeout uint32) (err error) = GetQueuedCompletionStatus
//sys setFileCompletionNotificationModes(h syscall.Handle, flags uint8) (err error) = SetFileCompletionNotificationModes //sys setFileCompletionNotificationModes(h windows.Handle, flags uint8) (err error) = SetFileCompletionNotificationModes
//sys wsaGetOverlappedResult(h syscall.Handle, o *syscall.Overlapped, bytes *uint32, wait bool, flags *uint32) (err error) = ws2_32.WSAGetOverlappedResult //sys wsaGetOverlappedResult(h windows.Handle, o *windows.Overlapped, bytes *uint32, wait bool, flags *uint32) (err error) = ws2_32.WSAGetOverlappedResult
type atomicBool int32
func (b *atomicBool) isSet() bool { return atomic.LoadInt32((*int32)(b)) != 0 }
func (b *atomicBool) setFalse() { atomic.StoreInt32((*int32)(b), 0) }
func (b *atomicBool) setTrue() { atomic.StoreInt32((*int32)(b), 1) }
//revive:disable-next-line:predeclared Keep "new" to maintain consistency with "atomic" pkg
func (b *atomicBool) swap(new bool) bool {
var newInt int32
if new {
newInt = 1
}
return atomic.SwapInt32((*int32)(b), newInt) == 1
}
var ( var (
ErrFileClosed = errors.New("file has already been closed") ErrFileClosed = errors.New("file has already been closed")
@ -50,7 +35,7 @@ func (*timeoutError) Temporary() bool { return true }
type timeoutChan chan struct{} type timeoutChan chan struct{}
var ioInitOnce sync.Once var ioInitOnce sync.Once
var ioCompletionPort syscall.Handle var ioCompletionPort windows.Handle
// ioResult contains the result of an asynchronous IO operation. // ioResult contains the result of an asynchronous IO operation.
type ioResult struct { type ioResult struct {
@ -60,12 +45,12 @@ type ioResult struct {
// ioOperation represents an outstanding asynchronous Win32 IO. // ioOperation represents an outstanding asynchronous Win32 IO.
type ioOperation struct { type ioOperation struct {
o syscall.Overlapped o windows.Overlapped
ch chan ioResult ch chan ioResult
} }
func initIO() { func initIO() {
h, err := createIoCompletionPort(syscall.InvalidHandle, 0, 0, 0xffffffff) h, err := createIoCompletionPort(windows.InvalidHandle, 0, 0, 0xffffffff)
if err != nil { if err != nil {
panic(err) panic(err)
} }
@ -76,10 +61,10 @@ func initIO() {
// win32File implements Reader, Writer, and Closer on a Win32 handle without blocking in a syscall. // win32File implements Reader, Writer, and Closer on a Win32 handle without blocking in a syscall.
// It takes ownership of this handle and will close it if it is garbage collected. // It takes ownership of this handle and will close it if it is garbage collected.
type win32File struct { type win32File struct {
handle syscall.Handle handle windows.Handle
wg sync.WaitGroup wg sync.WaitGroup
wgLock sync.RWMutex wgLock sync.RWMutex
closing atomicBool closing atomic.Bool
socket bool socket bool
readDeadline deadlineHandler readDeadline deadlineHandler
writeDeadline deadlineHandler writeDeadline deadlineHandler
@ -90,11 +75,11 @@ type deadlineHandler struct {
channel timeoutChan channel timeoutChan
channelLock sync.RWMutex channelLock sync.RWMutex
timer *time.Timer timer *time.Timer
timedout atomicBool timedout atomic.Bool
} }
// makeWin32File makes a new win32File from an existing file handle. // makeWin32File makes a new win32File from an existing file handle.
func makeWin32File(h syscall.Handle) (*win32File, error) { func makeWin32File(h windows.Handle) (*win32File, error) {
f := &win32File{handle: h} f := &win32File{handle: h}
ioInitOnce.Do(initIO) ioInitOnce.Do(initIO)
_, err := createIoCompletionPort(h, ioCompletionPort, 0, 0xffffffff) _, err := createIoCompletionPort(h, ioCompletionPort, 0, 0xffffffff)
@ -110,7 +95,12 @@ func makeWin32File(h syscall.Handle) (*win32File, error) {
return f, nil return f, nil
} }
// Deprecated: use NewOpenFile instead.
func MakeOpenFile(h syscall.Handle) (io.ReadWriteCloser, error) { func MakeOpenFile(h syscall.Handle) (io.ReadWriteCloser, error) {
return NewOpenFile(windows.Handle(h))
}
func NewOpenFile(h windows.Handle) (io.ReadWriteCloser, error) {
// If we return the result of makeWin32File directly, it can result in an // If we return the result of makeWin32File directly, it can result in an
// interface-wrapped nil, rather than a nil interface value. // interface-wrapped nil, rather than a nil interface value.
f, err := makeWin32File(h) f, err := makeWin32File(h)
@ -124,13 +114,13 @@ func MakeOpenFile(h syscall.Handle) (io.ReadWriteCloser, error) {
func (f *win32File) closeHandle() { func (f *win32File) closeHandle() {
f.wgLock.Lock() f.wgLock.Lock()
// Atomically set that we are closing, releasing the resources only once. // Atomically set that we are closing, releasing the resources only once.
if !f.closing.swap(true) { if !f.closing.Swap(true) {
f.wgLock.Unlock() f.wgLock.Unlock()
// cancel all IO and wait for it to complete // cancel all IO and wait for it to complete
_ = cancelIoEx(f.handle, nil) _ = cancelIoEx(f.handle, nil)
f.wg.Wait() f.wg.Wait()
// at this point, no new IO can start // at this point, no new IO can start
syscall.Close(f.handle) windows.Close(f.handle)
f.handle = 0 f.handle = 0
} else { } else {
f.wgLock.Unlock() f.wgLock.Unlock()
@ -145,14 +135,14 @@ func (f *win32File) Close() error {
// IsClosed checks if the file has been closed. // IsClosed checks if the file has been closed.
func (f *win32File) IsClosed() bool { func (f *win32File) IsClosed() bool {
return f.closing.isSet() return f.closing.Load()
} }
// prepareIO prepares for a new IO operation. // prepareIO prepares for a new IO operation.
// The caller must call f.wg.Done() when the IO is finished, prior to Close() returning. // The caller must call f.wg.Done() when the IO is finished, prior to Close() returning.
func (f *win32File) prepareIO() (*ioOperation, error) { func (f *win32File) prepareIO() (*ioOperation, error) {
f.wgLock.RLock() f.wgLock.RLock()
if f.closing.isSet() { if f.closing.Load() {
f.wgLock.RUnlock() f.wgLock.RUnlock()
return nil, ErrFileClosed return nil, ErrFileClosed
} }
@ -164,12 +154,12 @@ func (f *win32File) prepareIO() (*ioOperation, error) {
} }
// ioCompletionProcessor processes completed async IOs forever. // ioCompletionProcessor processes completed async IOs forever.
func ioCompletionProcessor(h syscall.Handle) { func ioCompletionProcessor(h windows.Handle) {
for { for {
var bytes uint32 var bytes uint32
var key uintptr var key uintptr
var op *ioOperation var op *ioOperation
err := getQueuedCompletionStatus(h, &bytes, &key, &op, syscall.INFINITE) err := getQueuedCompletionStatus(h, &bytes, &key, &op, windows.INFINITE)
if op == nil { if op == nil {
panic(err) panic(err)
} }
@ -182,11 +172,11 @@ func ioCompletionProcessor(h syscall.Handle) {
// asyncIO processes the return value from ReadFile or WriteFile, blocking until // asyncIO processes the return value from ReadFile or WriteFile, blocking until
// the operation has actually completed. // the operation has actually completed.
func (f *win32File) asyncIO(c *ioOperation, d *deadlineHandler, bytes uint32, err error) (int, error) { func (f *win32File) asyncIO(c *ioOperation, d *deadlineHandler, bytes uint32, err error) (int, error) {
if err != syscall.ERROR_IO_PENDING { //nolint:errorlint // err is Errno if err != windows.ERROR_IO_PENDING { //nolint:errorlint // err is Errno
return int(bytes), err return int(bytes), err
} }
if f.closing.isSet() { if f.closing.Load() {
_ = cancelIoEx(f.handle, &c.o) _ = cancelIoEx(f.handle, &c.o)
} }
@ -201,8 +191,8 @@ func (f *win32File) asyncIO(c *ioOperation, d *deadlineHandler, bytes uint32, er
select { select {
case r = <-c.ch: case r = <-c.ch:
err = r.err err = r.err
if err == syscall.ERROR_OPERATION_ABORTED { //nolint:errorlint // err is Errno if err == windows.ERROR_OPERATION_ABORTED { //nolint:errorlint // err is Errno
if f.closing.isSet() { if f.closing.Load() {
err = ErrFileClosed err = ErrFileClosed
} }
} else if err != nil && f.socket { } else if err != nil && f.socket {
@ -214,7 +204,7 @@ func (f *win32File) asyncIO(c *ioOperation, d *deadlineHandler, bytes uint32, er
_ = cancelIoEx(f.handle, &c.o) _ = cancelIoEx(f.handle, &c.o)
r = <-c.ch r = <-c.ch
err = r.err err = r.err
if err == syscall.ERROR_OPERATION_ABORTED { //nolint:errorlint // err is Errno if err == windows.ERROR_OPERATION_ABORTED { //nolint:errorlint // err is Errno
err = ErrTimeout err = ErrTimeout
} }
} }
@ -235,23 +225,22 @@ func (f *win32File) Read(b []byte) (int, error) {
} }
defer f.wg.Done() defer f.wg.Done()
if f.readDeadline.timedout.isSet() { if f.readDeadline.timedout.Load() {
return 0, ErrTimeout return 0, ErrTimeout
} }
var bytes uint32 var bytes uint32
err = syscall.ReadFile(f.handle, b, &bytes, &c.o) err = windows.ReadFile(f.handle, b, &bytes, &c.o)
n, err := f.asyncIO(c, &f.readDeadline, bytes, err) n, err := f.asyncIO(c, &f.readDeadline, bytes, err)
runtime.KeepAlive(b) runtime.KeepAlive(b)
// Handle EOF conditions. // Handle EOF conditions.
if err == nil && n == 0 && len(b) != 0 { if err == nil && n == 0 && len(b) != 0 {
return 0, io.EOF return 0, io.EOF
} else if err == syscall.ERROR_BROKEN_PIPE { //nolint:errorlint // err is Errno } else if err == windows.ERROR_BROKEN_PIPE { //nolint:errorlint // err is Errno
return 0, io.EOF return 0, io.EOF
} else {
return n, err
} }
return n, err
} }
// Write writes to a file handle. // Write writes to a file handle.
@ -262,12 +251,12 @@ func (f *win32File) Write(b []byte) (int, error) {
} }
defer f.wg.Done() defer f.wg.Done()
if f.writeDeadline.timedout.isSet() { if f.writeDeadline.timedout.Load() {
return 0, ErrTimeout return 0, ErrTimeout
} }
var bytes uint32 var bytes uint32
err = syscall.WriteFile(f.handle, b, &bytes, &c.o) err = windows.WriteFile(f.handle, b, &bytes, &c.o)
n, err := f.asyncIO(c, &f.writeDeadline, bytes, err) n, err := f.asyncIO(c, &f.writeDeadline, bytes, err)
runtime.KeepAlive(b) runtime.KeepAlive(b)
return n, err return n, err
@ -282,7 +271,7 @@ func (f *win32File) SetWriteDeadline(deadline time.Time) error {
} }
func (f *win32File) Flush() error { func (f *win32File) Flush() error {
return syscall.FlushFileBuffers(f.handle) return windows.FlushFileBuffers(f.handle)
} }
func (f *win32File) Fd() uintptr { func (f *win32File) Fd() uintptr {
@ -299,7 +288,7 @@ func (d *deadlineHandler) set(deadline time.Time) error {
} }
d.timer = nil d.timer = nil
} }
d.timedout.setFalse() d.timedout.Store(false)
select { select {
case <-d.channel: case <-d.channel:
@ -314,7 +303,7 @@ func (d *deadlineHandler) set(deadline time.Time) error {
} }
timeoutIO := func() { timeoutIO := func() {
d.timedout.setTrue() d.timedout.Store(true)
close(d.channel) close(d.channel)
} }

View File

@ -18,9 +18,18 @@ type FileBasicInfo struct {
_ uint32 // padding _ uint32 // padding
} }
// alignedFileBasicInfo is a FileBasicInfo, but aligned to uint64 by containing
// uint64 rather than windows.Filetime. Filetime contains two uint32s. uint64
// alignment is necessary to pass this as FILE_BASIC_INFO.
type alignedFileBasicInfo struct {
CreationTime, LastAccessTime, LastWriteTime, ChangeTime uint64
FileAttributes uint32
_ uint32 // padding
}
// GetFileBasicInfo retrieves times and attributes for a file. // GetFileBasicInfo retrieves times and attributes for a file.
func GetFileBasicInfo(f *os.File) (*FileBasicInfo, error) { func GetFileBasicInfo(f *os.File) (*FileBasicInfo, error) {
bi := &FileBasicInfo{} bi := &alignedFileBasicInfo{}
if err := windows.GetFileInformationByHandleEx( if err := windows.GetFileInformationByHandleEx(
windows.Handle(f.Fd()), windows.Handle(f.Fd()),
windows.FileBasicInfo, windows.FileBasicInfo,
@ -30,16 +39,21 @@ func GetFileBasicInfo(f *os.File) (*FileBasicInfo, error) {
return nil, &os.PathError{Op: "GetFileInformationByHandleEx", Path: f.Name(), Err: err} return nil, &os.PathError{Op: "GetFileInformationByHandleEx", Path: f.Name(), Err: err}
} }
runtime.KeepAlive(f) runtime.KeepAlive(f)
return bi, nil // Reinterpret the alignedFileBasicInfo as a FileBasicInfo so it matches the
// public API of this module. The data may be unnecessarily aligned.
return (*FileBasicInfo)(unsafe.Pointer(bi)), nil
} }
// SetFileBasicInfo sets times and attributes for a file. // SetFileBasicInfo sets times and attributes for a file.
func SetFileBasicInfo(f *os.File, bi *FileBasicInfo) error { func SetFileBasicInfo(f *os.File, bi *FileBasicInfo) error {
// Create an alignedFileBasicInfo based on a FileBasicInfo. The copy is
// suitable to pass to GetFileInformationByHandleEx.
biAligned := *(*alignedFileBasicInfo)(unsafe.Pointer(bi))
if err := windows.SetFileInformationByHandle( if err := windows.SetFileInformationByHandle(
windows.Handle(f.Fd()), windows.Handle(f.Fd()),
windows.FileBasicInfo, windows.FileBasicInfo,
(*byte)(unsafe.Pointer(bi)), (*byte)(unsafe.Pointer(&biAligned)),
uint32(unsafe.Sizeof(*bi)), uint32(unsafe.Sizeof(biAligned)),
); err != nil { ); err != nil {
return &os.PathError{Op: "SetFileInformationByHandle", Path: f.Name(), Err: err} return &os.PathError{Op: "SetFileInformationByHandle", Path: f.Name(), Err: err}
} }

View File

@ -10,7 +10,6 @@ import (
"io" "io"
"net" "net"
"os" "os"
"syscall"
"time" "time"
"unsafe" "unsafe"
@ -181,13 +180,13 @@ type HvsockConn struct {
var _ net.Conn = &HvsockConn{} var _ net.Conn = &HvsockConn{}
func newHVSocket() (*win32File, error) { func newHVSocket() (*win32File, error) {
fd, err := syscall.Socket(afHVSock, syscall.SOCK_STREAM, 1) fd, err := windows.Socket(afHVSock, windows.SOCK_STREAM, 1)
if err != nil { if err != nil {
return nil, os.NewSyscallError("socket", err) return nil, os.NewSyscallError("socket", err)
} }
f, err := makeWin32File(fd) f, err := makeWin32File(fd)
if err != nil { if err != nil {
syscall.Close(fd) windows.Close(fd)
return nil, err return nil, err
} }
f.socket = true f.socket = true
@ -197,16 +196,24 @@ func newHVSocket() (*win32File, error) {
// ListenHvsock listens for connections on the specified hvsock address. // ListenHvsock listens for connections on the specified hvsock address.
func ListenHvsock(addr *HvsockAddr) (_ *HvsockListener, err error) { func ListenHvsock(addr *HvsockAddr) (_ *HvsockListener, err error) {
l := &HvsockListener{addr: *addr} l := &HvsockListener{addr: *addr}
sock, err := newHVSocket()
var sock *win32File
sock, err = newHVSocket()
if err != nil { if err != nil {
return nil, l.opErr("listen", err) return nil, l.opErr("listen", err)
} }
defer func() {
if err != nil {
_ = sock.Close()
}
}()
sa := addr.raw() sa := addr.raw()
err = socket.Bind(windows.Handle(sock.handle), &sa) err = socket.Bind(sock.handle, &sa)
if err != nil { if err != nil {
return nil, l.opErr("listen", os.NewSyscallError("socket", err)) return nil, l.opErr("listen", os.NewSyscallError("socket", err))
} }
err = syscall.Listen(sock.handle, 16) err = windows.Listen(sock.handle, 16)
if err != nil { if err != nil {
return nil, l.opErr("listen", os.NewSyscallError("listen", err)) return nil, l.opErr("listen", os.NewSyscallError("listen", err))
} }
@ -246,7 +253,7 @@ func (l *HvsockListener) Accept() (_ net.Conn, err error) {
var addrbuf [addrlen * 2]byte var addrbuf [addrlen * 2]byte
var bytes uint32 var bytes uint32
err = syscall.AcceptEx(l.sock.handle, sock.handle, &addrbuf[0], 0 /* rxdatalen */, addrlen, addrlen, &bytes, &c.o) err = windows.AcceptEx(l.sock.handle, sock.handle, &addrbuf[0], 0 /* rxdatalen */, addrlen, addrlen, &bytes, &c.o)
if _, err = l.sock.asyncIO(c, nil, bytes, err); err != nil { if _, err = l.sock.asyncIO(c, nil, bytes, err); err != nil {
return nil, l.opErr("accept", os.NewSyscallError("acceptex", err)) return nil, l.opErr("accept", os.NewSyscallError("acceptex", err))
} }
@ -263,7 +270,7 @@ func (l *HvsockListener) Accept() (_ net.Conn, err error) {
conn.remote.fromRaw((*rawHvsockAddr)(unsafe.Pointer(&addrbuf[addrlen]))) conn.remote.fromRaw((*rawHvsockAddr)(unsafe.Pointer(&addrbuf[addrlen])))
// initialize the accepted socket and update its properties with those of the listening socket // initialize the accepted socket and update its properties with those of the listening socket
if err = windows.Setsockopt(windows.Handle(sock.handle), if err = windows.Setsockopt(sock.handle,
windows.SOL_SOCKET, windows.SO_UPDATE_ACCEPT_CONTEXT, windows.SOL_SOCKET, windows.SO_UPDATE_ACCEPT_CONTEXT,
(*byte)(unsafe.Pointer(&l.sock.handle)), int32(unsafe.Sizeof(l.sock.handle))); err != nil { (*byte)(unsafe.Pointer(&l.sock.handle)), int32(unsafe.Sizeof(l.sock.handle))); err != nil {
return nil, conn.opErr("accept", os.NewSyscallError("setsockopt", err)) return nil, conn.opErr("accept", os.NewSyscallError("setsockopt", err))
@ -334,7 +341,7 @@ func (d *HvsockDialer) Dial(ctx context.Context, addr *HvsockAddr) (conn *Hvsock
}() }()
sa := addr.raw() sa := addr.raw()
err = socket.Bind(windows.Handle(sock.handle), &sa) err = socket.Bind(sock.handle, &sa)
if err != nil { if err != nil {
return nil, conn.opErr(op, os.NewSyscallError("bind", err)) return nil, conn.opErr(op, os.NewSyscallError("bind", err))
} }
@ -347,7 +354,7 @@ func (d *HvsockDialer) Dial(ctx context.Context, addr *HvsockAddr) (conn *Hvsock
var bytes uint32 var bytes uint32
for i := uint(0); i <= d.Retries; i++ { for i := uint(0); i <= d.Retries; i++ {
err = socket.ConnectEx( err = socket.ConnectEx(
windows.Handle(sock.handle), sock.handle,
&sa, &sa,
nil, // sendBuf nil, // sendBuf
0, // sendDataLen 0, // sendDataLen
@ -367,7 +374,7 @@ func (d *HvsockDialer) Dial(ctx context.Context, addr *HvsockAddr) (conn *Hvsock
// update the connection properties, so shutdown can be used // update the connection properties, so shutdown can be used
if err = windows.Setsockopt( if err = windows.Setsockopt(
windows.Handle(sock.handle), sock.handle,
windows.SOL_SOCKET, windows.SOL_SOCKET,
windows.SO_UPDATE_CONNECT_CONTEXT, windows.SO_UPDATE_CONNECT_CONTEXT,
nil, // optvalue nil, // optvalue
@ -378,7 +385,7 @@ func (d *HvsockDialer) Dial(ctx context.Context, addr *HvsockAddr) (conn *Hvsock
// get the local name // get the local name
var sal rawHvsockAddr var sal rawHvsockAddr
err = socket.GetSockName(windows.Handle(sock.handle), &sal) err = socket.GetSockName(sock.handle, &sal)
if err != nil { if err != nil {
return nil, conn.opErr(op, os.NewSyscallError("getsockname", err)) return nil, conn.opErr(op, os.NewSyscallError("getsockname", err))
} }
@ -421,7 +428,7 @@ func (d *HvsockDialer) redialWait(ctx context.Context) (err error) {
return ctx.Err() return ctx.Err()
} }
// assumes error is a plain, unwrapped syscall.Errno provided by direct syscall. // assumes error is a plain, unwrapped windows.Errno provided by direct syscall.
func canRedial(err error) bool { func canRedial(err error) bool {
//nolint:errorlint // guaranteed to be an Errno //nolint:errorlint // guaranteed to be an Errno
switch err { switch err {
@ -447,9 +454,9 @@ func (conn *HvsockConn) Read(b []byte) (int, error) {
return 0, conn.opErr("read", err) return 0, conn.opErr("read", err)
} }
defer conn.sock.wg.Done() defer conn.sock.wg.Done()
buf := syscall.WSABuf{Buf: &b[0], Len: uint32(len(b))} buf := windows.WSABuf{Buf: &b[0], Len: uint32(len(b))}
var flags, bytes uint32 var flags, bytes uint32
err = syscall.WSARecv(conn.sock.handle, &buf, 1, &bytes, &flags, &c.o, nil) err = windows.WSARecv(conn.sock.handle, &buf, 1, &bytes, &flags, &c.o, nil)
n, err := conn.sock.asyncIO(c, &conn.sock.readDeadline, bytes, err) n, err := conn.sock.asyncIO(c, &conn.sock.readDeadline, bytes, err)
if err != nil { if err != nil {
var eno windows.Errno var eno windows.Errno
@ -482,9 +489,9 @@ func (conn *HvsockConn) write(b []byte) (int, error) {
return 0, conn.opErr("write", err) return 0, conn.opErr("write", err)
} }
defer conn.sock.wg.Done() defer conn.sock.wg.Done()
buf := syscall.WSABuf{Buf: &b[0], Len: uint32(len(b))} buf := windows.WSABuf{Buf: &b[0], Len: uint32(len(b))}
var bytes uint32 var bytes uint32
err = syscall.WSASend(conn.sock.handle, &buf, 1, &bytes, 0, &c.o, nil) err = windows.WSASend(conn.sock.handle, &buf, 1, &bytes, 0, &c.o, nil)
n, err := conn.sock.asyncIO(c, &conn.sock.writeDeadline, bytes, err) n, err := conn.sock.asyncIO(c, &conn.sock.writeDeadline, bytes, err)
if err != nil { if err != nil {
var eno windows.Errno var eno windows.Errno
@ -511,7 +518,7 @@ func (conn *HvsockConn) shutdown(how int) error {
return socket.ErrSocketClosed return socket.ErrSocketClosed
} }
err := syscall.Shutdown(conn.sock.handle, how) err := windows.Shutdown(conn.sock.handle, how)
if err != nil { if err != nil {
// If the connection was closed, shutdowns fail with "not connected" // If the connection was closed, shutdowns fail with "not connected"
if errors.Is(err, windows.WSAENOTCONN) || if errors.Is(err, windows.WSAENOTCONN) ||
@ -525,7 +532,7 @@ func (conn *HvsockConn) shutdown(how int) error {
// CloseRead shuts down the read end of the socket, preventing future read operations. // CloseRead shuts down the read end of the socket, preventing future read operations.
func (conn *HvsockConn) CloseRead() error { func (conn *HvsockConn) CloseRead() error {
err := conn.shutdown(syscall.SHUT_RD) err := conn.shutdown(windows.SHUT_RD)
if err != nil { if err != nil {
return conn.opErr("closeread", err) return conn.opErr("closeread", err)
} }
@ -535,7 +542,7 @@ func (conn *HvsockConn) CloseRead() error {
// CloseWrite shuts down the write end of the socket, preventing future write operations and // CloseWrite shuts down the write end of the socket, preventing future write operations and
// notifying the other endpoint that no more data will be written. // notifying the other endpoint that no more data will be written.
func (conn *HvsockConn) CloseWrite() error { func (conn *HvsockConn) CloseWrite() error {
err := conn.shutdown(syscall.SHUT_WR) err := conn.shutdown(windows.SHUT_WR)
if err != nil { if err != nil {
return conn.opErr("closewrite", err) return conn.opErr("closewrite", err)
} }

View File

@ -11,12 +11,14 @@ import (
//go:generate go run github.com/Microsoft/go-winio/tools/mkwinsyscall -output zsyscall_windows.go fs.go //go:generate go run github.com/Microsoft/go-winio/tools/mkwinsyscall -output zsyscall_windows.go fs.go
// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew // https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew
//sys CreateFile(name string, access AccessMask, mode FileShareMode, sa *syscall.SecurityAttributes, createmode FileCreationDisposition, attrs FileFlagOrAttribute, templatefile windows.Handle) (handle windows.Handle, err error) [failretval==windows.InvalidHandle] = CreateFileW //sys CreateFile(name string, access AccessMask, mode FileShareMode, sa *windows.SecurityAttributes, createmode FileCreationDisposition, attrs FileFlagOrAttribute, templatefile windows.Handle) (handle windows.Handle, err error) [failretval==windows.InvalidHandle] = CreateFileW
const NullHandle windows.Handle = 0 const NullHandle windows.Handle = 0
// AccessMask defines standard, specific, and generic rights. // AccessMask defines standard, specific, and generic rights.
// //
// Used with CreateFile and NtCreateFile (and co.).
//
// Bitmask: // Bitmask:
// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 // 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 // 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
@ -47,6 +49,12 @@ const (
// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew#parameters // https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew#parameters
FILE_ANY_ACCESS AccessMask = 0 FILE_ANY_ACCESS AccessMask = 0
GENERIC_READ AccessMask = 0x8000_0000
GENERIC_WRITE AccessMask = 0x4000_0000
GENERIC_EXECUTE AccessMask = 0x2000_0000
GENERIC_ALL AccessMask = 0x1000_0000
ACCESS_SYSTEM_SECURITY AccessMask = 0x0100_0000
// Specific Object Access // Specific Object Access
// from ntioapi.h // from ntioapi.h
@ -124,14 +132,32 @@ const (
TRUNCATE_EXISTING FileCreationDisposition = 0x05 TRUNCATE_EXISTING FileCreationDisposition = 0x05
) )
// Create disposition values for NtCreate*
type NTFileCreationDisposition uint32
//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API.
const (
// From ntioapi.h
FILE_SUPERSEDE NTFileCreationDisposition = 0x00
FILE_OPEN NTFileCreationDisposition = 0x01
FILE_CREATE NTFileCreationDisposition = 0x02
FILE_OPEN_IF NTFileCreationDisposition = 0x03
FILE_OVERWRITE NTFileCreationDisposition = 0x04
FILE_OVERWRITE_IF NTFileCreationDisposition = 0x05
FILE_MAXIMUM_DISPOSITION NTFileCreationDisposition = 0x05
)
// CreateFile and co. take flags or attributes together as one parameter. // CreateFile and co. take flags or attributes together as one parameter.
// Define alias until we can use generics to allow both // Define alias until we can use generics to allow both
//
// https://learn.microsoft.com/en-us/windows/win32/fileio/file-attribute-constants // https://learn.microsoft.com/en-us/windows/win32/fileio/file-attribute-constants
type FileFlagOrAttribute uint32 type FileFlagOrAttribute uint32
//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API. //nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API.
const ( // from winnt.h const (
// from winnt.h
FILE_FLAG_WRITE_THROUGH FileFlagOrAttribute = 0x8000_0000 FILE_FLAG_WRITE_THROUGH FileFlagOrAttribute = 0x8000_0000
FILE_FLAG_OVERLAPPED FileFlagOrAttribute = 0x4000_0000 FILE_FLAG_OVERLAPPED FileFlagOrAttribute = 0x4000_0000
FILE_FLAG_NO_BUFFERING FileFlagOrAttribute = 0x2000_0000 FILE_FLAG_NO_BUFFERING FileFlagOrAttribute = 0x2000_0000
@ -145,17 +171,51 @@ const ( // from winnt.h
FILE_FLAG_FIRST_PIPE_INSTANCE FileFlagOrAttribute = 0x0008_0000 FILE_FLAG_FIRST_PIPE_INSTANCE FileFlagOrAttribute = 0x0008_0000
) )
// NtCreate* functions take a dedicated CreateOptions parameter.
//
// https://learn.microsoft.com/en-us/windows/win32/api/Winternl/nf-winternl-ntcreatefile
//
// https://learn.microsoft.com/en-us/windows/win32/devnotes/nt-create-named-pipe-file
type NTCreateOptions uint32
//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API.
const (
// From ntioapi.h
FILE_DIRECTORY_FILE NTCreateOptions = 0x0000_0001
FILE_WRITE_THROUGH NTCreateOptions = 0x0000_0002
FILE_SEQUENTIAL_ONLY NTCreateOptions = 0x0000_0004
FILE_NO_INTERMEDIATE_BUFFERING NTCreateOptions = 0x0000_0008
FILE_SYNCHRONOUS_IO_ALERT NTCreateOptions = 0x0000_0010
FILE_SYNCHRONOUS_IO_NONALERT NTCreateOptions = 0x0000_0020
FILE_NON_DIRECTORY_FILE NTCreateOptions = 0x0000_0040
FILE_CREATE_TREE_CONNECTION NTCreateOptions = 0x0000_0080
FILE_COMPLETE_IF_OPLOCKED NTCreateOptions = 0x0000_0100
FILE_NO_EA_KNOWLEDGE NTCreateOptions = 0x0000_0200
FILE_DISABLE_TUNNELING NTCreateOptions = 0x0000_0400
FILE_RANDOM_ACCESS NTCreateOptions = 0x0000_0800
FILE_DELETE_ON_CLOSE NTCreateOptions = 0x0000_1000
FILE_OPEN_BY_FILE_ID NTCreateOptions = 0x0000_2000
FILE_OPEN_FOR_BACKUP_INTENT NTCreateOptions = 0x0000_4000
FILE_NO_COMPRESSION NTCreateOptions = 0x0000_8000
)
type FileSQSFlag = FileFlagOrAttribute type FileSQSFlag = FileFlagOrAttribute
//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API. //nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API.
const ( // from winbase.h const (
// from winbase.h
SECURITY_ANONYMOUS FileSQSFlag = FileSQSFlag(SecurityAnonymous << 16) SECURITY_ANONYMOUS FileSQSFlag = FileSQSFlag(SecurityAnonymous << 16)
SECURITY_IDENTIFICATION FileSQSFlag = FileSQSFlag(SecurityIdentification << 16) SECURITY_IDENTIFICATION FileSQSFlag = FileSQSFlag(SecurityIdentification << 16)
SECURITY_IMPERSONATION FileSQSFlag = FileSQSFlag(SecurityImpersonation << 16) SECURITY_IMPERSONATION FileSQSFlag = FileSQSFlag(SecurityImpersonation << 16)
SECURITY_DELEGATION FileSQSFlag = FileSQSFlag(SecurityDelegation << 16) SECURITY_DELEGATION FileSQSFlag = FileSQSFlag(SecurityDelegation << 16)
SECURITY_SQOS_PRESENT FileSQSFlag = 0x00100000 SECURITY_SQOS_PRESENT FileSQSFlag = 0x0010_0000
SECURITY_VALID_SQOS_FLAGS FileSQSFlag = 0x001F0000 SECURITY_VALID_SQOS_FLAGS FileSQSFlag = 0x001F_0000
) )
// GetFinalPathNameByHandle flags // GetFinalPathNameByHandle flags

View File

@ -33,9 +33,6 @@ func errnoErr(e syscall.Errno) error {
case errnoERROR_IO_PENDING: case errnoERROR_IO_PENDING:
return errERROR_IO_PENDING return errERROR_IO_PENDING
} }
// TODO: add more here, after collecting data on the common
// error values see on Windows. (perhaps when running
// all.bat?)
return e return e
} }
@ -45,7 +42,7 @@ var (
procCreateFileW = modkernel32.NewProc("CreateFileW") procCreateFileW = modkernel32.NewProc("CreateFileW")
) )
func CreateFile(name string, access AccessMask, mode FileShareMode, sa *syscall.SecurityAttributes, createmode FileCreationDisposition, attrs FileFlagOrAttribute, templatefile windows.Handle) (handle windows.Handle, err error) { func CreateFile(name string, access AccessMask, mode FileShareMode, sa *windows.SecurityAttributes, createmode FileCreationDisposition, attrs FileFlagOrAttribute, templatefile windows.Handle) (handle windows.Handle, err error) {
var _p0 *uint16 var _p0 *uint16
_p0, err = syscall.UTF16PtrFromString(name) _p0, err = syscall.UTF16PtrFromString(name)
if err != nil { if err != nil {
@ -54,8 +51,8 @@ func CreateFile(name string, access AccessMask, mode FileShareMode, sa *syscall.
return _CreateFile(_p0, access, mode, sa, createmode, attrs, templatefile) return _CreateFile(_p0, access, mode, sa, createmode, attrs, templatefile)
} }
func _CreateFile(name *uint16, access AccessMask, mode FileShareMode, sa *syscall.SecurityAttributes, createmode FileCreationDisposition, attrs FileFlagOrAttribute, templatefile windows.Handle) (handle windows.Handle, err error) { func _CreateFile(name *uint16, access AccessMask, mode FileShareMode, sa *windows.SecurityAttributes, createmode FileCreationDisposition, attrs FileFlagOrAttribute, templatefile windows.Handle) (handle windows.Handle, err error) {
r0, _, e1 := syscall.Syscall9(procCreateFileW.Addr(), 7, uintptr(unsafe.Pointer(name)), uintptr(access), uintptr(mode), uintptr(unsafe.Pointer(sa)), uintptr(createmode), uintptr(attrs), uintptr(templatefile), 0, 0) r0, _, e1 := syscall.SyscallN(procCreateFileW.Addr(), uintptr(unsafe.Pointer(name)), uintptr(access), uintptr(mode), uintptr(unsafe.Pointer(sa)), uintptr(createmode), uintptr(attrs), uintptr(templatefile))
handle = windows.Handle(r0) handle = windows.Handle(r0)
if handle == windows.InvalidHandle { if handle == windows.InvalidHandle {
err = errnoErr(e1) err = errnoErr(e1)

View File

@ -156,9 +156,7 @@ func connectEx(
bytesSent *uint32, bytesSent *uint32,
overlapped *windows.Overlapped, overlapped *windows.Overlapped,
) (err error) { ) (err error) {
// todo: after upgrading to 1.18, switch from syscall.Syscall9 to syscall.SyscallN r1, _, e1 := syscall.SyscallN(connectExFunc.addr,
r1, _, e1 := syscall.Syscall9(connectExFunc.addr,
7,
uintptr(s), uintptr(s),
uintptr(name), uintptr(name),
uintptr(namelen), uintptr(namelen),
@ -166,8 +164,8 @@ func connectEx(
uintptr(sendDataLen), uintptr(sendDataLen),
uintptr(unsafe.Pointer(bytesSent)), uintptr(unsafe.Pointer(bytesSent)),
uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(overlapped)),
0, )
0)
if r1 == 0 { if r1 == 0 {
if e1 != 0 { if e1 != 0 {
err = error(e1) err = error(e1)

View File

@ -33,9 +33,6 @@ func errnoErr(e syscall.Errno) error {
case errnoERROR_IO_PENDING: case errnoERROR_IO_PENDING:
return errERROR_IO_PENDING return errERROR_IO_PENDING
} }
// TODO: add more here, after collecting data on the common
// error values see on Windows. (perhaps when running
// all.bat?)
return e return e
} }
@ -48,7 +45,7 @@ var (
) )
func bind(s windows.Handle, name unsafe.Pointer, namelen int32) (err error) { func bind(s windows.Handle, name unsafe.Pointer, namelen int32) (err error) {
r1, _, e1 := syscall.Syscall(procbind.Addr(), 3, uintptr(s), uintptr(name), uintptr(namelen)) r1, _, e1 := syscall.SyscallN(procbind.Addr(), uintptr(s), uintptr(name), uintptr(namelen))
if r1 == socketError { if r1 == socketError {
err = errnoErr(e1) err = errnoErr(e1)
} }
@ -56,7 +53,7 @@ func bind(s windows.Handle, name unsafe.Pointer, namelen int32) (err error) {
} }
func getpeername(s windows.Handle, name unsafe.Pointer, namelen *int32) (err error) { func getpeername(s windows.Handle, name unsafe.Pointer, namelen *int32) (err error) {
r1, _, e1 := syscall.Syscall(procgetpeername.Addr(), 3, uintptr(s), uintptr(name), uintptr(unsafe.Pointer(namelen))) r1, _, e1 := syscall.SyscallN(procgetpeername.Addr(), uintptr(s), uintptr(name), uintptr(unsafe.Pointer(namelen)))
if r1 == socketError { if r1 == socketError {
err = errnoErr(e1) err = errnoErr(e1)
} }
@ -64,7 +61,7 @@ func getpeername(s windows.Handle, name unsafe.Pointer, namelen *int32) (err err
} }
func getsockname(s windows.Handle, name unsafe.Pointer, namelen *int32) (err error) { func getsockname(s windows.Handle, name unsafe.Pointer, namelen *int32) (err error) {
r1, _, e1 := syscall.Syscall(procgetsockname.Addr(), 3, uintptr(s), uintptr(name), uintptr(unsafe.Pointer(namelen))) r1, _, e1 := syscall.SyscallN(procgetsockname.Addr(), uintptr(s), uintptr(name), uintptr(unsafe.Pointer(namelen)))
if r1 == socketError { if r1 == socketError {
err = errnoErr(e1) err = errnoErr(e1)
} }

View File

@ -62,7 +62,7 @@ func (b *WString) Free() {
// ResizeTo grows the buffer to at least c and returns the new capacity, freeing the // ResizeTo grows the buffer to at least c and returns the new capacity, freeing the
// previous buffer back into pool. // previous buffer back into pool.
func (b *WString) ResizeTo(c uint32) uint32 { func (b *WString) ResizeTo(c uint32) uint32 {
// allready sufficient (or n is 0) // already sufficient (or n is 0)
if c <= b.Cap() { if c <= b.Cap() {
return b.Cap() return b.Cap()
} }

View File

@ -11,7 +11,6 @@ import (
"net" "net"
"os" "os"
"runtime" "runtime"
"syscall"
"time" "time"
"unsafe" "unsafe"
@ -20,20 +19,44 @@ import (
"github.com/Microsoft/go-winio/internal/fs" "github.com/Microsoft/go-winio/internal/fs"
) )
//sys connectNamedPipe(pipe syscall.Handle, o *syscall.Overlapped) (err error) = ConnectNamedPipe //sys connectNamedPipe(pipe windows.Handle, o *windows.Overlapped) (err error) = ConnectNamedPipe
//sys createNamedPipe(name string, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *syscall.SecurityAttributes) (handle syscall.Handle, err error) [failretval==syscall.InvalidHandle] = CreateNamedPipeW //sys createNamedPipe(name string, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *windows.SecurityAttributes) (handle windows.Handle, err error) [failretval==windows.InvalidHandle] = CreateNamedPipeW
//sys getNamedPipeInfo(pipe syscall.Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error) = GetNamedPipeInfo //sys disconnectNamedPipe(pipe windows.Handle) (err error) = DisconnectNamedPipe
//sys getNamedPipeHandleState(pipe syscall.Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) = GetNamedPipeHandleStateW //sys getNamedPipeInfo(pipe windows.Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error) = GetNamedPipeInfo
//sys localAlloc(uFlags uint32, length uint32) (ptr uintptr) = LocalAlloc //sys getNamedPipeHandleState(pipe windows.Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) = GetNamedPipeHandleStateW
//sys ntCreateNamedPipeFile(pipe *syscall.Handle, access uint32, oa *objectAttributes, iosb *ioStatusBlock, share uint32, disposition uint32, options uint32, typ uint32, readMode uint32, completionMode uint32, maxInstances uint32, inboundQuota uint32, outputQuota uint32, timeout *int64) (status ntStatus) = ntdll.NtCreateNamedPipeFile //sys ntCreateNamedPipeFile(pipe *windows.Handle, access ntAccessMask, oa *objectAttributes, iosb *ioStatusBlock, share ntFileShareMode, disposition ntFileCreationDisposition, options ntFileOptions, typ uint32, readMode uint32, completionMode uint32, maxInstances uint32, inboundQuota uint32, outputQuota uint32, timeout *int64) (status ntStatus) = ntdll.NtCreateNamedPipeFile
//sys rtlNtStatusToDosError(status ntStatus) (winerr error) = ntdll.RtlNtStatusToDosErrorNoTeb //sys rtlNtStatusToDosError(status ntStatus) (winerr error) = ntdll.RtlNtStatusToDosErrorNoTeb
//sys rtlDosPathNameToNtPathName(name *uint16, ntName *unicodeString, filePart uintptr, reserved uintptr) (status ntStatus) = ntdll.RtlDosPathNameToNtPathName_U //sys rtlDosPathNameToNtPathName(name *uint16, ntName *unicodeString, filePart uintptr, reserved uintptr) (status ntStatus) = ntdll.RtlDosPathNameToNtPathName_U
//sys rtlDefaultNpAcl(dacl *uintptr) (status ntStatus) = ntdll.RtlDefaultNpAcl //sys rtlDefaultNpAcl(dacl *uintptr) (status ntStatus) = ntdll.RtlDefaultNpAcl
type PipeConn interface {
net.Conn
Disconnect() error
Flush() error
}
// type aliases for mkwinsyscall code
type (
ntAccessMask = fs.AccessMask
ntFileShareMode = fs.FileShareMode
ntFileCreationDisposition = fs.NTFileCreationDisposition
ntFileOptions = fs.NTCreateOptions
)
type ioStatusBlock struct { type ioStatusBlock struct {
Status, Information uintptr Status, Information uintptr
} }
// typedef struct _OBJECT_ATTRIBUTES {
// ULONG Length;
// HANDLE RootDirectory;
// PUNICODE_STRING ObjectName;
// ULONG Attributes;
// PVOID SecurityDescriptor;
// PVOID SecurityQualityOfService;
// } OBJECT_ATTRIBUTES;
//
// https://learn.microsoft.com/en-us/windows/win32/api/ntdef/ns-ntdef-_object_attributes
type objectAttributes struct { type objectAttributes struct {
Length uintptr Length uintptr
RootDirectory uintptr RootDirectory uintptr
@ -49,6 +72,17 @@ type unicodeString struct {
Buffer uintptr Buffer uintptr
} }
// typedef struct _SECURITY_DESCRIPTOR {
// BYTE Revision;
// BYTE Sbz1;
// SECURITY_DESCRIPTOR_CONTROL Control;
// PSID Owner;
// PSID Group;
// PACL Sacl;
// PACL Dacl;
// } SECURITY_DESCRIPTOR, *PISECURITY_DESCRIPTOR;
//
// https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-security_descriptor
type securityDescriptor struct { type securityDescriptor struct {
Revision byte Revision byte
Sbz1 byte Sbz1 byte
@ -80,6 +114,8 @@ type win32Pipe struct {
path string path string
} }
var _ PipeConn = (*win32Pipe)(nil)
type win32MessageBytePipe struct { type win32MessageBytePipe struct {
win32Pipe win32Pipe
writeClosed bool writeClosed bool
@ -103,6 +139,10 @@ func (f *win32Pipe) SetDeadline(t time.Time) error {
return f.SetWriteDeadline(t) return f.SetWriteDeadline(t)
} }
func (f *win32Pipe) Disconnect() error {
return disconnectNamedPipe(f.win32File.handle)
}
// CloseWrite closes the write side of a message pipe in byte mode. // CloseWrite closes the write side of a message pipe in byte mode.
func (f *win32MessageBytePipe) CloseWrite() error { func (f *win32MessageBytePipe) CloseWrite() error {
if f.writeClosed { if f.writeClosed {
@ -146,7 +186,7 @@ func (f *win32MessageBytePipe) Read(b []byte) (int, error) {
// zero-byte message, ensure that all future Read() calls // zero-byte message, ensure that all future Read() calls
// also return EOF. // also return EOF.
f.readEOF = true f.readEOF = true
} else if err == syscall.ERROR_MORE_DATA { //nolint:errorlint // err is Errno } else if err == windows.ERROR_MORE_DATA { //nolint:errorlint // err is Errno
// ERROR_MORE_DATA indicates that the pipe's read mode is message mode // ERROR_MORE_DATA indicates that the pipe's read mode is message mode
// and the message still has more bytes. Treat this as a success, since // and the message still has more bytes. Treat this as a success, since
// this package presents all named pipes as byte streams. // this package presents all named pipes as byte streams.
@ -164,21 +204,20 @@ func (s pipeAddress) String() string {
} }
// tryDialPipe attempts to dial the pipe at `path` until `ctx` cancellation or timeout. // tryDialPipe attempts to dial the pipe at `path` until `ctx` cancellation or timeout.
func tryDialPipe(ctx context.Context, path *string, access fs.AccessMask) (syscall.Handle, error) { func tryDialPipe(ctx context.Context, path *string, access fs.AccessMask, impLevel PipeImpLevel) (windows.Handle, error) {
for { for {
select { select {
case <-ctx.Done(): case <-ctx.Done():
return syscall.Handle(0), ctx.Err() return windows.Handle(0), ctx.Err()
default: default:
wh, err := fs.CreateFile(*path, h, err := fs.CreateFile(*path,
access, access,
0, // mode 0, // mode
nil, // security attributes nil, // security attributes
fs.OPEN_EXISTING, fs.OPEN_EXISTING,
fs.FILE_FLAG_OVERLAPPED|fs.SECURITY_SQOS_PRESENT|fs.SECURITY_ANONYMOUS, fs.FILE_FLAG_OVERLAPPED|fs.SECURITY_SQOS_PRESENT|fs.FileSQSFlag(impLevel),
0, // template file handle 0, // template file handle
) )
h := syscall.Handle(wh)
if err == nil { if err == nil {
return h, nil return h, nil
} }
@ -214,15 +253,33 @@ func DialPipe(path string, timeout *time.Duration) (net.Conn, error) {
// DialPipeContext attempts to connect to a named pipe by `path` until `ctx` // DialPipeContext attempts to connect to a named pipe by `path` until `ctx`
// cancellation or timeout. // cancellation or timeout.
func DialPipeContext(ctx context.Context, path string) (net.Conn, error) { func DialPipeContext(ctx context.Context, path string) (net.Conn, error) {
return DialPipeAccess(ctx, path, syscall.GENERIC_READ|syscall.GENERIC_WRITE) return DialPipeAccess(ctx, path, uint32(fs.GENERIC_READ|fs.GENERIC_WRITE))
} }
// PipeImpLevel is an enumeration of impersonation levels that may be set
// when calling DialPipeAccessImpersonation.
type PipeImpLevel uint32
const (
PipeImpLevelAnonymous = PipeImpLevel(fs.SECURITY_ANONYMOUS)
PipeImpLevelIdentification = PipeImpLevel(fs.SECURITY_IDENTIFICATION)
PipeImpLevelImpersonation = PipeImpLevel(fs.SECURITY_IMPERSONATION)
PipeImpLevelDelegation = PipeImpLevel(fs.SECURITY_DELEGATION)
)
// DialPipeAccess attempts to connect to a named pipe by `path` with `access` until `ctx` // DialPipeAccess attempts to connect to a named pipe by `path` with `access` until `ctx`
// cancellation or timeout. // cancellation or timeout.
func DialPipeAccess(ctx context.Context, path string, access uint32) (net.Conn, error) { func DialPipeAccess(ctx context.Context, path string, access uint32) (net.Conn, error) {
return DialPipeAccessImpLevel(ctx, path, access, PipeImpLevelAnonymous)
}
// DialPipeAccessImpLevel attempts to connect to a named pipe by `path` with
// `access` at `impLevel` until `ctx` cancellation or timeout. The other
// DialPipe* implementations use PipeImpLevelAnonymous.
func DialPipeAccessImpLevel(ctx context.Context, path string, access uint32, impLevel PipeImpLevel) (net.Conn, error) {
var err error var err error
var h syscall.Handle var h windows.Handle
h, err = tryDialPipe(ctx, &path, fs.AccessMask(access)) h, err = tryDialPipe(ctx, &path, fs.AccessMask(access), impLevel)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -235,7 +292,7 @@ func DialPipeAccess(ctx context.Context, path string, access uint32) (net.Conn,
f, err := makeWin32File(h) f, err := makeWin32File(h)
if err != nil { if err != nil {
syscall.Close(h) windows.Close(h)
return nil, err return nil, err
} }
@ -255,7 +312,7 @@ type acceptResponse struct {
} }
type win32PipeListener struct { type win32PipeListener struct {
firstHandle syscall.Handle firstHandle windows.Handle
path string path string
config PipeConfig config PipeConfig
acceptCh chan (chan acceptResponse) acceptCh chan (chan acceptResponse)
@ -263,8 +320,8 @@ type win32PipeListener struct {
doneCh chan int doneCh chan int
} }
func makeServerPipeHandle(path string, sd []byte, c *PipeConfig, first bool) (syscall.Handle, error) { func makeServerPipeHandle(path string, sd []byte, c *PipeConfig, first bool) (windows.Handle, error) {
path16, err := syscall.UTF16FromString(path) path16, err := windows.UTF16FromString(path)
if err != nil { if err != nil {
return 0, &os.PathError{Op: "open", Path: path, Err: err} return 0, &os.PathError{Op: "open", Path: path, Err: err}
} }
@ -280,16 +337,20 @@ func makeServerPipeHandle(path string, sd []byte, c *PipeConfig, first bool) (sy
).Err(); err != nil { ).Err(); err != nil {
return 0, &os.PathError{Op: "open", Path: path, Err: err} return 0, &os.PathError{Op: "open", Path: path, Err: err}
} }
defer localFree(ntPath.Buffer) defer windows.LocalFree(windows.Handle(ntPath.Buffer)) //nolint:errcheck
oa.ObjectName = &ntPath oa.ObjectName = &ntPath
oa.Attributes = windows.OBJ_CASE_INSENSITIVE oa.Attributes = windows.OBJ_CASE_INSENSITIVE
// The security descriptor is only needed for the first pipe. // The security descriptor is only needed for the first pipe.
if first { if first {
if sd != nil { if sd != nil {
//todo: does `sdb` need to be allocated on the heap, or can go allocate it?
l := uint32(len(sd)) l := uint32(len(sd))
sdb := localAlloc(0, l) sdb, err := windows.LocalAlloc(0, l)
defer localFree(sdb) if err != nil {
return 0, fmt.Errorf("LocalAlloc for security descriptor with of length %d: %w", l, err)
}
defer windows.LocalFree(windows.Handle(sdb)) //nolint:errcheck
copy((*[0xffff]byte)(unsafe.Pointer(sdb))[:], sd) copy((*[0xffff]byte)(unsafe.Pointer(sdb))[:], sd)
oa.SecurityDescriptor = (*securityDescriptor)(unsafe.Pointer(sdb)) oa.SecurityDescriptor = (*securityDescriptor)(unsafe.Pointer(sdb))
} else { } else {
@ -298,7 +359,7 @@ func makeServerPipeHandle(path string, sd []byte, c *PipeConfig, first bool) (sy
if err := rtlDefaultNpAcl(&dacl).Err(); err != nil { if err := rtlDefaultNpAcl(&dacl).Err(); err != nil {
return 0, fmt.Errorf("getting default named pipe ACL: %w", err) return 0, fmt.Errorf("getting default named pipe ACL: %w", err)
} }
defer localFree(dacl) defer windows.LocalFree(windows.Handle(dacl)) //nolint:errcheck
sdb := &securityDescriptor{ sdb := &securityDescriptor{
Revision: 1, Revision: 1,
@ -314,27 +375,27 @@ func makeServerPipeHandle(path string, sd []byte, c *PipeConfig, first bool) (sy
typ |= windows.FILE_PIPE_MESSAGE_TYPE typ |= windows.FILE_PIPE_MESSAGE_TYPE
} }
disposition := uint32(windows.FILE_OPEN) disposition := fs.FILE_OPEN
access := uint32(syscall.GENERIC_READ | syscall.GENERIC_WRITE | syscall.SYNCHRONIZE) access := fs.GENERIC_READ | fs.GENERIC_WRITE | fs.SYNCHRONIZE
if first { if first {
disposition = windows.FILE_CREATE disposition = fs.FILE_CREATE
// By not asking for read or write access, the named pipe file system // By not asking for read or write access, the named pipe file system
// will put this pipe into an initially disconnected state, blocking // will put this pipe into an initially disconnected state, blocking
// client connections until the next call with first == false. // client connections until the next call with first == false.
access = syscall.SYNCHRONIZE access = fs.SYNCHRONIZE
} }
timeout := int64(-50 * 10000) // 50ms timeout := int64(-50 * 10000) // 50ms
var ( var (
h syscall.Handle h windows.Handle
iosb ioStatusBlock iosb ioStatusBlock
) )
err = ntCreateNamedPipeFile(&h, err = ntCreateNamedPipeFile(&h,
access, access,
&oa, &oa,
&iosb, &iosb,
syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE, fs.FILE_SHARE_READ|fs.FILE_SHARE_WRITE,
disposition, disposition,
0, 0,
typ, typ,
@ -359,7 +420,7 @@ func (l *win32PipeListener) makeServerPipe() (*win32File, error) {
} }
f, err := makeWin32File(h) f, err := makeWin32File(h)
if err != nil { if err != nil {
syscall.Close(h) windows.Close(h)
return nil, err return nil, err
} }
return f, nil return f, nil
@ -418,7 +479,7 @@ func (l *win32PipeListener) listenerRoutine() {
closed = err == ErrPipeListenerClosed //nolint:errorlint // err is Errno closed = err == ErrPipeListenerClosed //nolint:errorlint // err is Errno
} }
} }
syscall.Close(l.firstHandle) windows.Close(l.firstHandle)
l.firstHandle = 0 l.firstHandle = 0
// Notify Close() and Accept() callers that the handle has been closed. // Notify Close() and Accept() callers that the handle has been closed.
close(l.doneCh) close(l.doneCh)

View File

@ -0,0 +1,307 @@
//go:build windows
// +build windows
package bindfilter
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"os"
"path/filepath"
"strings"
"unsafe"
"golang.org/x/sys/windows"
)
//go:generate go run github.com/Microsoft/go-winio/tools/mkwinsyscall -output zsyscall_windows.go ./bind_filter.go
//sys bfSetupFilter(jobHandle windows.Handle, flags uint32, virtRootPath string, virtTargetPath string, virtExceptions **uint16, virtExceptionPathCount uint32) (hr error) = bindfltapi.BfSetupFilter?
//sys bfRemoveMapping(jobHandle windows.Handle, virtRootPath string) (hr error) = bindfltapi.BfRemoveMapping?
//sys bfGetMappings(flags uint32, jobHandle windows.Handle, virtRootPath *uint16, sid *windows.SID, bufferSize *uint32, outBuffer *byte) (hr error) = bindfltapi.BfGetMappings?
// BfSetupFilter flags. See:
// https://github.com/microsoft/BuildXL/blob/a6dce509f0d4f774255e5fbfb75fa6d5290ed163/Public/Src/Utilities/Native/Processes/Windows/NativeContainerUtilities.cs#L193-L240
//
//nolint:revive // var-naming: ALL_CAPS
const (
BINDFLT_FLAG_READ_ONLY_MAPPING uint32 = 0x00000001
// Tells bindflt to fail mapping with STATUS_INVALID_PARAMETER if a mapping produces
// multiple targets.
BINDFLT_FLAG_NO_MULTIPLE_TARGETS uint32 = 0x00000040
)
//nolint:revive // var-naming: ALL_CAPS
const (
BINDFLT_GET_MAPPINGS_FLAG_VOLUME uint32 = 0x00000001
BINDFLT_GET_MAPPINGS_FLAG_SILO uint32 = 0x00000002
BINDFLT_GET_MAPPINGS_FLAG_USER uint32 = 0x00000004
)
// ApplyFileBinding creates a global mount of the source in root, with an optional
// read only flag.
// The bind filter allows us to create mounts of directories and volumes. By default it allows
// us to mount multiple sources inside a single root, acting as an overlay. Files from the
// second source will superscede the first source that was mounted.
// This function disables this behavior and sets the BINDFLT_FLAG_NO_MULTIPLE_TARGETS flag
// on the mount.
func ApplyFileBinding(root, source string, readOnly bool) error {
// The parent directory needs to exist for the bind to work. MkdirAll stats and
// returns nil if the directory exists internally so we should be fine to mkdirall
// every time.
if err := os.MkdirAll(filepath.Dir(root), 0); err != nil {
return err
}
if strings.Contains(source, "Volume{") && !strings.HasSuffix(source, "\\") {
// Add trailing slash to volumes, otherwise we get an error when binding it to
// a folder.
source = source + "\\"
}
flags := BINDFLT_FLAG_NO_MULTIPLE_TARGETS
if readOnly {
flags |= BINDFLT_FLAG_READ_ONLY_MAPPING
}
// Set the job handle to 0 to create a global mount.
if err := bfSetupFilter(
0,
flags,
root,
source,
nil,
0,
); err != nil {
return fmt.Errorf("failed to bind target %q to root %q: %w", source, root, err)
}
return nil
}
// RemoveFileBinding removes a mount from the root path.
func RemoveFileBinding(root string) error {
if err := bfRemoveMapping(0, root); err != nil {
return fmt.Errorf("removing file binding: %w", err)
}
return nil
}
// GetBindMappings returns a list of bind mappings that have their root on a
// particular volume. The volumePath parameter can be any path that exists on
// a volume. For example, if a number of mappings are created in C:\ProgramData\test,
// to get a list of those mappings, the volumePath parameter would have to be set to
// C:\ or the VOLUME_NAME_GUID notation of C:\ (\\?\Volume{GUID}\), or any child
// path that exists.
func GetBindMappings(volumePath string) ([]BindMapping, error) {
rootPtr, err := windows.UTF16PtrFromString(volumePath)
if err != nil {
return nil, err
}
flags := BINDFLT_GET_MAPPINGS_FLAG_VOLUME
// allocate a large buffer for results
var outBuffSize uint32 = 256 * 1024
buf := make([]byte, outBuffSize)
if err := bfGetMappings(flags, 0, rootPtr, nil, &outBuffSize, &buf[0]); err != nil {
return nil, err
}
if outBuffSize < 12 {
return nil, fmt.Errorf("invalid buffer returned")
}
result := buf[:outBuffSize]
// The first 12 bytes are the three uint32 fields in getMappingsResponseHeader{}
headerBuffer := result[:12]
// The alternative to using unsafe and casting it to the above defined structures, is to manually
// parse the fields. Not too terrible, but not sure it'd worth the trouble.
header := *(*getMappingsResponseHeader)(unsafe.Pointer(&headerBuffer[0]))
if header.MappingCount == 0 {
// no mappings
return []BindMapping{}, nil
}
mappingsBuffer := result[12 : int(unsafe.Sizeof(mappingEntry{}))*int(header.MappingCount)]
// Get a pointer to the first mapping in the slice
mappingsPointer := (*mappingEntry)(unsafe.Pointer(&mappingsBuffer[0]))
// Get slice of mappings
mappings := unsafe.Slice(mappingsPointer, header.MappingCount)
mappingEntries := make([]BindMapping, header.MappingCount)
for i := 0; i < int(header.MappingCount); i++ {
bindMapping, err := getBindMappingFromBuffer(result, mappings[i])
if err != nil {
return nil, fmt.Errorf("fetching bind mappings: %w", err)
}
mappingEntries[i] = bindMapping
}
return mappingEntries, nil
}
// mappingEntry holds information about where in the response buffer we can
// find information about the virtual root (the mount point) and the targets (sources)
// that get mounted, as well as the flags used to bind the targets to the virtual root.
type mappingEntry struct {
VirtRootLength uint32
VirtRootOffset uint32
Flags uint32
NumberOfTargets uint32
TargetEntriesOffset uint32
}
type mappingTargetEntry struct {
TargetRootLength uint32
TargetRootOffset uint32
}
// getMappingsResponseHeader represents the first 12 bytes of the BfGetMappings() response.
// It gives us the size of the buffer, the status of the call and the number of mappings.
// A response
type getMappingsResponseHeader struct {
Size uint32
Status uint32
MappingCount uint32
}
type BindMapping struct {
MountPoint string
Flags uint32
Targets []string
}
func decodeEntry(buffer []byte) (string, error) {
name := make([]uint16, len(buffer)/2)
err := binary.Read(bytes.NewReader(buffer), binary.LittleEndian, &name)
if err != nil {
return "", fmt.Errorf("decoding name: %w", err)
}
return windows.UTF16ToString(name), nil
}
func getTargetsFromBuffer(buffer []byte, offset, count int) ([]string, error) {
if len(buffer) < offset+count*6 {
return nil, fmt.Errorf("invalid buffer")
}
targets := make([]string, count)
for i := 0; i < count; i++ {
entryBuf := buffer[offset+i*8 : offset+i*8+8]
tgt := *(*mappingTargetEntry)(unsafe.Pointer(&entryBuf[0]))
if len(buffer) < int(tgt.TargetRootOffset)+int(tgt.TargetRootLength) {
return nil, fmt.Errorf("invalid buffer")
}
decoded, err := decodeEntry(buffer[tgt.TargetRootOffset : tgt.TargetRootOffset+tgt.TargetRootLength])
if err != nil {
return nil, fmt.Errorf("decoding name: %w", err)
}
decoded, err = getFinalPath(decoded)
if err != nil {
return nil, fmt.Errorf("fetching final path: %w", err)
}
targets[i] = decoded
}
return targets, nil
}
func getFinalPath(pth string) (string, error) {
// BfGetMappings returns VOLUME_NAME_NT paths like \Device\HarddiskVolume2\ProgramData.
// These can be accessed by prepending \\.\GLOBALROOT to the path. We use this to get the
// DOS paths for these files.
if strings.HasPrefix(pth, `\Device`) {
pth = `\\.\GLOBALROOT` + pth
}
han, err := openPath(pth)
if err != nil {
return "", fmt.Errorf("fetching file handle: %w", err)
}
defer func() {
_ = windows.CloseHandle(han)
}()
buf := make([]uint16, 100)
var flags uint32 = 0x0
for {
n, err := windows.GetFinalPathNameByHandle(han, &buf[0], uint32(len(buf)), flags)
if err != nil {
// if we mounted a volume that does not also have a drive letter assigned, attempting to
// fetch the VOLUME_NAME_DOS will fail with os.ErrNotExist. Attempt to get the VOLUME_NAME_GUID.
if errors.Is(err, os.ErrNotExist) && flags != 0x1 {
flags = 0x1
continue
}
return "", fmt.Errorf("getting final path name: %w", err)
}
if n < uint32(len(buf)) {
break
}
buf = make([]uint16, n)
}
finalPath := windows.UTF16ToString(buf)
// We got VOLUME_NAME_DOS, we need to strip away some leading slashes.
// Leave unchanged if we ended up requesting VOLUME_NAME_GUID
if len(finalPath) > 4 && finalPath[:4] == `\\?\` && flags == 0x0 {
finalPath = finalPath[4:]
if len(finalPath) > 3 && finalPath[:3] == `UNC` {
// return path like \\server\share\...
finalPath = `\` + finalPath[3:]
}
}
return finalPath, nil
}
func getBindMappingFromBuffer(buffer []byte, entry mappingEntry) (BindMapping, error) {
if len(buffer) < int(entry.VirtRootOffset)+int(entry.VirtRootLength) {
return BindMapping{}, fmt.Errorf("invalid buffer")
}
src, err := decodeEntry(buffer[entry.VirtRootOffset : entry.VirtRootOffset+entry.VirtRootLength])
if err != nil {
return BindMapping{}, fmt.Errorf("decoding entry: %w", err)
}
targets, err := getTargetsFromBuffer(buffer, int(entry.TargetEntriesOffset), int(entry.NumberOfTargets))
if err != nil {
return BindMapping{}, fmt.Errorf("fetching targets: %w", err)
}
src, err = getFinalPath(src)
if err != nil {
return BindMapping{}, fmt.Errorf("fetching final path: %w", err)
}
return BindMapping{
Flags: entry.Flags,
Targets: targets,
MountPoint: src,
}, nil
}
func openPath(path string) (windows.Handle, error) {
u16, err := windows.UTF16PtrFromString(path)
if err != nil {
return 0, err
}
h, err := windows.CreateFile(
u16,
0,
windows.FILE_SHARE_READ|windows.FILE_SHARE_WRITE|windows.FILE_SHARE_DELETE,
nil,
windows.OPEN_EXISTING,
windows.FILE_FLAG_BACKUP_SEMANTICS, // Needed to open a directory handle.
0)
if err != nil {
return 0, &os.PathError{
Op: "CreateFile",
Path: path,
Err: err,
}
}
return h, nil
}

View File

@ -0,0 +1,113 @@
//go:build windows
// Code generated by 'go generate' using "github.com/Microsoft/go-winio/tools/mkwinsyscall"; DO NOT EDIT.
package bindfilter
import (
"syscall"
"unsafe"
"golang.org/x/sys/windows"
)
var _ unsafe.Pointer
// Do the interface allocations only once for common
// Errno values.
const (
errnoERROR_IO_PENDING = 997
)
var (
errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
errERROR_EINVAL error = syscall.EINVAL
)
// errnoErr returns common boxed Errno values, to prevent
// allocations at runtime.
func errnoErr(e syscall.Errno) error {
switch e {
case 0:
return errERROR_EINVAL
case errnoERROR_IO_PENDING:
return errERROR_IO_PENDING
}
return e
}
var (
modbindfltapi = windows.NewLazySystemDLL("bindfltapi.dll")
procBfGetMappings = modbindfltapi.NewProc("BfGetMappings")
procBfRemoveMapping = modbindfltapi.NewProc("BfRemoveMapping")
procBfSetupFilter = modbindfltapi.NewProc("BfSetupFilter")
)
func bfGetMappings(flags uint32, jobHandle windows.Handle, virtRootPath *uint16, sid *windows.SID, bufferSize *uint32, outBuffer *byte) (hr error) {
hr = procBfGetMappings.Find()
if hr != nil {
return
}
r0, _, _ := syscall.SyscallN(procBfGetMappings.Addr(), uintptr(flags), uintptr(jobHandle), uintptr(unsafe.Pointer(virtRootPath)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(bufferSize)), uintptr(unsafe.Pointer(outBuffer)))
if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
}
return
}
func bfRemoveMapping(jobHandle windows.Handle, virtRootPath string) (hr error) {
var _p0 *uint16
_p0, hr = syscall.UTF16PtrFromString(virtRootPath)
if hr != nil {
return
}
return _bfRemoveMapping(jobHandle, _p0)
}
func _bfRemoveMapping(jobHandle windows.Handle, virtRootPath *uint16) (hr error) {
hr = procBfRemoveMapping.Find()
if hr != nil {
return
}
r0, _, _ := syscall.SyscallN(procBfRemoveMapping.Addr(), uintptr(jobHandle), uintptr(unsafe.Pointer(virtRootPath)))
if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
}
return
}
func bfSetupFilter(jobHandle windows.Handle, flags uint32, virtRootPath string, virtTargetPath string, virtExceptions **uint16, virtExceptionPathCount uint32) (hr error) {
var _p0 *uint16
_p0, hr = syscall.UTF16PtrFromString(virtRootPath)
if hr != nil {
return
}
var _p1 *uint16
_p1, hr = syscall.UTF16PtrFromString(virtTargetPath)
if hr != nil {
return
}
return _bfSetupFilter(jobHandle, flags, _p0, _p1, virtExceptions, virtExceptionPathCount)
}
func _bfSetupFilter(jobHandle windows.Handle, flags uint32, virtRootPath *uint16, virtTargetPath *uint16, virtExceptions **uint16, virtExceptionPathCount uint32) (hr error) {
hr = procBfSetupFilter.Find()
if hr != nil {
return
}
r0, _, _ := syscall.SyscallN(procBfSetupFilter.Addr(), uintptr(jobHandle), uintptr(flags), uintptr(unsafe.Pointer(virtRootPath)), uintptr(unsafe.Pointer(virtTargetPath)), uintptr(unsafe.Pointer(virtExceptions)), uintptr(virtExceptionPathCount))
if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
}
return
}

View File

@ -9,7 +9,6 @@ import (
"fmt" "fmt"
"runtime" "runtime"
"sync" "sync"
"syscall"
"unicode/utf16" "unicode/utf16"
"golang.org/x/sys/windows" "golang.org/x/sys/windows"
@ -18,8 +17,8 @@ import (
//sys adjustTokenPrivileges(token windows.Token, releaseAll bool, input *byte, outputSize uint32, output *byte, requiredSize *uint32) (success bool, err error) [true] = advapi32.AdjustTokenPrivileges //sys adjustTokenPrivileges(token windows.Token, releaseAll bool, input *byte, outputSize uint32, output *byte, requiredSize *uint32) (success bool, err error) [true] = advapi32.AdjustTokenPrivileges
//sys impersonateSelf(level uint32) (err error) = advapi32.ImpersonateSelf //sys impersonateSelf(level uint32) (err error) = advapi32.ImpersonateSelf
//sys revertToSelf() (err error) = advapi32.RevertToSelf //sys revertToSelf() (err error) = advapi32.RevertToSelf
//sys openThreadToken(thread syscall.Handle, accessMask uint32, openAsSelf bool, token *windows.Token) (err error) = advapi32.OpenThreadToken //sys openThreadToken(thread windows.Handle, accessMask uint32, openAsSelf bool, token *windows.Token) (err error) = advapi32.OpenThreadToken
//sys getCurrentThread() (h syscall.Handle) = GetCurrentThread //sys getCurrentThread() (h windows.Handle) = GetCurrentThread
//sys lookupPrivilegeValue(systemName string, name string, luid *uint64) (err error) = advapi32.LookupPrivilegeValueW //sys lookupPrivilegeValue(systemName string, name string, luid *uint64) (err error) = advapi32.LookupPrivilegeValueW
//sys lookupPrivilegeName(systemName string, luid *uint64, buffer *uint16, size *uint32) (err error) = advapi32.LookupPrivilegeNameW //sys lookupPrivilegeName(systemName string, luid *uint64, buffer *uint16, size *uint32) (err error) = advapi32.LookupPrivilegeNameW
//sys lookupPrivilegeDisplayName(systemName string, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) = advapi32.LookupPrivilegeDisplayNameW //sys lookupPrivilegeDisplayName(systemName string, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) = advapi32.LookupPrivilegeDisplayNameW
@ -29,7 +28,7 @@ const (
SE_PRIVILEGE_ENABLED = windows.SE_PRIVILEGE_ENABLED SE_PRIVILEGE_ENABLED = windows.SE_PRIVILEGE_ENABLED
//revive:disable-next-line:var-naming ALL_CAPS //revive:disable-next-line:var-naming ALL_CAPS
ERROR_NOT_ALL_ASSIGNED syscall.Errno = windows.ERROR_NOT_ALL_ASSIGNED ERROR_NOT_ALL_ASSIGNED windows.Errno = windows.ERROR_NOT_ALL_ASSIGNED
SeBackupPrivilege = "SeBackupPrivilege" SeBackupPrivilege = "SeBackupPrivilege"
SeRestorePrivilege = "SeRestorePrivilege" SeRestorePrivilege = "SeRestorePrivilege"
@ -177,7 +176,7 @@ func newThreadToken() (windows.Token, error) {
} }
var token windows.Token var token windows.Token
err = openThreadToken(getCurrentThread(), syscall.TOKEN_ADJUST_PRIVILEGES|syscall.TOKEN_QUERY, false, &token) err = openThreadToken(getCurrentThread(), windows.TOKEN_ADJUST_PRIVILEGES|windows.TOKEN_QUERY, false, &token)
if err != nil { if err != nil {
rerr := revertToSelf() rerr := revertToSelf()
if rerr != nil { if rerr != nil {

View File

@ -5,7 +5,7 @@ package winio
import ( import (
"errors" "errors"
"syscall" "fmt"
"unsafe" "unsafe"
"golang.org/x/sys/windows" "golang.org/x/sys/windows"
@ -15,10 +15,6 @@ import (
//sys lookupAccountSid(systemName *uint16, sid *byte, name *uint16, nameSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) = advapi32.LookupAccountSidW //sys lookupAccountSid(systemName *uint16, sid *byte, name *uint16, nameSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) = advapi32.LookupAccountSidW
//sys convertSidToStringSid(sid *byte, str **uint16) (err error) = advapi32.ConvertSidToStringSidW //sys convertSidToStringSid(sid *byte, str **uint16) (err error) = advapi32.ConvertSidToStringSidW
//sys convertStringSidToSid(str *uint16, sid **byte) (err error) = advapi32.ConvertStringSidToSidW //sys convertStringSidToSid(str *uint16, sid **byte) (err error) = advapi32.ConvertStringSidToSidW
//sys convertStringSecurityDescriptorToSecurityDescriptor(str string, revision uint32, sd *uintptr, size *uint32) (err error) = advapi32.ConvertStringSecurityDescriptorToSecurityDescriptorW
//sys convertSecurityDescriptorToStringSecurityDescriptor(sd *byte, revision uint32, secInfo uint32, sddl **uint16, sddlSize *uint32) (err error) = advapi32.ConvertSecurityDescriptorToStringSecurityDescriptorW
//sys localFree(mem uintptr) = LocalFree
//sys getSecurityDescriptorLength(sd uintptr) (len uint32) = advapi32.GetSecurityDescriptorLength
type AccountLookupError struct { type AccountLookupError struct {
Name string Name string
@ -64,7 +60,7 @@ func LookupSidByName(name string) (sid string, err error) {
var sidSize, sidNameUse, refDomainSize uint32 var sidSize, sidNameUse, refDomainSize uint32
err = lookupAccountName(nil, name, nil, &sidSize, nil, &refDomainSize, &sidNameUse) err = lookupAccountName(nil, name, nil, &sidSize, nil, &refDomainSize, &sidNameUse)
if err != nil && err != syscall.ERROR_INSUFFICIENT_BUFFER { //nolint:errorlint // err is Errno if err != nil && err != windows.ERROR_INSUFFICIENT_BUFFER { //nolint:errorlint // err is Errno
return "", &AccountLookupError{name, err} return "", &AccountLookupError{name, err}
} }
sidBuffer := make([]byte, sidSize) sidBuffer := make([]byte, sidSize)
@ -78,8 +74,8 @@ func LookupSidByName(name string) (sid string, err error) {
if err != nil { if err != nil {
return "", &AccountLookupError{name, err} return "", &AccountLookupError{name, err}
} }
sid = syscall.UTF16ToString((*[0xffff]uint16)(unsafe.Pointer(strBuffer))[:]) sid = windows.UTF16ToString((*[0xffff]uint16)(unsafe.Pointer(strBuffer))[:])
localFree(uintptr(unsafe.Pointer(strBuffer))) _, _ = windows.LocalFree(windows.Handle(unsafe.Pointer(strBuffer)))
return sid, nil return sid, nil
} }
@ -100,7 +96,7 @@ func LookupNameBySid(sid string) (name string, err error) {
if err = convertStringSidToSid(sidBuffer, &sidPtr); err != nil { if err = convertStringSidToSid(sidBuffer, &sidPtr); err != nil {
return "", &AccountLookupError{sid, err} return "", &AccountLookupError{sid, err}
} }
defer localFree(uintptr(unsafe.Pointer(sidPtr))) defer windows.LocalFree(windows.Handle(unsafe.Pointer(sidPtr))) //nolint:errcheck
var nameSize, refDomainSize, sidNameUse uint32 var nameSize, refDomainSize, sidNameUse uint32
err = lookupAccountSid(nil, sidPtr, nil, &nameSize, nil, &refDomainSize, &sidNameUse) err = lookupAccountSid(nil, sidPtr, nil, &nameSize, nil, &refDomainSize, &sidNameUse)
@ -120,25 +116,18 @@ func LookupNameBySid(sid string) (name string, err error) {
} }
func SddlToSecurityDescriptor(sddl string) ([]byte, error) { func SddlToSecurityDescriptor(sddl string) ([]byte, error) {
var sdBuffer uintptr sd, err := windows.SecurityDescriptorFromString(sddl)
err := convertStringSecurityDescriptorToSecurityDescriptor(sddl, 1, &sdBuffer, nil)
if err != nil { if err != nil {
return nil, &SddlConversionError{sddl, err} return nil, &SddlConversionError{Sddl: sddl, Err: err}
} }
defer localFree(sdBuffer) b := unsafe.Slice((*byte)(unsafe.Pointer(sd)), sd.Length())
sd := make([]byte, getSecurityDescriptorLength(sdBuffer)) return b, nil
copy(sd, (*[0xffff]byte)(unsafe.Pointer(sdBuffer))[:len(sd)])
return sd, nil
} }
func SecurityDescriptorToSddl(sd []byte) (string, error) { func SecurityDescriptorToSddl(sd []byte) (string, error) {
var sddl *uint16 if l := int(unsafe.Sizeof(windows.SECURITY_DESCRIPTOR{})); len(sd) < l {
// The returned string length seems to include an arbitrary number of terminating NULs. return "", fmt.Errorf("SecurityDescriptor (%d) smaller than expected (%d): %w", len(sd), l, windows.ERROR_INCORRECT_SIZE)
// Don't use it.
err := convertSecurityDescriptorToStringSecurityDescriptor(&sd[0], 1, 0xff, &sddl, nil)
if err != nil {
return "", err
} }
defer localFree(uintptr(unsafe.Pointer(sddl))) s := (*windows.SECURITY_DESCRIPTOR)(unsafe.Pointer(&sd[0]))
return syscall.UTF16ToString((*[0xffff]uint16)(unsafe.Pointer(sddl))[:]), nil return s.String(), nil
} }

View File

@ -1,5 +0,0 @@
//go:build tools
package winio
import _ "golang.org/x/tools/cmd/stringer"

View File

@ -1,57 +0,0 @@
/*
mkwinsyscall generates windows system call bodies
It parses all files specified on command line containing function
prototypes (like syscall_windows.go) and prints system call bodies
to standard output.
The prototypes are marked by lines beginning with "//sys" and read
like func declarations if //sys is replaced by func, but:
- The parameter lists must give a name for each argument. This
includes return parameters.
- The parameter lists must give a type for each argument:
the (x, y, z int) shorthand is not allowed.
- If the return parameter is an error number, it must be named err.
- If go func name needs to be different from its winapi dll name,
the winapi name could be specified at the end, after "=" sign, like
//sys LoadLibrary(libname string) (handle uint32, err error) = LoadLibraryA
- Each function that returns err needs to supply a condition, that
return value of winapi will be tested against to detect failure.
This would set err to windows "last-error", otherwise it will be nil.
The value can be provided at end of //sys declaration, like
//sys LoadLibrary(libname string) (handle uint32, err error) [failretval==-1] = LoadLibraryA
and is [failretval==0] by default.
- If the function name ends in a "?", then the function not existing is non-
fatal, and an error will be returned instead of panicking.
Usage:
mkwinsyscall [flags] [path ...]
Flags
-output string
Output file name (standard output if omitted).
-sort
Sort DLL and function declarations (default true).
Intended to help transition from older versions of mkwinsyscall by making diffs
easier to read and understand.
-systemdll
Whether all DLLs should be loaded from the Windows system directory (default true).
-trace
Generate print statement after every syscall.
-utf16
Encode string arguments as UTF-16 for syscalls not ending in 'A' or 'W' (default true).
-winio
Import this package ("github.com/Microsoft/go-winio").
*/
package main

File diff suppressed because it is too large Load Diff

View File

@ -33,9 +33,6 @@ func errnoErr(e syscall.Errno) error {
case errnoERROR_IO_PENDING: case errnoERROR_IO_PENDING:
return errERROR_IO_PENDING return errERROR_IO_PENDING
} }
// TODO: add more here, after collecting data on the common
// error values see on Windows. (perhaps when running
// all.bat?)
return e return e
} }
@ -50,7 +47,7 @@ var (
) )
func attachVirtualDisk(handle syscall.Handle, securityDescriptor *uintptr, attachVirtualDiskFlag uint32, providerSpecificFlags uint32, parameters *AttachVirtualDiskParameters, overlapped *syscall.Overlapped) (win32err error) { func attachVirtualDisk(handle syscall.Handle, securityDescriptor *uintptr, attachVirtualDiskFlag uint32, providerSpecificFlags uint32, parameters *AttachVirtualDiskParameters, overlapped *syscall.Overlapped) (win32err error) {
r0, _, _ := syscall.Syscall6(procAttachVirtualDisk.Addr(), 6, uintptr(handle), uintptr(unsafe.Pointer(securityDescriptor)), uintptr(attachVirtualDiskFlag), uintptr(providerSpecificFlags), uintptr(unsafe.Pointer(parameters)), uintptr(unsafe.Pointer(overlapped))) r0, _, _ := syscall.SyscallN(procAttachVirtualDisk.Addr(), uintptr(handle), uintptr(unsafe.Pointer(securityDescriptor)), uintptr(attachVirtualDiskFlag), uintptr(providerSpecificFlags), uintptr(unsafe.Pointer(parameters)), uintptr(unsafe.Pointer(overlapped)))
if r0 != 0 { if r0 != 0 {
win32err = syscall.Errno(r0) win32err = syscall.Errno(r0)
} }
@ -67,7 +64,7 @@ func createVirtualDisk(virtualStorageType *VirtualStorageType, path string, virt
} }
func _createVirtualDisk(virtualStorageType *VirtualStorageType, path *uint16, virtualDiskAccessMask uint32, securityDescriptor *uintptr, createVirtualDiskFlags uint32, providerSpecificFlags uint32, parameters *CreateVirtualDiskParameters, overlapped *syscall.Overlapped, handle *syscall.Handle) (win32err error) { func _createVirtualDisk(virtualStorageType *VirtualStorageType, path *uint16, virtualDiskAccessMask uint32, securityDescriptor *uintptr, createVirtualDiskFlags uint32, providerSpecificFlags uint32, parameters *CreateVirtualDiskParameters, overlapped *syscall.Overlapped, handle *syscall.Handle) (win32err error) {
r0, _, _ := syscall.Syscall9(procCreateVirtualDisk.Addr(), 9, uintptr(unsafe.Pointer(virtualStorageType)), uintptr(unsafe.Pointer(path)), uintptr(virtualDiskAccessMask), uintptr(unsafe.Pointer(securityDescriptor)), uintptr(createVirtualDiskFlags), uintptr(providerSpecificFlags), uintptr(unsafe.Pointer(parameters)), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(handle))) r0, _, _ := syscall.SyscallN(procCreateVirtualDisk.Addr(), uintptr(unsafe.Pointer(virtualStorageType)), uintptr(unsafe.Pointer(path)), uintptr(virtualDiskAccessMask), uintptr(unsafe.Pointer(securityDescriptor)), uintptr(createVirtualDiskFlags), uintptr(providerSpecificFlags), uintptr(unsafe.Pointer(parameters)), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(handle)))
if r0 != 0 { if r0 != 0 {
win32err = syscall.Errno(r0) win32err = syscall.Errno(r0)
} }
@ -75,7 +72,7 @@ func _createVirtualDisk(virtualStorageType *VirtualStorageType, path *uint16, vi
} }
func detachVirtualDisk(handle syscall.Handle, detachVirtualDiskFlags uint32, providerSpecificFlags uint32) (win32err error) { func detachVirtualDisk(handle syscall.Handle, detachVirtualDiskFlags uint32, providerSpecificFlags uint32) (win32err error) {
r0, _, _ := syscall.Syscall(procDetachVirtualDisk.Addr(), 3, uintptr(handle), uintptr(detachVirtualDiskFlags), uintptr(providerSpecificFlags)) r0, _, _ := syscall.SyscallN(procDetachVirtualDisk.Addr(), uintptr(handle), uintptr(detachVirtualDiskFlags), uintptr(providerSpecificFlags))
if r0 != 0 { if r0 != 0 {
win32err = syscall.Errno(r0) win32err = syscall.Errno(r0)
} }
@ -83,7 +80,7 @@ func detachVirtualDisk(handle syscall.Handle, detachVirtualDiskFlags uint32, pro
} }
func getVirtualDiskPhysicalPath(handle syscall.Handle, diskPathSizeInBytes *uint32, buffer *uint16) (win32err error) { func getVirtualDiskPhysicalPath(handle syscall.Handle, diskPathSizeInBytes *uint32, buffer *uint16) (win32err error) {
r0, _, _ := syscall.Syscall(procGetVirtualDiskPhysicalPath.Addr(), 3, uintptr(handle), uintptr(unsafe.Pointer(diskPathSizeInBytes)), uintptr(unsafe.Pointer(buffer))) r0, _, _ := syscall.SyscallN(procGetVirtualDiskPhysicalPath.Addr(), uintptr(handle), uintptr(unsafe.Pointer(diskPathSizeInBytes)), uintptr(unsafe.Pointer(buffer)))
if r0 != 0 { if r0 != 0 {
win32err = syscall.Errno(r0) win32err = syscall.Errno(r0)
} }
@ -100,7 +97,7 @@ func openVirtualDisk(virtualStorageType *VirtualStorageType, path string, virtua
} }
func _openVirtualDisk(virtualStorageType *VirtualStorageType, path *uint16, virtualDiskAccessMask uint32, openVirtualDiskFlags uint32, parameters *openVirtualDiskParameters, handle *syscall.Handle) (win32err error) { func _openVirtualDisk(virtualStorageType *VirtualStorageType, path *uint16, virtualDiskAccessMask uint32, openVirtualDiskFlags uint32, parameters *openVirtualDiskParameters, handle *syscall.Handle) (win32err error) {
r0, _, _ := syscall.Syscall6(procOpenVirtualDisk.Addr(), 6, uintptr(unsafe.Pointer(virtualStorageType)), uintptr(unsafe.Pointer(path)), uintptr(virtualDiskAccessMask), uintptr(openVirtualDiskFlags), uintptr(unsafe.Pointer(parameters)), uintptr(unsafe.Pointer(handle))) r0, _, _ := syscall.SyscallN(procOpenVirtualDisk.Addr(), uintptr(unsafe.Pointer(virtualStorageType)), uintptr(unsafe.Pointer(path)), uintptr(virtualDiskAccessMask), uintptr(openVirtualDiskFlags), uintptr(unsafe.Pointer(parameters)), uintptr(unsafe.Pointer(handle)))
if r0 != 0 { if r0 != 0 {
win32err = syscall.Errno(r0) win32err = syscall.Errno(r0)
} }

View File

@ -33,9 +33,6 @@ func errnoErr(e syscall.Errno) error {
case errnoERROR_IO_PENDING: case errnoERROR_IO_PENDING:
return errERROR_IO_PENDING return errERROR_IO_PENDING
} }
// TODO: add more here, after collecting data on the common
// error values see on Windows. (perhaps when running
// all.bat?)
return e return e
} }
@ -46,11 +43,8 @@ var (
modws2_32 = windows.NewLazySystemDLL("ws2_32.dll") modws2_32 = windows.NewLazySystemDLL("ws2_32.dll")
procAdjustTokenPrivileges = modadvapi32.NewProc("AdjustTokenPrivileges") procAdjustTokenPrivileges = modadvapi32.NewProc("AdjustTokenPrivileges")
procConvertSecurityDescriptorToStringSecurityDescriptorW = modadvapi32.NewProc("ConvertSecurityDescriptorToStringSecurityDescriptorW")
procConvertSidToStringSidW = modadvapi32.NewProc("ConvertSidToStringSidW") procConvertSidToStringSidW = modadvapi32.NewProc("ConvertSidToStringSidW")
procConvertStringSecurityDescriptorToSecurityDescriptorW = modadvapi32.NewProc("ConvertStringSecurityDescriptorToSecurityDescriptorW")
procConvertStringSidToSidW = modadvapi32.NewProc("ConvertStringSidToSidW") procConvertStringSidToSidW = modadvapi32.NewProc("ConvertStringSidToSidW")
procGetSecurityDescriptorLength = modadvapi32.NewProc("GetSecurityDescriptorLength")
procImpersonateSelf = modadvapi32.NewProc("ImpersonateSelf") procImpersonateSelf = modadvapi32.NewProc("ImpersonateSelf")
procLookupAccountNameW = modadvapi32.NewProc("LookupAccountNameW") procLookupAccountNameW = modadvapi32.NewProc("LookupAccountNameW")
procLookupAccountSidW = modadvapi32.NewProc("LookupAccountSidW") procLookupAccountSidW = modadvapi32.NewProc("LookupAccountSidW")
@ -65,12 +59,11 @@ var (
procConnectNamedPipe = modkernel32.NewProc("ConnectNamedPipe") procConnectNamedPipe = modkernel32.NewProc("ConnectNamedPipe")
procCreateIoCompletionPort = modkernel32.NewProc("CreateIoCompletionPort") procCreateIoCompletionPort = modkernel32.NewProc("CreateIoCompletionPort")
procCreateNamedPipeW = modkernel32.NewProc("CreateNamedPipeW") procCreateNamedPipeW = modkernel32.NewProc("CreateNamedPipeW")
procDisconnectNamedPipe = modkernel32.NewProc("DisconnectNamedPipe")
procGetCurrentThread = modkernel32.NewProc("GetCurrentThread") procGetCurrentThread = modkernel32.NewProc("GetCurrentThread")
procGetNamedPipeHandleStateW = modkernel32.NewProc("GetNamedPipeHandleStateW") procGetNamedPipeHandleStateW = modkernel32.NewProc("GetNamedPipeHandleStateW")
procGetNamedPipeInfo = modkernel32.NewProc("GetNamedPipeInfo") procGetNamedPipeInfo = modkernel32.NewProc("GetNamedPipeInfo")
procGetQueuedCompletionStatus = modkernel32.NewProc("GetQueuedCompletionStatus") procGetQueuedCompletionStatus = modkernel32.NewProc("GetQueuedCompletionStatus")
procLocalAlloc = modkernel32.NewProc("LocalAlloc")
procLocalFree = modkernel32.NewProc("LocalFree")
procSetFileCompletionNotificationModes = modkernel32.NewProc("SetFileCompletionNotificationModes") procSetFileCompletionNotificationModes = modkernel32.NewProc("SetFileCompletionNotificationModes")
procNtCreateNamedPipeFile = modntdll.NewProc("NtCreateNamedPipeFile") procNtCreateNamedPipeFile = modntdll.NewProc("NtCreateNamedPipeFile")
procRtlDefaultNpAcl = modntdll.NewProc("RtlDefaultNpAcl") procRtlDefaultNpAcl = modntdll.NewProc("RtlDefaultNpAcl")
@ -84,7 +77,7 @@ func adjustTokenPrivileges(token windows.Token, releaseAll bool, input *byte, ou
if releaseAll { if releaseAll {
_p0 = 1 _p0 = 1
} }
r0, _, e1 := syscall.Syscall6(procAdjustTokenPrivileges.Addr(), 6, uintptr(token), uintptr(_p0), uintptr(unsafe.Pointer(input)), uintptr(outputSize), uintptr(unsafe.Pointer(output)), uintptr(unsafe.Pointer(requiredSize))) r0, _, e1 := syscall.SyscallN(procAdjustTokenPrivileges.Addr(), uintptr(token), uintptr(_p0), uintptr(unsafe.Pointer(input)), uintptr(outputSize), uintptr(unsafe.Pointer(output)), uintptr(unsafe.Pointer(requiredSize)))
success = r0 != 0 success = r0 != 0
if true { if true {
err = errnoErr(e1) err = errnoErr(e1)
@ -92,33 +85,8 @@ func adjustTokenPrivileges(token windows.Token, releaseAll bool, input *byte, ou
return return
} }
func convertSecurityDescriptorToStringSecurityDescriptor(sd *byte, revision uint32, secInfo uint32, sddl **uint16, sddlSize *uint32) (err error) {
r1, _, e1 := syscall.Syscall6(procConvertSecurityDescriptorToStringSecurityDescriptorW.Addr(), 5, uintptr(unsafe.Pointer(sd)), uintptr(revision), uintptr(secInfo), uintptr(unsafe.Pointer(sddl)), uintptr(unsafe.Pointer(sddlSize)), 0)
if r1 == 0 {
err = errnoErr(e1)
}
return
}
func convertSidToStringSid(sid *byte, str **uint16) (err error) { func convertSidToStringSid(sid *byte, str **uint16) (err error) {
r1, _, e1 := syscall.Syscall(procConvertSidToStringSidW.Addr(), 2, uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(str)), 0) r1, _, e1 := syscall.SyscallN(procConvertSidToStringSidW.Addr(), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(str)))
if r1 == 0 {
err = errnoErr(e1)
}
return
}
func convertStringSecurityDescriptorToSecurityDescriptor(str string, revision uint32, sd *uintptr, size *uint32) (err error) {
var _p0 *uint16
_p0, err = syscall.UTF16PtrFromString(str)
if err != nil {
return
}
return _convertStringSecurityDescriptorToSecurityDescriptor(_p0, revision, sd, size)
}
func _convertStringSecurityDescriptorToSecurityDescriptor(str *uint16, revision uint32, sd *uintptr, size *uint32) (err error) {
r1, _, e1 := syscall.Syscall6(procConvertStringSecurityDescriptorToSecurityDescriptorW.Addr(), 4, uintptr(unsafe.Pointer(str)), uintptr(revision), uintptr(unsafe.Pointer(sd)), uintptr(unsafe.Pointer(size)), 0, 0)
if r1 == 0 { if r1 == 0 {
err = errnoErr(e1) err = errnoErr(e1)
} }
@ -126,21 +94,15 @@ func _convertStringSecurityDescriptorToSecurityDescriptor(str *uint16, revision
} }
func convertStringSidToSid(str *uint16, sid **byte) (err error) { func convertStringSidToSid(str *uint16, sid **byte) (err error) {
r1, _, e1 := syscall.Syscall(procConvertStringSidToSidW.Addr(), 2, uintptr(unsafe.Pointer(str)), uintptr(unsafe.Pointer(sid)), 0) r1, _, e1 := syscall.SyscallN(procConvertStringSidToSidW.Addr(), uintptr(unsafe.Pointer(str)), uintptr(unsafe.Pointer(sid)))
if r1 == 0 { if r1 == 0 {
err = errnoErr(e1) err = errnoErr(e1)
} }
return return
} }
func getSecurityDescriptorLength(sd uintptr) (len uint32) {
r0, _, _ := syscall.Syscall(procGetSecurityDescriptorLength.Addr(), 1, uintptr(sd), 0, 0)
len = uint32(r0)
return
}
func impersonateSelf(level uint32) (err error) { func impersonateSelf(level uint32) (err error) {
r1, _, e1 := syscall.Syscall(procImpersonateSelf.Addr(), 1, uintptr(level), 0, 0) r1, _, e1 := syscall.SyscallN(procImpersonateSelf.Addr(), uintptr(level))
if r1 == 0 { if r1 == 0 {
err = errnoErr(e1) err = errnoErr(e1)
} }
@ -157,7 +119,7 @@ func lookupAccountName(systemName *uint16, accountName string, sid *byte, sidSiz
} }
func _lookupAccountName(systemName *uint16, accountName *uint16, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) { func _lookupAccountName(systemName *uint16, accountName *uint16, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) {
r1, _, e1 := syscall.Syscall9(procLookupAccountNameW.Addr(), 7, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(accountName)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(sidSize)), uintptr(unsafe.Pointer(refDomain)), uintptr(unsafe.Pointer(refDomainSize)), uintptr(unsafe.Pointer(sidNameUse)), 0, 0) r1, _, e1 := syscall.SyscallN(procLookupAccountNameW.Addr(), uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(accountName)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(sidSize)), uintptr(unsafe.Pointer(refDomain)), uintptr(unsafe.Pointer(refDomainSize)), uintptr(unsafe.Pointer(sidNameUse)))
if r1 == 0 { if r1 == 0 {
err = errnoErr(e1) err = errnoErr(e1)
} }
@ -165,7 +127,7 @@ func _lookupAccountName(systemName *uint16, accountName *uint16, sid *byte, sidS
} }
func lookupAccountSid(systemName *uint16, sid *byte, name *uint16, nameSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) { func lookupAccountSid(systemName *uint16, sid *byte, name *uint16, nameSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) {
r1, _, e1 := syscall.Syscall9(procLookupAccountSidW.Addr(), 7, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(nameSize)), uintptr(unsafe.Pointer(refDomain)), uintptr(unsafe.Pointer(refDomainSize)), uintptr(unsafe.Pointer(sidNameUse)), 0, 0) r1, _, e1 := syscall.SyscallN(procLookupAccountSidW.Addr(), uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(nameSize)), uintptr(unsafe.Pointer(refDomain)), uintptr(unsafe.Pointer(refDomainSize)), uintptr(unsafe.Pointer(sidNameUse)))
if r1 == 0 { if r1 == 0 {
err = errnoErr(e1) err = errnoErr(e1)
} }
@ -182,7 +144,7 @@ func lookupPrivilegeDisplayName(systemName string, name *uint16, buffer *uint16,
} }
func _lookupPrivilegeDisplayName(systemName *uint16, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) { func _lookupPrivilegeDisplayName(systemName *uint16, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) {
r1, _, e1 := syscall.Syscall6(procLookupPrivilegeDisplayNameW.Addr(), 5, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(buffer)), uintptr(unsafe.Pointer(size)), uintptr(unsafe.Pointer(languageId)), 0) r1, _, e1 := syscall.SyscallN(procLookupPrivilegeDisplayNameW.Addr(), uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(buffer)), uintptr(unsafe.Pointer(size)), uintptr(unsafe.Pointer(languageId)))
if r1 == 0 { if r1 == 0 {
err = errnoErr(e1) err = errnoErr(e1)
} }
@ -199,7 +161,7 @@ func lookupPrivilegeName(systemName string, luid *uint64, buffer *uint16, size *
} }
func _lookupPrivilegeName(systemName *uint16, luid *uint64, buffer *uint16, size *uint32) (err error) { func _lookupPrivilegeName(systemName *uint16, luid *uint64, buffer *uint16, size *uint32) (err error) {
r1, _, e1 := syscall.Syscall6(procLookupPrivilegeNameW.Addr(), 4, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(luid)), uintptr(unsafe.Pointer(buffer)), uintptr(unsafe.Pointer(size)), 0, 0) r1, _, e1 := syscall.SyscallN(procLookupPrivilegeNameW.Addr(), uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(luid)), uintptr(unsafe.Pointer(buffer)), uintptr(unsafe.Pointer(size)))
if r1 == 0 { if r1 == 0 {
err = errnoErr(e1) err = errnoErr(e1)
} }
@ -221,19 +183,19 @@ func lookupPrivilegeValue(systemName string, name string, luid *uint64) (err err
} }
func _lookupPrivilegeValue(systemName *uint16, name *uint16, luid *uint64) (err error) { func _lookupPrivilegeValue(systemName *uint16, name *uint16, luid *uint64) (err error) {
r1, _, e1 := syscall.Syscall(procLookupPrivilegeValueW.Addr(), 3, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(luid))) r1, _, e1 := syscall.SyscallN(procLookupPrivilegeValueW.Addr(), uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(luid)))
if r1 == 0 { if r1 == 0 {
err = errnoErr(e1) err = errnoErr(e1)
} }
return return
} }
func openThreadToken(thread syscall.Handle, accessMask uint32, openAsSelf bool, token *windows.Token) (err error) { func openThreadToken(thread windows.Handle, accessMask uint32, openAsSelf bool, token *windows.Token) (err error) {
var _p0 uint32 var _p0 uint32
if openAsSelf { if openAsSelf {
_p0 = 1 _p0 = 1
} }
r1, _, e1 := syscall.Syscall6(procOpenThreadToken.Addr(), 4, uintptr(thread), uintptr(accessMask), uintptr(_p0), uintptr(unsafe.Pointer(token)), 0, 0) r1, _, e1 := syscall.SyscallN(procOpenThreadToken.Addr(), uintptr(thread), uintptr(accessMask), uintptr(_p0), uintptr(unsafe.Pointer(token)))
if r1 == 0 { if r1 == 0 {
err = errnoErr(e1) err = errnoErr(e1)
} }
@ -241,14 +203,14 @@ func openThreadToken(thread syscall.Handle, accessMask uint32, openAsSelf bool,
} }
func revertToSelf() (err error) { func revertToSelf() (err error) {
r1, _, e1 := syscall.Syscall(procRevertToSelf.Addr(), 0, 0, 0, 0) r1, _, e1 := syscall.SyscallN(procRevertToSelf.Addr())
if r1 == 0 { if r1 == 0 {
err = errnoErr(e1) err = errnoErr(e1)
} }
return return
} }
func backupRead(h syscall.Handle, b []byte, bytesRead *uint32, abort bool, processSecurity bool, context *uintptr) (err error) { func backupRead(h windows.Handle, b []byte, bytesRead *uint32, abort bool, processSecurity bool, context *uintptr) (err error) {
var _p0 *byte var _p0 *byte
if len(b) > 0 { if len(b) > 0 {
_p0 = &b[0] _p0 = &b[0]
@ -261,14 +223,14 @@ func backupRead(h syscall.Handle, b []byte, bytesRead *uint32, abort bool, proce
if processSecurity { if processSecurity {
_p2 = 1 _p2 = 1
} }
r1, _, e1 := syscall.Syscall9(procBackupRead.Addr(), 7, uintptr(h), uintptr(unsafe.Pointer(_p0)), uintptr(len(b)), uintptr(unsafe.Pointer(bytesRead)), uintptr(_p1), uintptr(_p2), uintptr(unsafe.Pointer(context)), 0, 0) r1, _, e1 := syscall.SyscallN(procBackupRead.Addr(), uintptr(h), uintptr(unsafe.Pointer(_p0)), uintptr(len(b)), uintptr(unsafe.Pointer(bytesRead)), uintptr(_p1), uintptr(_p2), uintptr(unsafe.Pointer(context)))
if r1 == 0 { if r1 == 0 {
err = errnoErr(e1) err = errnoErr(e1)
} }
return return
} }
func backupWrite(h syscall.Handle, b []byte, bytesWritten *uint32, abort bool, processSecurity bool, context *uintptr) (err error) { func backupWrite(h windows.Handle, b []byte, bytesWritten *uint32, abort bool, processSecurity bool, context *uintptr) (err error) {
var _p0 *byte var _p0 *byte
if len(b) > 0 { if len(b) > 0 {
_p0 = &b[0] _p0 = &b[0]
@ -281,39 +243,39 @@ func backupWrite(h syscall.Handle, b []byte, bytesWritten *uint32, abort bool, p
if processSecurity { if processSecurity {
_p2 = 1 _p2 = 1
} }
r1, _, e1 := syscall.Syscall9(procBackupWrite.Addr(), 7, uintptr(h), uintptr(unsafe.Pointer(_p0)), uintptr(len(b)), uintptr(unsafe.Pointer(bytesWritten)), uintptr(_p1), uintptr(_p2), uintptr(unsafe.Pointer(context)), 0, 0) r1, _, e1 := syscall.SyscallN(procBackupWrite.Addr(), uintptr(h), uintptr(unsafe.Pointer(_p0)), uintptr(len(b)), uintptr(unsafe.Pointer(bytesWritten)), uintptr(_p1), uintptr(_p2), uintptr(unsafe.Pointer(context)))
if r1 == 0 { if r1 == 0 {
err = errnoErr(e1) err = errnoErr(e1)
} }
return return
} }
func cancelIoEx(file syscall.Handle, o *syscall.Overlapped) (err error) { func cancelIoEx(file windows.Handle, o *windows.Overlapped) (err error) {
r1, _, e1 := syscall.Syscall(procCancelIoEx.Addr(), 2, uintptr(file), uintptr(unsafe.Pointer(o)), 0) r1, _, e1 := syscall.SyscallN(procCancelIoEx.Addr(), uintptr(file), uintptr(unsafe.Pointer(o)))
if r1 == 0 { if r1 == 0 {
err = errnoErr(e1) err = errnoErr(e1)
} }
return return
} }
func connectNamedPipe(pipe syscall.Handle, o *syscall.Overlapped) (err error) { func connectNamedPipe(pipe windows.Handle, o *windows.Overlapped) (err error) {
r1, _, e1 := syscall.Syscall(procConnectNamedPipe.Addr(), 2, uintptr(pipe), uintptr(unsafe.Pointer(o)), 0) r1, _, e1 := syscall.SyscallN(procConnectNamedPipe.Addr(), uintptr(pipe), uintptr(unsafe.Pointer(o)))
if r1 == 0 { if r1 == 0 {
err = errnoErr(e1) err = errnoErr(e1)
} }
return return
} }
func createIoCompletionPort(file syscall.Handle, port syscall.Handle, key uintptr, threadCount uint32) (newport syscall.Handle, err error) { func createIoCompletionPort(file windows.Handle, port windows.Handle, key uintptr, threadCount uint32) (newport windows.Handle, err error) {
r0, _, e1 := syscall.Syscall6(procCreateIoCompletionPort.Addr(), 4, uintptr(file), uintptr(port), uintptr(key), uintptr(threadCount), 0, 0) r0, _, e1 := syscall.SyscallN(procCreateIoCompletionPort.Addr(), uintptr(file), uintptr(port), uintptr(key), uintptr(threadCount))
newport = syscall.Handle(r0) newport = windows.Handle(r0)
if newport == 0 { if newport == 0 {
err = errnoErr(e1) err = errnoErr(e1)
} }
return return
} }
func createNamedPipe(name string, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *syscall.SecurityAttributes) (handle syscall.Handle, err error) { func createNamedPipe(name string, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *windows.SecurityAttributes) (handle windows.Handle, err error) {
var _p0 *uint16 var _p0 *uint16
_p0, err = syscall.UTF16PtrFromString(name) _p0, err = syscall.UTF16PtrFromString(name)
if err != nil { if err != nil {
@ -322,96 +284,93 @@ func createNamedPipe(name string, flags uint32, pipeMode uint32, maxInstances ui
return _createNamedPipe(_p0, flags, pipeMode, maxInstances, outSize, inSize, defaultTimeout, sa) return _createNamedPipe(_p0, flags, pipeMode, maxInstances, outSize, inSize, defaultTimeout, sa)
} }
func _createNamedPipe(name *uint16, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *syscall.SecurityAttributes) (handle syscall.Handle, err error) { func _createNamedPipe(name *uint16, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *windows.SecurityAttributes) (handle windows.Handle, err error) {
r0, _, e1 := syscall.Syscall9(procCreateNamedPipeW.Addr(), 8, uintptr(unsafe.Pointer(name)), uintptr(flags), uintptr(pipeMode), uintptr(maxInstances), uintptr(outSize), uintptr(inSize), uintptr(defaultTimeout), uintptr(unsafe.Pointer(sa)), 0) r0, _, e1 := syscall.SyscallN(procCreateNamedPipeW.Addr(), uintptr(unsafe.Pointer(name)), uintptr(flags), uintptr(pipeMode), uintptr(maxInstances), uintptr(outSize), uintptr(inSize), uintptr(defaultTimeout), uintptr(unsafe.Pointer(sa)))
handle = syscall.Handle(r0) handle = windows.Handle(r0)
if handle == syscall.InvalidHandle { if handle == windows.InvalidHandle {
err = errnoErr(e1) err = errnoErr(e1)
} }
return return
} }
func getCurrentThread() (h syscall.Handle) { func disconnectNamedPipe(pipe windows.Handle) (err error) {
r0, _, _ := syscall.Syscall(procGetCurrentThread.Addr(), 0, 0, 0, 0) r1, _, e1 := syscall.SyscallN(procDisconnectNamedPipe.Addr(), uintptr(pipe))
h = syscall.Handle(r0)
return
}
func getNamedPipeHandleState(pipe syscall.Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) {
r1, _, e1 := syscall.Syscall9(procGetNamedPipeHandleStateW.Addr(), 7, uintptr(pipe), uintptr(unsafe.Pointer(state)), uintptr(unsafe.Pointer(curInstances)), uintptr(unsafe.Pointer(maxCollectionCount)), uintptr(unsafe.Pointer(collectDataTimeout)), uintptr(unsafe.Pointer(userName)), uintptr(maxUserNameSize), 0, 0)
if r1 == 0 { if r1 == 0 {
err = errnoErr(e1) err = errnoErr(e1)
} }
return return
} }
func getNamedPipeInfo(pipe syscall.Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error) { func getCurrentThread() (h windows.Handle) {
r1, _, e1 := syscall.Syscall6(procGetNamedPipeInfo.Addr(), 5, uintptr(pipe), uintptr(unsafe.Pointer(flags)), uintptr(unsafe.Pointer(outSize)), uintptr(unsafe.Pointer(inSize)), uintptr(unsafe.Pointer(maxInstances)), 0) r0, _, _ := syscall.SyscallN(procGetCurrentThread.Addr())
h = windows.Handle(r0)
return
}
func getNamedPipeHandleState(pipe windows.Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) {
r1, _, e1 := syscall.SyscallN(procGetNamedPipeHandleStateW.Addr(), uintptr(pipe), uintptr(unsafe.Pointer(state)), uintptr(unsafe.Pointer(curInstances)), uintptr(unsafe.Pointer(maxCollectionCount)), uintptr(unsafe.Pointer(collectDataTimeout)), uintptr(unsafe.Pointer(userName)), uintptr(maxUserNameSize))
if r1 == 0 { if r1 == 0 {
err = errnoErr(e1) err = errnoErr(e1)
} }
return return
} }
func getQueuedCompletionStatus(port syscall.Handle, bytes *uint32, key *uintptr, o **ioOperation, timeout uint32) (err error) { func getNamedPipeInfo(pipe windows.Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error) {
r1, _, e1 := syscall.Syscall6(procGetQueuedCompletionStatus.Addr(), 5, uintptr(port), uintptr(unsafe.Pointer(bytes)), uintptr(unsafe.Pointer(key)), uintptr(unsafe.Pointer(o)), uintptr(timeout), 0) r1, _, e1 := syscall.SyscallN(procGetNamedPipeInfo.Addr(), uintptr(pipe), uintptr(unsafe.Pointer(flags)), uintptr(unsafe.Pointer(outSize)), uintptr(unsafe.Pointer(inSize)), uintptr(unsafe.Pointer(maxInstances)))
if r1 == 0 { if r1 == 0 {
err = errnoErr(e1) err = errnoErr(e1)
} }
return return
} }
func localAlloc(uFlags uint32, length uint32) (ptr uintptr) { func getQueuedCompletionStatus(port windows.Handle, bytes *uint32, key *uintptr, o **ioOperation, timeout uint32) (err error) {
r0, _, _ := syscall.Syscall(procLocalAlloc.Addr(), 2, uintptr(uFlags), uintptr(length), 0) r1, _, e1 := syscall.SyscallN(procGetQueuedCompletionStatus.Addr(), uintptr(port), uintptr(unsafe.Pointer(bytes)), uintptr(unsafe.Pointer(key)), uintptr(unsafe.Pointer(o)), uintptr(timeout))
ptr = uintptr(r0)
return
}
func localFree(mem uintptr) {
syscall.Syscall(procLocalFree.Addr(), 1, uintptr(mem), 0, 0)
return
}
func setFileCompletionNotificationModes(h syscall.Handle, flags uint8) (err error) {
r1, _, e1 := syscall.Syscall(procSetFileCompletionNotificationModes.Addr(), 2, uintptr(h), uintptr(flags), 0)
if r1 == 0 { if r1 == 0 {
err = errnoErr(e1) err = errnoErr(e1)
} }
return return
} }
func ntCreateNamedPipeFile(pipe *syscall.Handle, access uint32, oa *objectAttributes, iosb *ioStatusBlock, share uint32, disposition uint32, options uint32, typ uint32, readMode uint32, completionMode uint32, maxInstances uint32, inboundQuota uint32, outputQuota uint32, timeout *int64) (status ntStatus) { func setFileCompletionNotificationModes(h windows.Handle, flags uint8) (err error) {
r0, _, _ := syscall.Syscall15(procNtCreateNamedPipeFile.Addr(), 14, uintptr(unsafe.Pointer(pipe)), uintptr(access), uintptr(unsafe.Pointer(oa)), uintptr(unsafe.Pointer(iosb)), uintptr(share), uintptr(disposition), uintptr(options), uintptr(typ), uintptr(readMode), uintptr(completionMode), uintptr(maxInstances), uintptr(inboundQuota), uintptr(outputQuota), uintptr(unsafe.Pointer(timeout)), 0) r1, _, e1 := syscall.SyscallN(procSetFileCompletionNotificationModes.Addr(), uintptr(h), uintptr(flags))
if r1 == 0 {
err = errnoErr(e1)
}
return
}
func ntCreateNamedPipeFile(pipe *windows.Handle, access ntAccessMask, oa *objectAttributes, iosb *ioStatusBlock, share ntFileShareMode, disposition ntFileCreationDisposition, options ntFileOptions, typ uint32, readMode uint32, completionMode uint32, maxInstances uint32, inboundQuota uint32, outputQuota uint32, timeout *int64) (status ntStatus) {
r0, _, _ := syscall.SyscallN(procNtCreateNamedPipeFile.Addr(), uintptr(unsafe.Pointer(pipe)), uintptr(access), uintptr(unsafe.Pointer(oa)), uintptr(unsafe.Pointer(iosb)), uintptr(share), uintptr(disposition), uintptr(options), uintptr(typ), uintptr(readMode), uintptr(completionMode), uintptr(maxInstances), uintptr(inboundQuota), uintptr(outputQuota), uintptr(unsafe.Pointer(timeout)))
status = ntStatus(r0) status = ntStatus(r0)
return return
} }
func rtlDefaultNpAcl(dacl *uintptr) (status ntStatus) { func rtlDefaultNpAcl(dacl *uintptr) (status ntStatus) {
r0, _, _ := syscall.Syscall(procRtlDefaultNpAcl.Addr(), 1, uintptr(unsafe.Pointer(dacl)), 0, 0) r0, _, _ := syscall.SyscallN(procRtlDefaultNpAcl.Addr(), uintptr(unsafe.Pointer(dacl)))
status = ntStatus(r0) status = ntStatus(r0)
return return
} }
func rtlDosPathNameToNtPathName(name *uint16, ntName *unicodeString, filePart uintptr, reserved uintptr) (status ntStatus) { func rtlDosPathNameToNtPathName(name *uint16, ntName *unicodeString, filePart uintptr, reserved uintptr) (status ntStatus) {
r0, _, _ := syscall.Syscall6(procRtlDosPathNameToNtPathName_U.Addr(), 4, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(ntName)), uintptr(filePart), uintptr(reserved), 0, 0) r0, _, _ := syscall.SyscallN(procRtlDosPathNameToNtPathName_U.Addr(), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(ntName)), uintptr(filePart), uintptr(reserved))
status = ntStatus(r0) status = ntStatus(r0)
return return
} }
func rtlNtStatusToDosError(status ntStatus) (winerr error) { func rtlNtStatusToDosError(status ntStatus) (winerr error) {
r0, _, _ := syscall.Syscall(procRtlNtStatusToDosErrorNoTeb.Addr(), 1, uintptr(status), 0, 0) r0, _, _ := syscall.SyscallN(procRtlNtStatusToDosErrorNoTeb.Addr(), uintptr(status))
if r0 != 0 { if r0 != 0 {
winerr = syscall.Errno(r0) winerr = syscall.Errno(r0)
} }
return return
} }
func wsaGetOverlappedResult(h syscall.Handle, o *syscall.Overlapped, bytes *uint32, wait bool, flags *uint32) (err error) { func wsaGetOverlappedResult(h windows.Handle, o *windows.Overlapped, bytes *uint32, wait bool, flags *uint32) (err error) {
var _p0 uint32 var _p0 uint32
if wait { if wait {
_p0 = 1 _p0 = 1
} }
r1, _, e1 := syscall.Syscall6(procWSAGetOverlappedResult.Addr(), 5, uintptr(h), uintptr(unsafe.Pointer(o)), uintptr(unsafe.Pointer(bytes)), uintptr(_p0), uintptr(unsafe.Pointer(flags)), 0) r1, _, e1 := syscall.SyscallN(procWSAGetOverlappedResult.Addr(), uintptr(h), uintptr(unsafe.Pointer(o)), uintptr(unsafe.Pointer(bytes)), uintptr(_p0), uintptr(unsafe.Pointer(flags)))
if r1 == 0 { if r1 == 0 {
err = errnoErr(e1) err = errnoErr(e1)
} }

View File

@ -37,6 +37,10 @@ rootfs-conv/*
deps/* deps/*
out/* out/*
# protobuf files
# only files at root of the repo, otherwise this will cause issues with vendoring
/protobuf/*
# test results # test results
test/results test/results

View File

@ -135,3 +135,14 @@ issues:
linters: linters:
- stylecheck - stylecheck
Text: "ST1003:" Text: "ST1003:"
# v0 APIs are deprecated, but still retained for backwards compatability
- path: cmd\\ncproxy\\
linters:
- staticcheck
text: "^SA1019: .*(ncproxygrpc|nodenetsvc)[/]?v0"
- path: internal\\tools\\networkagent
linters:
- staticcheck
text: "^SA1019: .*nodenetsvc[/]?v0"

View File

@ -94,23 +94,9 @@ out/delta.tar.gz: bin/init bin/vsockexec bin/cmd/gcs bin/cmd/gcstools bin/cmd/ho
tar -zcf $@ -C rootfs . tar -zcf $@ -C rootfs .
rm -rf rootfs rm -rf rootfs
-include deps/cmd/gcs.gomake bin/cmd/gcs bin/cmd/gcstools bin/cmd/hooks/wait-paths bin/cmd/tar2ext4 bin/internal/tools/snp-report:
-include deps/cmd/gcstools.gomake
-include deps/cmd/hooks/wait-paths.gomake
-include deps/cmd/tar2ext4.gomake
-include deps/internal/tools/snp-report.gomake
# Implicit rule for includes that define Go targets.
%.gomake: $(SRCROOT)/Makefile
@mkdir -p $(dir $@) @mkdir -p $(dir $@)
@/bin/echo $(@:deps/%.gomake=bin/%): $(SRCROOT)/hack/gomakedeps.sh > $@.new GOOS=linux $(GO_BUILD) -o $@ $(SRCROOT)/$(@:bin/%=%)
@/bin/echo -e '\t@mkdir -p $$(dir $$@) $(dir $@)' >> $@.new
@/bin/echo -e '\t$$(GO_BUILD) -o $$@.new $$(SRCROOT)/$$(@:bin/%=%)' >> $@.new
@/bin/echo -e '\tGO="$(GO)" $$(SRCROOT)/hack/gomakedeps.sh $$@ $$(SRCROOT)/$$(@:bin/%=%) $$(GO_FLAGS) $$(GO_FLAGS_EXTRA) > $(@:%.gomake=%.godeps).new' >> $@.new
@/bin/echo -e '\tmv $(@:%.gomake=%.godeps).new $(@:%.gomake=%.godeps)' >> $@.new
@/bin/echo -e '\tmv $$@.new $$@' >> $@.new
@/bin/echo -e '-include $(@:%.gomake=%.godeps)' >> $@.new
mv $@.new $@
bin/vsockexec: vsockexec/vsockexec.o vsockexec/vsock.o bin/vsockexec: vsockexec/vsockexec.o vsockexec/vsock.o
@mkdir -p bin @mkdir -p bin

View File

@ -9,6 +9,10 @@ plugins = ["grpc", "fieldpath"]
# treat the root of the project as an include, but this may not be necessary. # treat the root of the project as an include, but this may not be necessary.
before = ["./protobuf"] before = ["./protobuf"]
# defaults are "/usr/local/include" and "/usr/include", which don't exist on Windows.
# override defaults to supress errors about non-existant directories.
after = []
# Paths that should be treated as include roots in relation to the vendor # Paths that should be treated as include roots in relation to the vendor
# directory. These will be calculated with the vendor directory nearest the # directory. These will be calculated with the vendor directory nearest the
# target package. # target package.

View File

@ -33,9 +33,6 @@ func errnoErr(e syscall.Errno) error {
case errnoERROR_IO_PENDING: case errnoERROR_IO_PENDING:
return errERROR_IO_PENDING return errERROR_IO_PENDING
} }
// TODO: add more here, after collecting data on the common
// error values see on Windows. (perhaps when running
// all.bat?)
return e return e
} }
@ -73,7 +70,7 @@ func _hcsAttachLayerStorageFilter(layerPath *uint16, layerData *uint16) (hr erro
if hr != nil { if hr != nil {
return return
} }
r0, _, _ := syscall.Syscall(procHcsAttachLayerStorageFilter.Addr(), 2, uintptr(unsafe.Pointer(layerPath)), uintptr(unsafe.Pointer(layerData)), 0) r0, _, _ := syscall.SyscallN(procHcsAttachLayerStorageFilter.Addr(), uintptr(unsafe.Pointer(layerPath)), uintptr(unsafe.Pointer(layerData)))
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -97,7 +94,7 @@ func _hcsDestroyLayer(layerPath *uint16) (hr error) {
if hr != nil { if hr != nil {
return return
} }
r0, _, _ := syscall.Syscall(procHcsDestoryLayer.Addr(), 1, uintptr(unsafe.Pointer(layerPath)), 0, 0) r0, _, _ := syscall.SyscallN(procHcsDestoryLayer.Addr(), uintptr(unsafe.Pointer(layerPath)))
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -121,7 +118,7 @@ func _hcsDetachLayerStorageFilter(layerPath *uint16) (hr error) {
if hr != nil { if hr != nil {
return return
} }
r0, _, _ := syscall.Syscall(procHcsDetachLayerStorageFilter.Addr(), 1, uintptr(unsafe.Pointer(layerPath)), 0, 0) r0, _, _ := syscall.SyscallN(procHcsDetachLayerStorageFilter.Addr(), uintptr(unsafe.Pointer(layerPath)))
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -160,7 +157,7 @@ func _hcsExportLayer(layerPath *uint16, exportFolderPath *uint16, layerData *uin
if hr != nil { if hr != nil {
return return
} }
r0, _, _ := syscall.Syscall6(procHcsExportLayer.Addr(), 4, uintptr(unsafe.Pointer(layerPath)), uintptr(unsafe.Pointer(exportFolderPath)), uintptr(unsafe.Pointer(layerData)), uintptr(unsafe.Pointer(options)), 0, 0) r0, _, _ := syscall.SyscallN(procHcsExportLayer.Addr(), uintptr(unsafe.Pointer(layerPath)), uintptr(unsafe.Pointer(exportFolderPath)), uintptr(unsafe.Pointer(layerData)), uintptr(unsafe.Pointer(options)))
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -175,7 +172,7 @@ func hcsFormatWritableLayerVhd(handle windows.Handle) (hr error) {
if hr != nil { if hr != nil {
return return
} }
r0, _, _ := syscall.Syscall(procHcsFormatWritableLayerVhd.Addr(), 1, uintptr(handle), 0, 0) r0, _, _ := syscall.SyscallN(procHcsFormatWritableLayerVhd.Addr(), uintptr(handle))
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -190,7 +187,7 @@ func hcsGetLayerVhdMountPath(vhdHandle windows.Handle, mountPath **uint16) (hr e
if hr != nil { if hr != nil {
return return
} }
r0, _, _ := syscall.Syscall(procHcsGetLayerVhdMountPath.Addr(), 2, uintptr(vhdHandle), uintptr(unsafe.Pointer(mountPath)), 0) r0, _, _ := syscall.SyscallN(procHcsGetLayerVhdMountPath.Addr(), uintptr(vhdHandle), uintptr(unsafe.Pointer(mountPath)))
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -224,7 +221,7 @@ func _hcsImportLayer(layerPath *uint16, sourceFolderPath *uint16, layerData *uin
if hr != nil { if hr != nil {
return return
} }
r0, _, _ := syscall.Syscall(procHcsImportLayer.Addr(), 3, uintptr(unsafe.Pointer(layerPath)), uintptr(unsafe.Pointer(sourceFolderPath)), uintptr(unsafe.Pointer(layerData))) r0, _, _ := syscall.SyscallN(procHcsImportLayer.Addr(), uintptr(unsafe.Pointer(layerPath)), uintptr(unsafe.Pointer(sourceFolderPath)), uintptr(unsafe.Pointer(layerData)))
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -258,7 +255,7 @@ func _hcsInitializeWritableLayer(writableLayerPath *uint16, layerData *uint16, o
if hr != nil { if hr != nil {
return return
} }
r0, _, _ := syscall.Syscall(procHcsInitializeWritableLayer.Addr(), 3, uintptr(unsafe.Pointer(writableLayerPath)), uintptr(unsafe.Pointer(layerData)), uintptr(unsafe.Pointer(options))) r0, _, _ := syscall.SyscallN(procHcsInitializeWritableLayer.Addr(), uintptr(unsafe.Pointer(writableLayerPath)), uintptr(unsafe.Pointer(layerData)), uintptr(unsafe.Pointer(options)))
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -287,7 +284,7 @@ func _hcsSetupBaseOSLayer(layerPath *uint16, handle windows.Handle, options *uin
if hr != nil { if hr != nil {
return return
} }
r0, _, _ := syscall.Syscall(procHcsSetupBaseOSLayer.Addr(), 3, uintptr(unsafe.Pointer(layerPath)), uintptr(handle), uintptr(unsafe.Pointer(options))) r0, _, _ := syscall.SyscallN(procHcsSetupBaseOSLayer.Addr(), uintptr(unsafe.Pointer(layerPath)), uintptr(handle), uintptr(unsafe.Pointer(options)))
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -321,7 +318,7 @@ func _hcsSetupBaseOSVolume(layerPath *uint16, volumePath *uint16, options *uint1
if hr != nil { if hr != nil {
return return
} }
r0, _, _ := syscall.Syscall(procHcsSetupBaseOSVolume.Addr(), 3, uintptr(unsafe.Pointer(layerPath)), uintptr(unsafe.Pointer(volumePath)), uintptr(unsafe.Pointer(options))) r0, _, _ := syscall.SyscallN(procHcsSetupBaseOSVolume.Addr(), uintptr(unsafe.Pointer(layerPath)), uintptr(unsafe.Pointer(volumePath)), uintptr(unsafe.Pointer(options)))
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff

View File

@ -421,12 +421,6 @@ func (process *Process) CloseStdin(ctx context.Context) (err error) {
return makeProcessError(process, operation, ErrAlreadyClosed, nil) return makeProcessError(process, operation, ErrAlreadyClosed, nil)
} }
process.stdioLock.Lock()
defer process.stdioLock.Unlock()
if process.stdin == nil {
return nil
}
//HcsModifyProcess request to close stdin will fail if the process has already exited //HcsModifyProcess request to close stdin will fail if the process has already exited
if !process.stopped() { if !process.stopped() {
modifyRequest := processModifyRequest{ modifyRequest := processModifyRequest{
@ -448,8 +442,12 @@ func (process *Process) CloseStdin(ctx context.Context) (err error) {
} }
} }
process.stdioLock.Lock()
defer process.stdioLock.Unlock()
if process.stdin != nil {
process.stdin.Close() process.stdin.Close()
process.stdin = nil process.stdin = nil
}
return nil return nil
} }

View File

@ -14,14 +14,14 @@ import (
"golang.org/x/sys/windows" "golang.org/x/sys/windows"
) )
// makeOpenFiles calls winio.MakeOpenFile for each handle in a slice but closes all the handles // makeOpenFiles calls winio.NewOpenFile for each handle in a slice but closes all the handles
// if there is an error. // if there is an error.
func makeOpenFiles(hs []syscall.Handle) (_ []io.ReadWriteCloser, err error) { func makeOpenFiles(hs []syscall.Handle) (_ []io.ReadWriteCloser, err error) {
fs := make([]io.ReadWriteCloser, len(hs)) fs := make([]io.ReadWriteCloser, len(hs))
for i, h := range hs { for i, h := range hs {
if h != syscall.Handle(0) { if h != syscall.Handle(0) {
if err == nil { if err == nil {
fs[i], err = winio.MakeOpenFile(h) fs[i], err = winio.NewOpenFile(windows.Handle(h))
} }
if err != nil { if err != nil {
syscall.Close(h) syscall.Close(h)

View File

@ -10,6 +10,28 @@ import (
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
// EndpointState represents the states of an HNS Endpoint lifecycle.
type EndpointState uint16
// EndpointState const
// The lifecycle of an Endpoint goes through created, attached, AttachedSharing - endpoint is being shared with other containers,
// detached, after being attached, degraded and finally destroyed.
// Note: This attribute is used by calico to define stale containers and is dependent on HNS v1 api, if we move to HNS v2 api we will need
// to update the current calico code and cordinate the change with calico. Reach out to Microsoft to facilate the change via HNS.
const (
Uninitialized EndpointState = iota
Created EndpointState = 1
Attached EndpointState = 2
AttachedSharing EndpointState = 3
Detached EndpointState = 4
Degraded EndpointState = 5
Destroyed EndpointState = 6
)
func (es EndpointState) String() string {
return [...]string{"Uninitialized", "Attached", "AttachedSharing", "Detached", "Degraded", "Destroyed"}[es]
}
// HNSEndpoint represents a network endpoint in HNS // HNSEndpoint represents a network endpoint in HNS
type HNSEndpoint struct { type HNSEndpoint struct {
Id string `json:"ID,omitempty"` Id string `json:"ID,omitempty"`
@ -34,6 +56,7 @@ type HNSEndpoint struct {
Namespace *Namespace `json:",omitempty"` Namespace *Namespace `json:",omitempty"`
EncapOverhead uint16 `json:",omitempty"` EncapOverhead uint16 `json:",omitempty"`
SharedContainers []string `json:",omitempty"` SharedContainers []string `json:",omitempty"`
State EndpointState `json:",omitempty"`
} }
// SystemType represents the type of the system on which actions are done // SystemType represents the type of the system on which actions are done

View File

@ -60,6 +60,7 @@ type OutboundNatPolicy struct {
VIP string `json:"VIP,omitempty"` VIP string `json:"VIP,omitempty"`
Exceptions []string `json:"ExceptionList,omitempty"` Exceptions []string `json:"ExceptionList,omitempty"`
Destinations []string `json:",omitempty"` Destinations []string `json:",omitempty"`
MaxPortPoolUsage uint16 `json:",omitempty"`
} }
type ProxyPolicy struct { type ProxyPolicy struct {

View File

@ -33,9 +33,6 @@ func errnoErr(e syscall.Errno) error {
case errnoERROR_IO_PENDING: case errnoERROR_IO_PENDING:
return errERROR_IO_PENDING return errERROR_IO_PENDING
} }
// TODO: add more here, after collecting data on the common
// error values see on Windows. (perhaps when running
// all.bat?)
return e return e
} }
@ -69,7 +66,7 @@ func __hnsCall(method *uint16, path *uint16, object *uint16, response **uint16)
if hr != nil { if hr != nil {
return return
} }
r0, _, _ := syscall.Syscall6(procHNSCall.Addr(), 4, uintptr(unsafe.Pointer(method)), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(object)), uintptr(unsafe.Pointer(response)), 0, 0) r0, _, _ := syscall.SyscallN(procHNSCall.Addr(), uintptr(unsafe.Pointer(method)), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(object)), uintptr(unsafe.Pointer(response)))
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff

View File

@ -33,9 +33,6 @@ func errnoErr(e syscall.Errno) error {
case errnoERROR_IO_PENDING: case errnoERROR_IO_PENDING:
return errERROR_IO_PENDING return errERROR_IO_PENDING
} }
// TODO: add more here, after collecting data on the common
// error values see on Windows. (perhaps when running
// all.bat?)
return e return e
} }
@ -46,6 +43,6 @@ var (
) )
func coTaskMemFree(buffer unsafe.Pointer) { func coTaskMemFree(buffer unsafe.Pointer) {
syscall.Syscall(procCoTaskMemFree.Addr(), 1, uintptr(buffer), 0, 0) syscall.SyscallN(procCoTaskMemFree.Addr(), uintptr(buffer))
return return
} }

View File

@ -0,0 +1,87 @@
package log
import (
"bytes"
"context"
"encoding/json"
"fmt"
"net"
"reflect"
"time"
)
// TimeFormat is [time.RFC3339Nano] with nanoseconds padded using
// zeros to ensure the formatted time is always the same number of
// characters.
// Based on RFC3339NanoFixed from github.com/containerd/log
const TimeFormat = "2006-01-02T15:04:05.000000000Z07:00"
func FormatTime(t time.Time) string {
return t.Format(TimeFormat)
}
// DurationFormat formats a [time.Duration] log entry.
//
// A nil value signals an error with the formatting.
type DurationFormat func(time.Duration) interface{}
func DurationFormatString(d time.Duration) interface{} { return d.String() }
func DurationFormatSeconds(d time.Duration) interface{} { return d.Seconds() }
func DurationFormatMilliseconds(d time.Duration) interface{} { return d.Milliseconds() }
// FormatIO formats net.Conn and other types that have an `Addr()` or `Name()`.
//
// See FormatEnabled for more information.
func FormatIO(ctx context.Context, v interface{}) string {
m := make(map[string]string)
m["type"] = reflect.TypeOf(v).String()
switch t := v.(type) {
case net.Conn:
m["localAddress"] = formatAddr(t.LocalAddr())
m["remoteAddress"] = formatAddr(t.RemoteAddr())
case interface{ Addr() net.Addr }:
m["address"] = formatAddr(t.Addr())
default:
return Format(ctx, t)
}
return Format(ctx, m)
}
func formatAddr(a net.Addr) string {
return a.Network() + "://" + a.String()
}
// Format formats an object into a JSON string, without any indendtation or
// HTML escapes.
// Context is used to output a log waring if the conversion fails.
//
// This is intended primarily for `trace.StringAttribute()`
func Format(ctx context.Context, v interface{}) string {
b, err := encode(v)
if err != nil {
G(ctx).WithError(err).Warning("could not format value")
return ""
}
return string(b)
}
func encode(v interface{}) ([]byte, error) {
return encodeBuffer(&bytes.Buffer{}, v)
}
func encodeBuffer(buf *bytes.Buffer, v interface{}) ([]byte, error) {
enc := json.NewEncoder(buf)
enc.SetEscapeHTML(false)
enc.SetIndent("", "")
if err := enc.Encode(v); err != nil {
err = fmt.Errorf("could not marshall %T to JSON for logging: %w", v, err)
return nil, err
}
// encoder.Encode appends a newline to the end
return bytes.TrimSpace(buf.Bytes()), nil
}

View File

@ -1,23 +1,57 @@
package log package log
import ( import (
"bytes"
"reflect"
"time"
"github.com/Microsoft/hcsshim/internal/logfields" "github.com/Microsoft/hcsshim/internal/logfields"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"go.opencensus.io/trace" "go.opencensus.io/trace"
) )
// Hook serves to intercept and format `logrus.Entry`s before they are passed const nullString = "null"
// to the ETW hook.
// Hook intercepts and formats a [logrus.Entry] before it logged.
// //
// The containerd shim discards the (formatted) logrus output, and outputs only via ETW. // The shim either outputs the logs through an ETW hook, discarding the (formatted) output
// The Linux GCS outputs logrus entries over stdout, which is consumed by the shim and // or logs output to a pipe for logging binaries to consume.
// then re-output via the ETW hook. // The Linux GCS outputs logrus entries over stdout, which is then consumed and re-output
type Hook struct{} // by the shim.
type Hook struct {
// EncodeAsJSON formats structs, maps, arrays, slices, and [bytes.Buffer] as JSON.
// Variables of [bytes.Buffer] will be converted to []byte.
//
// Default is false.
EncodeAsJSON bool
// FormatTime specifies the format for [time.Time] variables.
// An empty string disables formatting.
// When disabled, the fall back will the JSON encoding, if enabled.
//
// Default is [TimeFormat].
TimeFormat string
// Duration format converts a [time.Duration] fields to an appropriate encoding.
// nil disables formatting.
// When disabled, the fall back will the JSON encoding, if enabled.
//
// Default is [DurationFormatString], which appends a duration unit after the value.
DurationFormat DurationFormat
// AddSpanContext adds [logfields.TraceID] and [logfields.SpanID] fields to
// the entry from the span context stored in [logrus.Entry.Context], if it exists.
AddSpanContext bool
}
var _ logrus.Hook = &Hook{} var _ logrus.Hook = &Hook{}
func NewHook() *Hook { func NewHook() *Hook {
return &Hook{} return &Hook{
TimeFormat: TimeFormat,
DurationFormat: DurationFormatString,
AddSpanContext: true,
}
} }
func (h *Hook) Levels() []logrus.Level { func (h *Hook) Levels() []logrus.Level {
@ -25,14 +59,108 @@ func (h *Hook) Levels() []logrus.Level {
} }
func (h *Hook) Fire(e *logrus.Entry) (err error) { func (h *Hook) Fire(e *logrus.Entry) (err error) {
// JSON encode, if necessary, then add span information
h.encode(e)
h.addSpanContext(e) h.addSpanContext(e)
return nil return nil
} }
// encode loops through all the fields in the [logrus.Entry] and encodes them according to
// the settings in [Hook].
// If [Hook.TimeFormat] is non-empty, it will be passed to [time.Time.Format] for
// fields of type [time.Time].
//
// If [Hook.EncodeAsJSON] is true, then fields that are not numeric, boolean, strings, or
// errors will be encoded via a [json.Marshal] (with HTML escaping disabled).
// Chanel- and function-typed fields, as well as unsafe pointers are left alone and not encoded.
//
// If [Hook.TimeFormat] and [Hook.DurationFormat] are empty and [Hook.EncodeAsJSON] is false,
// then this is a no-op.
func (h *Hook) encode(e *logrus.Entry) {
d := e.Data
formatTime := h.TimeFormat != ""
formatDuration := h.DurationFormat != nil
if !(h.EncodeAsJSON || formatTime || formatDuration) {
return
}
for k, v := range d {
// encode types with dedicated formatting options first
if vv, ok := v.(time.Time); formatTime && ok {
d[k] = vv.Format(h.TimeFormat)
continue
}
if vv, ok := v.(time.Duration); formatDuration && ok {
d[k] = h.DurationFormat(vv)
continue
}
// general case JSON encoding
if !h.EncodeAsJSON {
continue
}
switch vv := v.(type) {
// built in types
// "json" marshals errors as "{}", so leave alone here
case bool, string, error, uintptr,
int8, int16, int32, int64, int,
uint8, uint32, uint64, uint,
float32, float64:
continue
// Rather than setting d[k] = vv.String(), JSON encode []byte value, since it
// may be a binary payload and not representable as a string.
// `case bytes.Buffer,*bytes.Buffer:` resolves `vv` to `interface{}`,
// so cannot use `vv.Bytes`.
// Could move to below the `reflect.Indirect()` call below, but
// that would require additional typematching and dereferencing.
// Easier to keep these duplicate branches here.
case bytes.Buffer:
v = vv.Bytes()
case *bytes.Buffer:
v = vv.Bytes()
}
// dereference pointer or interface variables
rv := reflect.Indirect(reflect.ValueOf(v))
// check if `v` is a null pointer
if !rv.IsValid() {
d[k] = nullString
continue
}
switch rv.Kind() {
case reflect.Map, reflect.Struct, reflect.Array, reflect.Slice:
default:
// Bool, [U]?Int*, Float*, Complex*, Uintptr, String: encoded as normal
// Chan, Func: not supported by json
// Interface, Pointer: dereferenced above
// UnsafePointer: not supported by json, not safe to de-reference; leave alone
continue
}
b, err := encode(v)
if err != nil {
// Errors are written to stderr (ie, to `panic.log`) and stops the remaining
// hooks (ie, exporting to ETW) from firing. So add encoding errors to
// the entry data to be written out, but keep on processing.
d[k+"-"+logrus.ErrorKey] = err.Error()
// keep the original `v` as the value,
continue
}
d[k] = string(b)
}
}
func (h *Hook) addSpanContext(e *logrus.Entry) { func (h *Hook) addSpanContext(e *logrus.Entry) {
ctx := e.Context ctx := e.Context
if ctx == nil { if !h.AddSpanContext || ctx == nil {
return return
} }
span := trace.FromContext(ctx) span := trace.FromContext(ctx)

View File

@ -4,7 +4,6 @@ import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"errors" "errors"
"strings"
"sync/atomic" "sync/atomic"
hcsschema "github.com/Microsoft/hcsshim/internal/hcs/schema2" hcsschema "github.com/Microsoft/hcsshim/internal/hcs/schema2"
@ -56,11 +55,11 @@ func ScrubProcessParameters(s string) (string, error) {
} }
pp.Environment = map[string]string{_scrubbedReplacement: _scrubbedReplacement} pp.Environment = map[string]string{_scrubbedReplacement: _scrubbedReplacement}
buf := bytes.NewBuffer(b[:0]) b, err := encodeBuffer(bytes.NewBuffer(b[:0]), pp)
if err := encode(buf, pp); err != nil { if err != nil {
return "", err return "", err
} }
return strings.TrimSpace(buf.String()), nil return string(b), nil
} }
// ScrubBridgeCreate scrubs requests sent over the bridge of type // ScrubBridgeCreate scrubs requests sent over the bridge of type
@ -150,21 +149,12 @@ func scrubBytes(b []byte, scrub scrubberFunc) ([]byte, error) {
return nil, err return nil, err
} }
buf := &bytes.Buffer{} b, err := encode(m)
if err := encode(buf, m); err != nil { if err != nil {
return nil, err return nil, err
} }
return bytes.TrimSpace(buf.Bytes()), nil return b, nil
}
func encode(buf *bytes.Buffer, v interface{}) error {
enc := json.NewEncoder(buf)
enc.SetEscapeHTML(false)
if err := enc.Encode(v); err != nil {
return err
}
return nil
} }
func isRequestBase(m genMap) bool { func isRequestBase(m genMap) bool {

View File

@ -0,0 +1,69 @@
package oc
import (
"errors"
"io"
"net"
"os"
"github.com/containerd/containerd/errdefs"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
// todo: break import cycle with "internal/hcs/errors.go" and reference errors defined there
// todo: add errors defined in "internal/guest/gcserror" (Hresult does not implement error)
func toStatusCode(err error) codes.Code {
// checks if err implements GRPCStatus() *"google.golang.org/grpc/status".Status,
// wraps an error defined in "github.com/containerd/containerd/errdefs", or is a
// context timeout or cancelled error
if s, ok := status.FromError(errdefs.ToGRPC(err)); ok {
return s.Code()
}
switch {
// case isAny(err):
// return codes.Cancelled
case isAny(err, os.ErrInvalid):
return codes.InvalidArgument
case isAny(err, os.ErrDeadlineExceeded):
return codes.DeadlineExceeded
case isAny(err, os.ErrNotExist):
return codes.NotFound
case isAny(err, os.ErrExist):
return codes.AlreadyExists
case isAny(err, os.ErrPermission):
return codes.PermissionDenied
// case isAny(err):
// return codes.ResourceExhausted
case isAny(err, os.ErrClosed, net.ErrClosed, io.ErrClosedPipe, io.ErrShortBuffer):
return codes.FailedPrecondition
// case isAny(err):
// return codes.Aborted
// case isAny(err):
// return codes.OutOfRange
// case isAny(err):
// return codes.Unimplemented
case isAny(err, io.ErrNoProgress):
return codes.Internal
// case isAny(err):
// return codes.Unavailable
case isAny(err, io.ErrShortWrite, io.ErrUnexpectedEOF):
return codes.DataLoss
// case isAny(err):
// return codes.Unauthenticated
default:
return codes.Unknown
}
}
// isAny returns true if errors.Is is true for any of the provided errors, errs.
func isAny(err error, errs ...error) bool {
for _, e := range errs {
if errors.Is(err, e) {
return true
}
}
return false
}

View File

@ -3,19 +3,26 @@ package oc
import ( import (
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"go.opencensus.io/trace" "go.opencensus.io/trace"
"google.golang.org/grpc/codes"
"github.com/Microsoft/hcsshim/internal/log"
"github.com/Microsoft/hcsshim/internal/logfields"
) )
var _ = (trace.Exporter)(&LogrusExporter{}) const spanMessage = "Span"
var _errorCodeKey = logrus.ErrorKey + "Code"
// LogrusExporter is an OpenCensus `trace.Exporter` that exports // LogrusExporter is an OpenCensus `trace.Exporter` that exports
// `trace.SpanData` to logrus output. // `trace.SpanData` to logrus output.
type LogrusExporter struct { type LogrusExporter struct{}
}
var _ trace.Exporter = &LogrusExporter{}
// ExportSpan exports `s` based on the the following rules: // ExportSpan exports `s` based on the the following rules:
// //
// 1. All output will contain `s.Attributes`, `s.TraceID`, `s.SpanID`, // 1. All output will contain `s.Attributes`, `s.SpanKind`, `s.TraceID`,
// `s.ParentSpanID` for correlation // `s.SpanID`, and `s.ParentSpanID` for correlation
// //
// 2. Any calls to .Annotate will not be supported. // 2. Any calls to .Annotate will not be supported.
// //
@ -23,21 +30,57 @@ type LogrusExporter struct {
// `s.Status.Code != 0` in which case it will be written at `logrus.ErrorLevel` // `s.Status.Code != 0` in which case it will be written at `logrus.ErrorLevel`
// providing `s.Status.Message` as the error value. // providing `s.Status.Message` as the error value.
func (le *LogrusExporter) ExportSpan(s *trace.SpanData) { func (le *LogrusExporter) ExportSpan(s *trace.SpanData) {
// Combine all span annotations with traceID, spanID, parentSpanID if s.DroppedAnnotationCount > 0 {
baseEntry := logrus.WithFields(logrus.Fields(s.Attributes)) logrus.WithFields(logrus.Fields{
baseEntry.Data["traceID"] = s.TraceID.String() "name": s.Name,
baseEntry.Data["spanID"] = s.SpanID.String() logfields.TraceID: s.TraceID.String(),
baseEntry.Data["parentSpanID"] = s.ParentSpanID.String() logfields.SpanID: s.SpanID.String(),
baseEntry.Data["startTime"] = s.StartTime "dropped": s.DroppedAttributeCount,
baseEntry.Data["endTime"] = s.EndTime "maxAttributes": len(s.Attributes),
baseEntry.Data["duration"] = s.EndTime.Sub(s.StartTime).String() }).Warning("span had dropped attributes")
baseEntry.Data["name"] = s.Name }
baseEntry.Time = s.StartTime
entry := log.L.Dup()
// Combine all span annotations with span data (eg, trace ID, span ID, parent span ID,
// error, status code)
// (OC) Span attributes are guaranteed to be strings, bools, or int64s, so we can
// can skip overhead in entry.WithFields() and add them directly to entry.Data.
// Preallocate ahead of time, since we should add, at most, 10 additional entries
data := make(logrus.Fields, len(entry.Data)+len(s.Attributes)+10)
// Default log entry may have prexisting/application-wide data
for k, v := range entry.Data {
data[k] = v
}
for k, v := range s.Attributes {
data[k] = v
}
data[logfields.Name] = s.Name
data[logfields.TraceID] = s.TraceID.String()
data[logfields.SpanID] = s.SpanID.String()
data[logfields.ParentSpanID] = s.ParentSpanID.String()
data[logfields.StartTime] = s.StartTime
data[logfields.EndTime] = s.EndTime
data[logfields.Duration] = s.EndTime.Sub(s.StartTime)
if sk := spanKindToString(s.SpanKind); sk != "" {
data["spanKind"] = sk
}
level := logrus.InfoLevel level := logrus.InfoLevel
if s.Status.Code != 0 { if s.Status.Code != 0 {
level = logrus.ErrorLevel level = logrus.ErrorLevel
baseEntry.Data[logrus.ErrorKey] = s.Status.Message
// don't overwrite an existing "error" or "errorCode" attributes
if _, ok := data[logrus.ErrorKey]; !ok {
data[logrus.ErrorKey] = s.Status.Message
} }
baseEntry.Log(level, "Span") if _, ok := data[_errorCodeKey]; !ok {
data[_errorCodeKey] = codes.Code(s.Status.Code).String()
}
}
entry.Data = data
entry.Time = s.StartTime
entry.Log(level, spanMessage)
} }

View File

@ -14,8 +14,7 @@ var DefaultSampler = trace.AlwaysSample()
func SetSpanStatus(span *trace.Span, err error) { func SetSpanStatus(span *trace.Span, err error) {
status := trace.Status{} status := trace.Status{}
if err != nil { if err != nil {
// TODO: JTERRY75 - Handle errors in a non-generic way status.Code = int32(toStatusCode(err))
status.Code = trace.StatusCodeUnknown
status.Message = err.Error() status.Message = err.Error()
} }
span.SetStatus(status) span.SetStatus(status)
@ -46,3 +45,14 @@ func update(ctx context.Context, s *trace.Span) (context.Context, *trace.Span) {
var WithServerSpanKind = trace.WithSpanKind(trace.SpanKindServer) var WithServerSpanKind = trace.WithSpanKind(trace.SpanKindServer)
var WithClientSpanKind = trace.WithSpanKind(trace.SpanKindClient) var WithClientSpanKind = trace.WithSpanKind(trace.SpanKindClient)
func spanKindToString(sk int) string {
switch sk {
case trace.SpanKindClient:
return "client"
case trace.SpanKindServer:
return "server"
default:
return ""
}
}

View File

@ -23,20 +23,14 @@ type (
) )
type explicitAccess struct { type explicitAccess struct {
//nolint:structcheck
accessPermissions accessMask accessPermissions accessMask
//nolint:structcheck
accessMode accessMode accessMode accessMode
//nolint:structcheck
inheritance inheritMode inheritance inheritMode
//nolint:structcheck
trustee trustee trustee trustee
} }
type trustee struct { type trustee struct {
//nolint:unused,structcheck
multipleTrustee *trustee multipleTrustee *trustee
//nolint:unused,structcheck
multipleTrusteeOperation int32 multipleTrusteeOperation int32
trusteeForm trusteeForm trusteeForm trusteeForm
trusteeType trusteeType trusteeType trusteeType

View File

@ -33,9 +33,6 @@ func errnoErr(e syscall.Errno) error {
case errnoERROR_IO_PENDING: case errnoERROR_IO_PENDING:
return errERROR_IO_PENDING return errERROR_IO_PENDING
} }
// TODO: add more here, after collecting data on the common
// error values see on Windows. (perhaps when running
// all.bat?)
return e return e
} }
@ -48,7 +45,7 @@ var (
) )
func getSecurityInfo(handle syscall.Handle, objectType uint32, si uint32, ppsidOwner **uintptr, ppsidGroup **uintptr, ppDacl *uintptr, ppSacl *uintptr, ppSecurityDescriptor *uintptr) (win32err error) { func getSecurityInfo(handle syscall.Handle, objectType uint32, si uint32, ppsidOwner **uintptr, ppsidGroup **uintptr, ppDacl *uintptr, ppSacl *uintptr, ppSecurityDescriptor *uintptr) (win32err error) {
r0, _, _ := syscall.Syscall9(procGetSecurityInfo.Addr(), 8, uintptr(handle), uintptr(objectType), uintptr(si), uintptr(unsafe.Pointer(ppsidOwner)), uintptr(unsafe.Pointer(ppsidGroup)), uintptr(unsafe.Pointer(ppDacl)), uintptr(unsafe.Pointer(ppSacl)), uintptr(unsafe.Pointer(ppSecurityDescriptor)), 0) r0, _, _ := syscall.SyscallN(procGetSecurityInfo.Addr(), uintptr(handle), uintptr(objectType), uintptr(si), uintptr(unsafe.Pointer(ppsidOwner)), uintptr(unsafe.Pointer(ppsidGroup)), uintptr(unsafe.Pointer(ppDacl)), uintptr(unsafe.Pointer(ppSacl)), uintptr(unsafe.Pointer(ppSecurityDescriptor)))
if r0 != 0 { if r0 != 0 {
win32err = syscall.Errno(r0) win32err = syscall.Errno(r0)
} }
@ -56,7 +53,7 @@ func getSecurityInfo(handle syscall.Handle, objectType uint32, si uint32, ppsidO
} }
func setEntriesInAcl(count uintptr, pListOfEEs uintptr, oldAcl uintptr, newAcl *uintptr) (win32err error) { func setEntriesInAcl(count uintptr, pListOfEEs uintptr, oldAcl uintptr, newAcl *uintptr) (win32err error) {
r0, _, _ := syscall.Syscall6(procSetEntriesInAclW.Addr(), 4, uintptr(count), uintptr(pListOfEEs), uintptr(oldAcl), uintptr(unsafe.Pointer(newAcl)), 0, 0) r0, _, _ := syscall.SyscallN(procSetEntriesInAclW.Addr(), uintptr(count), uintptr(pListOfEEs), uintptr(oldAcl), uintptr(unsafe.Pointer(newAcl)))
if r0 != 0 { if r0 != 0 {
win32err = syscall.Errno(r0) win32err = syscall.Errno(r0)
} }
@ -64,7 +61,7 @@ func setEntriesInAcl(count uintptr, pListOfEEs uintptr, oldAcl uintptr, newAcl *
} }
func setSecurityInfo(handle syscall.Handle, objectType uint32, si uint32, psidOwner uintptr, psidGroup uintptr, pDacl uintptr, pSacl uintptr) (win32err error) { func setSecurityInfo(handle syscall.Handle, objectType uint32, si uint32, psidOwner uintptr, psidGroup uintptr, pDacl uintptr, pSacl uintptr) (win32err error) {
r0, _, _ := syscall.Syscall9(procSetSecurityInfo.Addr(), 7, uintptr(handle), uintptr(objectType), uintptr(si), uintptr(psidOwner), uintptr(psidGroup), uintptr(pDacl), uintptr(pSacl), 0, 0) r0, _, _ := syscall.SyscallN(procSetSecurityInfo.Addr(), uintptr(handle), uintptr(objectType), uintptr(si), uintptr(psidOwner), uintptr(psidGroup), uintptr(pDacl), uintptr(pSacl))
if r0 != 0 { if r0 != 0 {
win32err = syscall.Errno(r0) win32err = syscall.Errno(r0)
} }

View File

@ -33,9 +33,6 @@ func errnoErr(e syscall.Errno) error {
case errnoERROR_IO_PENDING: case errnoERROR_IO_PENDING:
return errERROR_IO_PENDING return errERROR_IO_PENDING
} }
// TODO: add more here, after collecting data on the common
// error values see on Windows. (perhaps when running
// all.bat?)
return e return e
} }
@ -75,7 +72,7 @@ func hcsCloseComputeSystem(computeSystem HcsSystem) (hr error) {
if hr != nil { if hr != nil {
return return
} }
r0, _, _ := syscall.Syscall(procHcsCloseComputeSystem.Addr(), 1, uintptr(computeSystem), 0, 0) r0, _, _ := syscall.SyscallN(procHcsCloseComputeSystem.Addr(), uintptr(computeSystem))
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -90,7 +87,7 @@ func hcsCloseProcess(process HcsProcess) (hr error) {
if hr != nil { if hr != nil {
return return
} }
r0, _, _ := syscall.Syscall(procHcsCloseProcess.Addr(), 1, uintptr(process), 0, 0) r0, _, _ := syscall.SyscallN(procHcsCloseProcess.Addr(), uintptr(process))
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -119,7 +116,7 @@ func _hcsCreateComputeSystem(id *uint16, configuration *uint16, identity syscall
if hr != nil { if hr != nil {
return return
} }
r0, _, _ := syscall.Syscall6(procHcsCreateComputeSystem.Addr(), 5, uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(configuration)), uintptr(identity), uintptr(unsafe.Pointer(computeSystem)), uintptr(unsafe.Pointer(result)), 0) r0, _, _ := syscall.SyscallN(procHcsCreateComputeSystem.Addr(), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(configuration)), uintptr(identity), uintptr(unsafe.Pointer(computeSystem)), uintptr(unsafe.Pointer(result)))
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -143,7 +140,7 @@ func _hcsCreateProcess(computeSystem HcsSystem, processParameters *uint16, proce
if hr != nil { if hr != nil {
return return
} }
r0, _, _ := syscall.Syscall6(procHcsCreateProcess.Addr(), 5, uintptr(computeSystem), uintptr(unsafe.Pointer(processParameters)), uintptr(unsafe.Pointer(processInformation)), uintptr(unsafe.Pointer(process)), uintptr(unsafe.Pointer(result)), 0) r0, _, _ := syscall.SyscallN(procHcsCreateProcess.Addr(), uintptr(computeSystem), uintptr(unsafe.Pointer(processParameters)), uintptr(unsafe.Pointer(processInformation)), uintptr(unsafe.Pointer(process)), uintptr(unsafe.Pointer(result)))
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -167,7 +164,7 @@ func _hcsEnumerateComputeSystems(query *uint16, computeSystems **uint16, result
if hr != nil { if hr != nil {
return return
} }
r0, _, _ := syscall.Syscall(procHcsEnumerateComputeSystems.Addr(), 3, uintptr(unsafe.Pointer(query)), uintptr(unsafe.Pointer(computeSystems)), uintptr(unsafe.Pointer(result))) r0, _, _ := syscall.SyscallN(procHcsEnumerateComputeSystems.Addr(), uintptr(unsafe.Pointer(query)), uintptr(unsafe.Pointer(computeSystems)), uintptr(unsafe.Pointer(result)))
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -191,7 +188,7 @@ func _hcsGetComputeSystemProperties(computeSystem HcsSystem, propertyQuery *uint
if hr != nil { if hr != nil {
return return
} }
r0, _, _ := syscall.Syscall6(procHcsGetComputeSystemProperties.Addr(), 4, uintptr(computeSystem), uintptr(unsafe.Pointer(propertyQuery)), uintptr(unsafe.Pointer(properties)), uintptr(unsafe.Pointer(result)), 0, 0) r0, _, _ := syscall.SyscallN(procHcsGetComputeSystemProperties.Addr(), uintptr(computeSystem), uintptr(unsafe.Pointer(propertyQuery)), uintptr(unsafe.Pointer(properties)), uintptr(unsafe.Pointer(result)))
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -206,7 +203,7 @@ func hcsGetProcessInfo(process HcsProcess, processInformation *HcsProcessInforma
if hr != nil { if hr != nil {
return return
} }
r0, _, _ := syscall.Syscall(procHcsGetProcessInfo.Addr(), 3, uintptr(process), uintptr(unsafe.Pointer(processInformation)), uintptr(unsafe.Pointer(result))) r0, _, _ := syscall.SyscallN(procHcsGetProcessInfo.Addr(), uintptr(process), uintptr(unsafe.Pointer(processInformation)), uintptr(unsafe.Pointer(result)))
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -221,7 +218,7 @@ func hcsGetProcessProperties(process HcsProcess, processProperties **uint16, res
if hr != nil { if hr != nil {
return return
} }
r0, _, _ := syscall.Syscall(procHcsGetProcessProperties.Addr(), 3, uintptr(process), uintptr(unsafe.Pointer(processProperties)), uintptr(unsafe.Pointer(result))) r0, _, _ := syscall.SyscallN(procHcsGetProcessProperties.Addr(), uintptr(process), uintptr(unsafe.Pointer(processProperties)), uintptr(unsafe.Pointer(result)))
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -245,7 +242,7 @@ func _hcsGetServiceProperties(propertyQuery *uint16, properties **uint16, result
if hr != nil { if hr != nil {
return return
} }
r0, _, _ := syscall.Syscall(procHcsGetServiceProperties.Addr(), 3, uintptr(unsafe.Pointer(propertyQuery)), uintptr(unsafe.Pointer(properties)), uintptr(unsafe.Pointer(result))) r0, _, _ := syscall.SyscallN(procHcsGetServiceProperties.Addr(), uintptr(unsafe.Pointer(propertyQuery)), uintptr(unsafe.Pointer(properties)), uintptr(unsafe.Pointer(result)))
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -269,7 +266,7 @@ func _hcsModifyComputeSystem(computeSystem HcsSystem, configuration *uint16, res
if hr != nil { if hr != nil {
return return
} }
r0, _, _ := syscall.Syscall(procHcsModifyComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(configuration)), uintptr(unsafe.Pointer(result))) r0, _, _ := syscall.SyscallN(procHcsModifyComputeSystem.Addr(), uintptr(computeSystem), uintptr(unsafe.Pointer(configuration)), uintptr(unsafe.Pointer(result)))
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -293,7 +290,7 @@ func _hcsModifyProcess(process HcsProcess, settings *uint16, result **uint16) (h
if hr != nil { if hr != nil {
return return
} }
r0, _, _ := syscall.Syscall(procHcsModifyProcess.Addr(), 3, uintptr(process), uintptr(unsafe.Pointer(settings)), uintptr(unsafe.Pointer(result))) r0, _, _ := syscall.SyscallN(procHcsModifyProcess.Addr(), uintptr(process), uintptr(unsafe.Pointer(settings)), uintptr(unsafe.Pointer(result)))
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -317,7 +314,7 @@ func _hcsModifyServiceSettings(settings *uint16, result **uint16) (hr error) {
if hr != nil { if hr != nil {
return return
} }
r0, _, _ := syscall.Syscall(procHcsModifyServiceSettings.Addr(), 2, uintptr(unsafe.Pointer(settings)), uintptr(unsafe.Pointer(result)), 0) r0, _, _ := syscall.SyscallN(procHcsModifyServiceSettings.Addr(), uintptr(unsafe.Pointer(settings)), uintptr(unsafe.Pointer(result)))
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -341,7 +338,7 @@ func _hcsOpenComputeSystem(id *uint16, computeSystem *HcsSystem, result **uint16
if hr != nil { if hr != nil {
return return
} }
r0, _, _ := syscall.Syscall(procHcsOpenComputeSystem.Addr(), 3, uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(computeSystem)), uintptr(unsafe.Pointer(result))) r0, _, _ := syscall.SyscallN(procHcsOpenComputeSystem.Addr(), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(computeSystem)), uintptr(unsafe.Pointer(result)))
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -356,7 +353,7 @@ func hcsOpenProcess(computeSystem HcsSystem, pid uint32, process *HcsProcess, re
if hr != nil { if hr != nil {
return return
} }
r0, _, _ := syscall.Syscall6(procHcsOpenProcess.Addr(), 4, uintptr(computeSystem), uintptr(pid), uintptr(unsafe.Pointer(process)), uintptr(unsafe.Pointer(result)), 0, 0) r0, _, _ := syscall.SyscallN(procHcsOpenProcess.Addr(), uintptr(computeSystem), uintptr(pid), uintptr(unsafe.Pointer(process)), uintptr(unsafe.Pointer(result)))
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -380,7 +377,7 @@ func _hcsPauseComputeSystem(computeSystem HcsSystem, options *uint16, result **u
if hr != nil { if hr != nil {
return return
} }
r0, _, _ := syscall.Syscall(procHcsPauseComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result))) r0, _, _ := syscall.SyscallN(procHcsPauseComputeSystem.Addr(), uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result)))
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -395,7 +392,7 @@ func hcsRegisterComputeSystemCallback(computeSystem HcsSystem, callback uintptr,
if hr != nil { if hr != nil {
return return
} }
r0, _, _ := syscall.Syscall6(procHcsRegisterComputeSystemCallback.Addr(), 4, uintptr(computeSystem), uintptr(callback), uintptr(context), uintptr(unsafe.Pointer(callbackHandle)), 0, 0) r0, _, _ := syscall.SyscallN(procHcsRegisterComputeSystemCallback.Addr(), uintptr(computeSystem), uintptr(callback), uintptr(context), uintptr(unsafe.Pointer(callbackHandle)))
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -410,7 +407,7 @@ func hcsRegisterProcessCallback(process HcsProcess, callback uintptr, context ui
if hr != nil { if hr != nil {
return return
} }
r0, _, _ := syscall.Syscall6(procHcsRegisterProcessCallback.Addr(), 4, uintptr(process), uintptr(callback), uintptr(context), uintptr(unsafe.Pointer(callbackHandle)), 0, 0) r0, _, _ := syscall.SyscallN(procHcsRegisterProcessCallback.Addr(), uintptr(process), uintptr(callback), uintptr(context), uintptr(unsafe.Pointer(callbackHandle)))
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -434,7 +431,7 @@ func _hcsResumeComputeSystem(computeSystem HcsSystem, options *uint16, result **
if hr != nil { if hr != nil {
return return
} }
r0, _, _ := syscall.Syscall(procHcsResumeComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result))) r0, _, _ := syscall.SyscallN(procHcsResumeComputeSystem.Addr(), uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result)))
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -458,7 +455,7 @@ func _hcsSaveComputeSystem(computeSystem HcsSystem, options *uint16, result **ui
if hr != nil { if hr != nil {
return return
} }
r0, _, _ := syscall.Syscall(procHcsSaveComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result))) r0, _, _ := syscall.SyscallN(procHcsSaveComputeSystem.Addr(), uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result)))
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -482,7 +479,7 @@ func _hcsShutdownComputeSystem(computeSystem HcsSystem, options *uint16, result
if hr != nil { if hr != nil {
return return
} }
r0, _, _ := syscall.Syscall(procHcsShutdownComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result))) r0, _, _ := syscall.SyscallN(procHcsShutdownComputeSystem.Addr(), uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result)))
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -506,7 +503,7 @@ func _hcsSignalProcess(process HcsProcess, options *uint16, result **uint16) (hr
if hr != nil { if hr != nil {
return return
} }
r0, _, _ := syscall.Syscall(procHcsSignalProcess.Addr(), 3, uintptr(process), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result))) r0, _, _ := syscall.SyscallN(procHcsSignalProcess.Addr(), uintptr(process), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result)))
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -530,7 +527,7 @@ func _hcsStartComputeSystem(computeSystem HcsSystem, options *uint16, result **u
if hr != nil { if hr != nil {
return return
} }
r0, _, _ := syscall.Syscall(procHcsStartComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result))) r0, _, _ := syscall.SyscallN(procHcsStartComputeSystem.Addr(), uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result)))
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -554,7 +551,7 @@ func _hcsTerminateComputeSystem(computeSystem HcsSystem, options *uint16, result
if hr != nil { if hr != nil {
return return
} }
r0, _, _ := syscall.Syscall(procHcsTerminateComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result))) r0, _, _ := syscall.SyscallN(procHcsTerminateComputeSystem.Addr(), uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result)))
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -569,7 +566,7 @@ func hcsTerminateProcess(process HcsProcess, result **uint16) (hr error) {
if hr != nil { if hr != nil {
return return
} }
r0, _, _ := syscall.Syscall(procHcsTerminateProcess.Addr(), 2, uintptr(process), uintptr(unsafe.Pointer(result)), 0) r0, _, _ := syscall.SyscallN(procHcsTerminateProcess.Addr(), uintptr(process), uintptr(unsafe.Pointer(result)))
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -584,7 +581,7 @@ func hcsUnregisterComputeSystemCallback(callbackHandle HcsCallback) (hr error) {
if hr != nil { if hr != nil {
return return
} }
r0, _, _ := syscall.Syscall(procHcsUnregisterComputeSystemCallback.Addr(), 1, uintptr(callbackHandle), 0, 0) r0, _, _ := syscall.SyscallN(procHcsUnregisterComputeSystemCallback.Addr(), uintptr(callbackHandle))
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -599,7 +596,7 @@ func hcsUnregisterProcessCallback(callbackHandle HcsCallback) (hr error) {
if hr != nil { if hr != nil {
return return
} }
r0, _, _ := syscall.Syscall(procHcsUnregisterProcessCallback.Addr(), 1, uintptr(callbackHandle), 0, 0) r0, _, _ := syscall.SyscallN(procHcsUnregisterProcessCallback.Addr(), uintptr(callbackHandle))
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff

View File

@ -33,9 +33,6 @@ func errnoErr(e syscall.Errno) error {
case errnoERROR_IO_PENDING: case errnoERROR_IO_PENDING:
return errERROR_IO_PENDING return errERROR_IO_PENDING
} }
// TODO: add more here, after collecting data on the common
// error values see on Windows. (perhaps when running
// all.bat?)
return e return e
} }
@ -77,7 +74,7 @@ func getDiskFreeSpaceEx(directoryName string, freeBytesAvailableToCaller *int64,
} }
func _getDiskFreeSpaceEx(directoryName *uint16, freeBytesAvailableToCaller *int64, totalNumberOfBytes *int64, totalNumberOfFreeBytes *int64) (err error) { func _getDiskFreeSpaceEx(directoryName *uint16, freeBytesAvailableToCaller *int64, totalNumberOfBytes *int64, totalNumberOfFreeBytes *int64) (err error) {
r1, _, e1 := syscall.Syscall6(procGetDiskFreeSpaceExW.Addr(), 4, uintptr(unsafe.Pointer(directoryName)), uintptr(unsafe.Pointer(freeBytesAvailableToCaller)), uintptr(unsafe.Pointer(totalNumberOfBytes)), uintptr(unsafe.Pointer(totalNumberOfFreeBytes)), 0, 0) r1, _, e1 := syscall.SyscallN(procGetDiskFreeSpaceExW.Addr(), uintptr(unsafe.Pointer(directoryName)), uintptr(unsafe.Pointer(freeBytesAvailableToCaller)), uintptr(unsafe.Pointer(totalNumberOfBytes)), uintptr(unsafe.Pointer(totalNumberOfFreeBytes)))
if r1 == 0 { if r1 == 0 {
err = errnoErr(e1) err = errnoErr(e1)
} }
@ -85,7 +82,7 @@ func _getDiskFreeSpaceEx(directoryName *uint16, freeBytesAvailableToCaller *int6
} }
func attachVirtualDisk(handle syscall.Handle, sd uintptr, flags uint32, providerFlags uint32, params uintptr, overlapped uintptr) (err error) { func attachVirtualDisk(handle syscall.Handle, sd uintptr, flags uint32, providerFlags uint32, params uintptr, overlapped uintptr) (err error) {
r1, _, e1 := syscall.Syscall6(procAttachVirtualDisk.Addr(), 6, uintptr(handle), uintptr(sd), uintptr(flags), uintptr(providerFlags), uintptr(params), uintptr(overlapped)) r1, _, e1 := syscall.SyscallN(procAttachVirtualDisk.Addr(), uintptr(handle), uintptr(sd), uintptr(flags), uintptr(providerFlags), uintptr(params), uintptr(overlapped))
if r1 != 0 { if r1 != 0 {
err = errnoErr(e1) err = errnoErr(e1)
} }
@ -102,7 +99,7 @@ func openVirtualDisk(virtualStorageType *virtualStorageType, path string, virtua
} }
func _openVirtualDisk(virtualStorageType *virtualStorageType, path *uint16, virtualDiskAccessMask uint32, flags uint32, parameters *openVirtualDiskParameters, handle *syscall.Handle) (err error) { func _openVirtualDisk(virtualStorageType *virtualStorageType, path *uint16, virtualDiskAccessMask uint32, flags uint32, parameters *openVirtualDiskParameters, handle *syscall.Handle) (err error) {
r1, _, e1 := syscall.Syscall6(procOpenVirtualDisk.Addr(), 6, uintptr(unsafe.Pointer(virtualStorageType)), uintptr(unsafe.Pointer(path)), uintptr(virtualDiskAccessMask), uintptr(flags), uintptr(unsafe.Pointer(parameters)), uintptr(unsafe.Pointer(handle))) r1, _, e1 := syscall.SyscallN(procOpenVirtualDisk.Addr(), uintptr(unsafe.Pointer(virtualStorageType)), uintptr(unsafe.Pointer(path)), uintptr(virtualDiskAccessMask), uintptr(flags), uintptr(unsafe.Pointer(parameters)), uintptr(unsafe.Pointer(handle)))
if r1 != 0 { if r1 != 0 {
err = errnoErr(e1) err = errnoErr(e1)
} }
@ -123,7 +120,7 @@ func _activateLayer(info *driverInfo, id *uint16) (hr error) {
if hr != nil { if hr != nil {
return return
} }
r0, _, _ := syscall.Syscall(procActivateLayer.Addr(), 2, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), 0) r0, _, _ := syscall.SyscallN(procActivateLayer.Addr(), uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)))
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -156,7 +153,7 @@ func _copyLayer(info *driverInfo, srcId *uint16, dstId *uint16, descriptors []WC
if len(descriptors) > 0 { if len(descriptors) > 0 {
_p2 = &descriptors[0] _p2 = &descriptors[0]
} }
r0, _, _ := syscall.Syscall6(procCopyLayer.Addr(), 5, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(srcId)), uintptr(unsafe.Pointer(dstId)), uintptr(unsafe.Pointer(_p2)), uintptr(len(descriptors)), 0) r0, _, _ := syscall.SyscallN(procCopyLayer.Addr(), uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(srcId)), uintptr(unsafe.Pointer(dstId)), uintptr(unsafe.Pointer(_p2)), uintptr(len(descriptors)))
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -185,7 +182,7 @@ func _createLayer(info *driverInfo, id *uint16, parent *uint16) (hr error) {
if hr != nil { if hr != nil {
return return
} }
r0, _, _ := syscall.Syscall(procCreateLayer.Addr(), 3, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(parent))) r0, _, _ := syscall.SyscallN(procCreateLayer.Addr(), uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(parent)))
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -213,7 +210,7 @@ func _createSandboxLayer(info *driverInfo, id *uint16, parent uintptr, descripto
if len(descriptors) > 0 { if len(descriptors) > 0 {
_p1 = &descriptors[0] _p1 = &descriptors[0]
} }
r0, _, _ := syscall.Syscall6(procCreateSandboxLayer.Addr(), 5, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(parent), uintptr(unsafe.Pointer(_p1)), uintptr(len(descriptors)), 0) r0, _, _ := syscall.SyscallN(procCreateSandboxLayer.Addr(), uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(parent), uintptr(unsafe.Pointer(_p1)), uintptr(len(descriptors)))
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -237,7 +234,7 @@ func _deactivateLayer(info *driverInfo, id *uint16) (hr error) {
if hr != nil { if hr != nil {
return return
} }
r0, _, _ := syscall.Syscall(procDeactivateLayer.Addr(), 2, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), 0) r0, _, _ := syscall.SyscallN(procDeactivateLayer.Addr(), uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)))
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -261,7 +258,7 @@ func _destroyLayer(info *driverInfo, id *uint16) (hr error) {
if hr != nil { if hr != nil {
return return
} }
r0, _, _ := syscall.Syscall(procDestroyLayer.Addr(), 2, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), 0) r0, _, _ := syscall.SyscallN(procDestroyLayer.Addr(), uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)))
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -285,7 +282,7 @@ func _expandSandboxSize(info *driverInfo, id *uint16, size uint64) (hr error) {
if hr != nil { if hr != nil {
return return
} }
r0, _, _ := syscall.Syscall(procExpandSandboxSize.Addr(), 3, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(size)) r0, _, _ := syscall.SyscallN(procExpandSandboxSize.Addr(), uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(size))
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -318,7 +315,7 @@ func _exportLayer(info *driverInfo, id *uint16, path *uint16, descriptors []WC_L
if len(descriptors) > 0 { if len(descriptors) > 0 {
_p2 = &descriptors[0] _p2 = &descriptors[0]
} }
r0, _, _ := syscall.Syscall6(procExportLayer.Addr(), 5, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(_p2)), uintptr(len(descriptors)), 0) r0, _, _ := syscall.SyscallN(procExportLayer.Addr(), uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(_p2)), uintptr(len(descriptors)))
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -333,7 +330,7 @@ func getBaseImages(buffer **uint16) (hr error) {
if hr != nil { if hr != nil {
return return
} }
r0, _, _ := syscall.Syscall(procGetBaseImages.Addr(), 1, uintptr(unsafe.Pointer(buffer)), 0, 0) r0, _, _ := syscall.SyscallN(procGetBaseImages.Addr(), uintptr(unsafe.Pointer(buffer)))
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -357,7 +354,7 @@ func _getLayerMountPath(info *driverInfo, id *uint16, length *uintptr, buffer *u
if hr != nil { if hr != nil {
return return
} }
r0, _, _ := syscall.Syscall6(procGetLayerMountPath.Addr(), 4, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(length)), uintptr(unsafe.Pointer(buffer)), 0, 0) r0, _, _ := syscall.SyscallN(procGetLayerMountPath.Addr(), uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(length)), uintptr(unsafe.Pointer(buffer)))
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -386,7 +383,7 @@ func _grantVmAccess(vmid *uint16, filepath *uint16) (hr error) {
if hr != nil { if hr != nil {
return return
} }
r0, _, _ := syscall.Syscall(procGrantVmAccess.Addr(), 2, uintptr(unsafe.Pointer(vmid)), uintptr(unsafe.Pointer(filepath)), 0) r0, _, _ := syscall.SyscallN(procGrantVmAccess.Addr(), uintptr(unsafe.Pointer(vmid)), uintptr(unsafe.Pointer(filepath)))
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -419,7 +416,7 @@ func _importLayer(info *driverInfo, id *uint16, path *uint16, descriptors []WC_L
if len(descriptors) > 0 { if len(descriptors) > 0 {
_p2 = &descriptors[0] _p2 = &descriptors[0]
} }
r0, _, _ := syscall.Syscall6(procImportLayer.Addr(), 5, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(_p2)), uintptr(len(descriptors)), 0) r0, _, _ := syscall.SyscallN(procImportLayer.Addr(), uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(_p2)), uintptr(len(descriptors)))
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -443,7 +440,7 @@ func _layerExists(info *driverInfo, id *uint16, exists *uint32) (hr error) {
if hr != nil { if hr != nil {
return return
} }
r0, _, _ := syscall.Syscall(procLayerExists.Addr(), 3, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(exists))) r0, _, _ := syscall.SyscallN(procLayerExists.Addr(), uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(exists)))
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -467,7 +464,7 @@ func _nameToGuid(name *uint16, guid *_guid) (hr error) {
if hr != nil { if hr != nil {
return return
} }
r0, _, _ := syscall.Syscall(procNameToGuid.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(guid)), 0) r0, _, _ := syscall.SyscallN(procNameToGuid.Addr(), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(guid)))
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -495,7 +492,7 @@ func _prepareLayer(info *driverInfo, id *uint16, descriptors []WC_LAYER_DESCRIPT
if len(descriptors) > 0 { if len(descriptors) > 0 {
_p1 = &descriptors[0] _p1 = &descriptors[0]
} }
r0, _, _ := syscall.Syscall6(procPrepareLayer.Addr(), 4, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(_p1)), uintptr(len(descriptors)), 0, 0) r0, _, _ := syscall.SyscallN(procPrepareLayer.Addr(), uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(_p1)), uintptr(len(descriptors)))
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -519,7 +516,7 @@ func _processBaseImage(path *uint16) (hr error) {
if hr != nil { if hr != nil {
return return
} }
r0, _, _ := syscall.Syscall(procProcessBaseImage.Addr(), 1, uintptr(unsafe.Pointer(path)), 0, 0) r0, _, _ := syscall.SyscallN(procProcessBaseImage.Addr(), uintptr(unsafe.Pointer(path)))
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -543,7 +540,7 @@ func _processUtilityImage(path *uint16) (hr error) {
if hr != nil { if hr != nil {
return return
} }
r0, _, _ := syscall.Syscall(procProcessUtilityImage.Addr(), 1, uintptr(unsafe.Pointer(path)), 0, 0) r0, _, _ := syscall.SyscallN(procProcessUtilityImage.Addr(), uintptr(unsafe.Pointer(path)))
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -567,7 +564,7 @@ func _unprepareLayer(info *driverInfo, id *uint16) (hr error) {
if hr != nil { if hr != nil {
return return
} }
r0, _, _ := syscall.Syscall(procUnprepareLayer.Addr(), 2, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), 0) r0, _, _ := syscall.SyscallN(procUnprepareLayer.Addr(), uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)))
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff

View File

@ -33,9 +33,6 @@ func errnoErr(e syscall.Errno) error {
case errnoERROR_IO_PENDING: case errnoERROR_IO_PENDING:
return errERROR_IO_PENDING return errERROR_IO_PENDING
} }
// TODO: add more here, after collecting data on the common
// error values see on Windows. (perhaps when running
// all.bat?)
return e return e
} }
@ -89,7 +86,7 @@ var (
) )
func LogonUser(username *uint16, domain *uint16, password *uint16, logonType uint32, logonProvider uint32, token *windows.Token) (err error) { func LogonUser(username *uint16, domain *uint16, password *uint16, logonType uint32, logonProvider uint32, token *windows.Token) (err error) {
r1, _, e1 := syscall.Syscall6(procLogonUserW.Addr(), 6, uintptr(unsafe.Pointer(username)), uintptr(unsafe.Pointer(domain)), uintptr(unsafe.Pointer(password)), uintptr(logonType), uintptr(logonProvider), uintptr(unsafe.Pointer(token))) r1, _, e1 := syscall.SyscallN(procLogonUserW.Addr(), uintptr(unsafe.Pointer(username)), uintptr(unsafe.Pointer(domain)), uintptr(unsafe.Pointer(password)), uintptr(logonType), uintptr(logonProvider), uintptr(unsafe.Pointer(token)))
if r1 == 0 { if r1 == 0 {
err = errnoErr(e1) err = errnoErr(e1)
} }
@ -101,7 +98,7 @@ func BfSetupFilter(jobHandle windows.Handle, flags uint32, virtRootPath *uint16,
if hr != nil { if hr != nil {
return return
} }
r0, _, _ := syscall.Syscall6(procBfSetupFilter.Addr(), 6, uintptr(jobHandle), uintptr(flags), uintptr(unsafe.Pointer(virtRootPath)), uintptr(unsafe.Pointer(virtTargetPath)), uintptr(unsafe.Pointer(virtExceptions)), uintptr(virtExceptionPathCount)) r0, _, _ := syscall.SyscallN(procBfSetupFilter.Addr(), uintptr(jobHandle), uintptr(flags), uintptr(unsafe.Pointer(virtRootPath)), uintptr(unsafe.Pointer(virtTargetPath)), uintptr(unsafe.Pointer(virtExceptions)), uintptr(virtExceptionPathCount))
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -112,7 +109,7 @@ func BfSetupFilter(jobHandle windows.Handle, flags uint32, virtRootPath *uint16,
} }
func CMGetDevNodeProperty(dnDevInst uint32, propertyKey *DevPropKey, propertyType *uint32, propertyBuffer *uint16, propertyBufferSize *uint32, uFlags uint32) (hr error) { func CMGetDevNodeProperty(dnDevInst uint32, propertyKey *DevPropKey, propertyType *uint32, propertyBuffer *uint16, propertyBufferSize *uint32, uFlags uint32) (hr error) {
r0, _, _ := syscall.Syscall6(procCM_Get_DevNode_PropertyW.Addr(), 6, uintptr(dnDevInst), uintptr(unsafe.Pointer(propertyKey)), uintptr(unsafe.Pointer(propertyType)), uintptr(unsafe.Pointer(propertyBuffer)), uintptr(unsafe.Pointer(propertyBufferSize)), uintptr(uFlags)) r0, _, _ := syscall.SyscallN(procCM_Get_DevNode_PropertyW.Addr(), uintptr(dnDevInst), uintptr(unsafe.Pointer(propertyKey)), uintptr(unsafe.Pointer(propertyType)), uintptr(unsafe.Pointer(propertyBuffer)), uintptr(unsafe.Pointer(propertyBufferSize)), uintptr(uFlags))
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -123,7 +120,7 @@ func CMGetDevNodeProperty(dnDevInst uint32, propertyKey *DevPropKey, propertyTyp
} }
func CMGetDeviceIDList(pszFilter *byte, buffer *byte, bufferLen uint32, uFlags uint32) (hr error) { func CMGetDeviceIDList(pszFilter *byte, buffer *byte, bufferLen uint32, uFlags uint32) (hr error) {
r0, _, _ := syscall.Syscall6(procCM_Get_Device_ID_ListA.Addr(), 4, uintptr(unsafe.Pointer(pszFilter)), uintptr(unsafe.Pointer(buffer)), uintptr(bufferLen), uintptr(uFlags), 0, 0) r0, _, _ := syscall.SyscallN(procCM_Get_Device_ID_ListA.Addr(), uintptr(unsafe.Pointer(pszFilter)), uintptr(unsafe.Pointer(buffer)), uintptr(bufferLen), uintptr(uFlags))
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -134,7 +131,7 @@ func CMGetDeviceIDList(pszFilter *byte, buffer *byte, bufferLen uint32, uFlags u
} }
func CMGetDeviceIDListSize(pulLen *uint32, pszFilter *byte, uFlags uint32) (hr error) { func CMGetDeviceIDListSize(pulLen *uint32, pszFilter *byte, uFlags uint32) (hr error) {
r0, _, _ := syscall.Syscall(procCM_Get_Device_ID_List_SizeA.Addr(), 3, uintptr(unsafe.Pointer(pulLen)), uintptr(unsafe.Pointer(pszFilter)), uintptr(uFlags)) r0, _, _ := syscall.SyscallN(procCM_Get_Device_ID_List_SizeA.Addr(), uintptr(unsafe.Pointer(pulLen)), uintptr(unsafe.Pointer(pszFilter)), uintptr(uFlags))
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -154,7 +151,7 @@ func CMLocateDevNode(pdnDevInst *uint32, pDeviceID string, uFlags uint32) (hr er
} }
func _CMLocateDevNode(pdnDevInst *uint32, pDeviceID *uint16, uFlags uint32) (hr error) { func _CMLocateDevNode(pdnDevInst *uint32, pDeviceID *uint16, uFlags uint32) (hr error) {
r0, _, _ := syscall.Syscall(procCM_Locate_DevNodeW.Addr(), 3, uintptr(unsafe.Pointer(pdnDevInst)), uintptr(unsafe.Pointer(pDeviceID)), uintptr(uFlags)) r0, _, _ := syscall.SyscallN(procCM_Locate_DevNodeW.Addr(), uintptr(unsafe.Pointer(pdnDevInst)), uintptr(unsafe.Pointer(pDeviceID)), uintptr(uFlags))
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -165,7 +162,7 @@ func _CMLocateDevNode(pdnDevInst *uint32, pDeviceID *uint16, uFlags uint32) (hr
} }
func SetJobCompartmentId(handle windows.Handle, compartmentId uint32) (win32Err error) { func SetJobCompartmentId(handle windows.Handle, compartmentId uint32) (win32Err error) {
r0, _, _ := syscall.Syscall(procSetJobCompartmentId.Addr(), 2, uintptr(handle), uintptr(compartmentId), 0) r0, _, _ := syscall.SyscallN(procSetJobCompartmentId.Addr(), uintptr(handle), uintptr(compartmentId))
if r0 != 0 { if r0 != 0 {
win32Err = syscall.Errno(r0) win32Err = syscall.Errno(r0)
} }
@ -173,12 +170,12 @@ func SetJobCompartmentId(handle windows.Handle, compartmentId uint32) (win32Err
} }
func ClosePseudoConsole(hpc windows.Handle) { func ClosePseudoConsole(hpc windows.Handle) {
syscall.Syscall(procClosePseudoConsole.Addr(), 1, uintptr(hpc), 0, 0) syscall.SyscallN(procClosePseudoConsole.Addr(), uintptr(hpc))
return return
} }
func CopyFileW(existingFileName *uint16, newFileName *uint16, failIfExists int32) (err error) { func CopyFileW(existingFileName *uint16, newFileName *uint16, failIfExists int32) (err error) {
r1, _, e1 := syscall.Syscall(procCopyFileW.Addr(), 3, uintptr(unsafe.Pointer(existingFileName)), uintptr(unsafe.Pointer(newFileName)), uintptr(failIfExists)) r1, _, e1 := syscall.SyscallN(procCopyFileW.Addr(), uintptr(unsafe.Pointer(existingFileName)), uintptr(unsafe.Pointer(newFileName)), uintptr(failIfExists))
if r1 == 0 { if r1 == 0 {
err = errnoErr(e1) err = errnoErr(e1)
} }
@ -186,7 +183,7 @@ func CopyFileW(existingFileName *uint16, newFileName *uint16, failIfExists int32
} }
func createPseudoConsole(size uint32, hInput windows.Handle, hOutput windows.Handle, dwFlags uint32, hpcon *windows.Handle) (hr error) { func createPseudoConsole(size uint32, hInput windows.Handle, hOutput windows.Handle, dwFlags uint32, hpcon *windows.Handle) (hr error) {
r0, _, _ := syscall.Syscall6(procCreatePseudoConsole.Addr(), 5, uintptr(size), uintptr(hInput), uintptr(hOutput), uintptr(dwFlags), uintptr(unsafe.Pointer(hpcon)), 0) r0, _, _ := syscall.SyscallN(procCreatePseudoConsole.Addr(), uintptr(size), uintptr(hInput), uintptr(hOutput), uintptr(dwFlags), uintptr(unsafe.Pointer(hpcon)))
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -197,7 +194,7 @@ func createPseudoConsole(size uint32, hInput windows.Handle, hOutput windows.Han
} }
func CreateRemoteThread(process windows.Handle, sa *windows.SecurityAttributes, stackSize uint32, startAddr uintptr, parameter uintptr, creationFlags uint32, threadID *uint32) (handle windows.Handle, err error) { func CreateRemoteThread(process windows.Handle, sa *windows.SecurityAttributes, stackSize uint32, startAddr uintptr, parameter uintptr, creationFlags uint32, threadID *uint32) (handle windows.Handle, err error) {
r0, _, e1 := syscall.Syscall9(procCreateRemoteThread.Addr(), 7, uintptr(process), uintptr(unsafe.Pointer(sa)), uintptr(stackSize), uintptr(startAddr), uintptr(parameter), uintptr(creationFlags), uintptr(unsafe.Pointer(threadID)), 0, 0) r0, _, e1 := syscall.SyscallN(procCreateRemoteThread.Addr(), uintptr(process), uintptr(unsafe.Pointer(sa)), uintptr(stackSize), uintptr(startAddr), uintptr(parameter), uintptr(creationFlags), uintptr(unsafe.Pointer(threadID)))
handle = windows.Handle(r0) handle = windows.Handle(r0)
if handle == 0 { if handle == 0 {
err = errnoErr(e1) err = errnoErr(e1)
@ -206,13 +203,13 @@ func CreateRemoteThread(process windows.Handle, sa *windows.SecurityAttributes,
} }
func GetActiveProcessorCount(groupNumber uint16) (amount uint32) { func GetActiveProcessorCount(groupNumber uint16) (amount uint32) {
r0, _, _ := syscall.Syscall(procGetActiveProcessorCount.Addr(), 1, uintptr(groupNumber), 0, 0) r0, _, _ := syscall.SyscallN(procGetActiveProcessorCount.Addr(), uintptr(groupNumber))
amount = uint32(r0) amount = uint32(r0)
return return
} }
func IsProcessInJob(procHandle windows.Handle, jobHandle windows.Handle, result *int32) (err error) { func IsProcessInJob(procHandle windows.Handle, jobHandle windows.Handle, result *int32) (err error) {
r1, _, e1 := syscall.Syscall(procIsProcessInJob.Addr(), 3, uintptr(procHandle), uintptr(jobHandle), uintptr(unsafe.Pointer(result))) r1, _, e1 := syscall.SyscallN(procIsProcessInJob.Addr(), uintptr(procHandle), uintptr(jobHandle), uintptr(unsafe.Pointer(result)))
if r1 == 0 { if r1 == 0 {
err = errnoErr(e1) err = errnoErr(e1)
} }
@ -220,18 +217,18 @@ func IsProcessInJob(procHandle windows.Handle, jobHandle windows.Handle, result
} }
func LocalAlloc(flags uint32, size int) (ptr uintptr) { func LocalAlloc(flags uint32, size int) (ptr uintptr) {
r0, _, _ := syscall.Syscall(procLocalAlloc.Addr(), 2, uintptr(flags), uintptr(size), 0) r0, _, _ := syscall.SyscallN(procLocalAlloc.Addr(), uintptr(flags), uintptr(size))
ptr = uintptr(r0) ptr = uintptr(r0)
return return
} }
func LocalFree(ptr uintptr) { func LocalFree(ptr uintptr) {
syscall.Syscall(procLocalFree.Addr(), 1, uintptr(ptr), 0, 0) syscall.SyscallN(procLocalFree.Addr(), uintptr(ptr))
return return
} }
func OpenJobObject(desiredAccess uint32, inheritHandle int32, lpName *uint16) (handle windows.Handle, err error) { func OpenJobObject(desiredAccess uint32, inheritHandle int32, lpName *uint16) (handle windows.Handle, err error) {
r0, _, e1 := syscall.Syscall(procOpenJobObjectW.Addr(), 3, uintptr(desiredAccess), uintptr(inheritHandle), uintptr(unsafe.Pointer(lpName))) r0, _, e1 := syscall.SyscallN(procOpenJobObjectW.Addr(), uintptr(desiredAccess), uintptr(inheritHandle), uintptr(unsafe.Pointer(lpName)))
handle = windows.Handle(r0) handle = windows.Handle(r0)
if handle == 0 { if handle == 0 {
err = errnoErr(e1) err = errnoErr(e1)
@ -240,7 +237,7 @@ func OpenJobObject(desiredAccess uint32, inheritHandle int32, lpName *uint16) (h
} }
func QueryInformationJobObject(jobHandle windows.Handle, infoClass uint32, jobObjectInfo unsafe.Pointer, jobObjectInformationLength uint32, lpReturnLength *uint32) (err error) { func QueryInformationJobObject(jobHandle windows.Handle, infoClass uint32, jobObjectInfo unsafe.Pointer, jobObjectInformationLength uint32, lpReturnLength *uint32) (err error) {
r1, _, e1 := syscall.Syscall6(procQueryInformationJobObject.Addr(), 5, uintptr(jobHandle), uintptr(infoClass), uintptr(jobObjectInfo), uintptr(jobObjectInformationLength), uintptr(unsafe.Pointer(lpReturnLength)), 0) r1, _, e1 := syscall.SyscallN(procQueryInformationJobObject.Addr(), uintptr(jobHandle), uintptr(infoClass), uintptr(jobObjectInfo), uintptr(jobObjectInformationLength), uintptr(unsafe.Pointer(lpReturnLength)))
if r1 == 0 { if r1 == 0 {
err = errnoErr(e1) err = errnoErr(e1)
} }
@ -248,7 +245,7 @@ func QueryInformationJobObject(jobHandle windows.Handle, infoClass uint32, jobOb
} }
func QueryIoRateControlInformationJobObject(jobHandle windows.Handle, volumeName *uint16, ioRateControlInfo **JOBOBJECT_IO_RATE_CONTROL_INFORMATION, infoBlockCount *uint32) (ret uint32, err error) { func QueryIoRateControlInformationJobObject(jobHandle windows.Handle, volumeName *uint16, ioRateControlInfo **JOBOBJECT_IO_RATE_CONTROL_INFORMATION, infoBlockCount *uint32) (ret uint32, err error) {
r0, _, e1 := syscall.Syscall6(procQueryIoRateControlInformationJobObject.Addr(), 4, uintptr(jobHandle), uintptr(unsafe.Pointer(volumeName)), uintptr(unsafe.Pointer(ioRateControlInfo)), uintptr(unsafe.Pointer(infoBlockCount)), 0, 0) r0, _, e1 := syscall.SyscallN(procQueryIoRateControlInformationJobObject.Addr(), uintptr(jobHandle), uintptr(unsafe.Pointer(volumeName)), uintptr(unsafe.Pointer(ioRateControlInfo)), uintptr(unsafe.Pointer(infoBlockCount)))
ret = uint32(r0) ret = uint32(r0)
if ret == 0 { if ret == 0 {
err = errnoErr(e1) err = errnoErr(e1)
@ -257,7 +254,7 @@ func QueryIoRateControlInformationJobObject(jobHandle windows.Handle, volumeName
} }
func resizePseudoConsole(hPc windows.Handle, size uint32) (hr error) { func resizePseudoConsole(hPc windows.Handle, size uint32) (hr error) {
r0, _, _ := syscall.Syscall(procResizePseudoConsole.Addr(), 2, uintptr(hPc), uintptr(size), 0) r0, _, _ := syscall.SyscallN(procResizePseudoConsole.Addr(), uintptr(hPc), uintptr(size))
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -268,7 +265,7 @@ func resizePseudoConsole(hPc windows.Handle, size uint32) (hr error) {
} }
func SearchPath(lpPath *uint16, lpFileName *uint16, lpExtension *uint16, nBufferLength uint32, lpBuffer *uint16, lpFilePath *uint16) (size uint32, err error) { func SearchPath(lpPath *uint16, lpFileName *uint16, lpExtension *uint16, nBufferLength uint32, lpBuffer *uint16, lpFilePath *uint16) (size uint32, err error) {
r0, _, e1 := syscall.Syscall6(procSearchPathW.Addr(), 6, uintptr(unsafe.Pointer(lpPath)), uintptr(unsafe.Pointer(lpFileName)), uintptr(unsafe.Pointer(lpExtension)), uintptr(nBufferLength), uintptr(unsafe.Pointer(lpBuffer)), uintptr(unsafe.Pointer(lpFilePath))) r0, _, e1 := syscall.SyscallN(procSearchPathW.Addr(), uintptr(unsafe.Pointer(lpPath)), uintptr(unsafe.Pointer(lpFileName)), uintptr(unsafe.Pointer(lpExtension)), uintptr(nBufferLength), uintptr(unsafe.Pointer(lpBuffer)), uintptr(unsafe.Pointer(lpFilePath)))
size = uint32(r0) size = uint32(r0)
if size == 0 { if size == 0 {
err = errnoErr(e1) err = errnoErr(e1)
@ -277,7 +274,7 @@ func SearchPath(lpPath *uint16, lpFileName *uint16, lpExtension *uint16, nBuffer
} }
func SetIoRateControlInformationJobObject(jobHandle windows.Handle, ioRateControlInfo *JOBOBJECT_IO_RATE_CONTROL_INFORMATION) (ret uint32, err error) { func SetIoRateControlInformationJobObject(jobHandle windows.Handle, ioRateControlInfo *JOBOBJECT_IO_RATE_CONTROL_INFORMATION) (ret uint32, err error) {
r0, _, e1 := syscall.Syscall(procSetIoRateControlInformationJobObject.Addr(), 2, uintptr(jobHandle), uintptr(unsafe.Pointer(ioRateControlInfo)), 0) r0, _, e1 := syscall.SyscallN(procSetIoRateControlInformationJobObject.Addr(), uintptr(jobHandle), uintptr(unsafe.Pointer(ioRateControlInfo)))
ret = uint32(r0) ret = uint32(r0)
if ret == 0 { if ret == 0 {
err = errnoErr(e1) err = errnoErr(e1)
@ -286,7 +283,7 @@ func SetIoRateControlInformationJobObject(jobHandle windows.Handle, ioRateContro
} }
func netLocalGroupAddMembers(serverName *uint16, groupName *uint16, level uint32, buf *byte, totalEntries uint32) (status error) { func netLocalGroupAddMembers(serverName *uint16, groupName *uint16, level uint32, buf *byte, totalEntries uint32) (status error) {
r0, _, _ := syscall.Syscall6(procNetLocalGroupAddMembers.Addr(), 5, uintptr(unsafe.Pointer(serverName)), uintptr(unsafe.Pointer(groupName)), uintptr(level), uintptr(unsafe.Pointer(buf)), uintptr(totalEntries), 0) r0, _, _ := syscall.SyscallN(procNetLocalGroupAddMembers.Addr(), uintptr(unsafe.Pointer(serverName)), uintptr(unsafe.Pointer(groupName)), uintptr(level), uintptr(unsafe.Pointer(buf)), uintptr(totalEntries))
if r0 != 0 { if r0 != 0 {
status = syscall.Errno(r0) status = syscall.Errno(r0)
} }
@ -294,7 +291,7 @@ func netLocalGroupAddMembers(serverName *uint16, groupName *uint16, level uint32
} }
func netLocalGroupGetInfo(serverName *uint16, groupName *uint16, level uint32, bufptr **byte) (status error) { func netLocalGroupGetInfo(serverName *uint16, groupName *uint16, level uint32, bufptr **byte) (status error) {
r0, _, _ := syscall.Syscall6(procNetLocalGroupGetInfo.Addr(), 4, uintptr(unsafe.Pointer(serverName)), uintptr(unsafe.Pointer(groupName)), uintptr(level), uintptr(unsafe.Pointer(bufptr)), 0, 0) r0, _, _ := syscall.SyscallN(procNetLocalGroupGetInfo.Addr(), uintptr(unsafe.Pointer(serverName)), uintptr(unsafe.Pointer(groupName)), uintptr(level), uintptr(unsafe.Pointer(bufptr)))
if r0 != 0 { if r0 != 0 {
status = syscall.Errno(r0) status = syscall.Errno(r0)
} }
@ -302,7 +299,7 @@ func netLocalGroupGetInfo(serverName *uint16, groupName *uint16, level uint32, b
} }
func netUserAdd(serverName *uint16, level uint32, buf *byte, parm_err *uint32) (status error) { func netUserAdd(serverName *uint16, level uint32, buf *byte, parm_err *uint32) (status error) {
r0, _, _ := syscall.Syscall6(procNetUserAdd.Addr(), 4, uintptr(unsafe.Pointer(serverName)), uintptr(level), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(parm_err)), 0, 0) r0, _, _ := syscall.SyscallN(procNetUserAdd.Addr(), uintptr(unsafe.Pointer(serverName)), uintptr(level), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(parm_err)))
if r0 != 0 { if r0 != 0 {
status = syscall.Errno(r0) status = syscall.Errno(r0)
} }
@ -310,7 +307,7 @@ func netUserAdd(serverName *uint16, level uint32, buf *byte, parm_err *uint32) (
} }
func netUserDel(serverName *uint16, username *uint16) (status error) { func netUserDel(serverName *uint16, username *uint16) (status error) {
r0, _, _ := syscall.Syscall(procNetUserDel.Addr(), 2, uintptr(unsafe.Pointer(serverName)), uintptr(unsafe.Pointer(username)), 0) r0, _, _ := syscall.SyscallN(procNetUserDel.Addr(), uintptr(unsafe.Pointer(serverName)), uintptr(unsafe.Pointer(username)))
if r0 != 0 { if r0 != 0 {
status = syscall.Errno(r0) status = syscall.Errno(r0)
} }
@ -318,25 +315,25 @@ func netUserDel(serverName *uint16, username *uint16) (status error) {
} }
func NtCreateFile(handle *uintptr, accessMask uint32, oa *ObjectAttributes, iosb *IOStatusBlock, allocationSize *uint64, fileAttributes uint32, shareAccess uint32, createDisposition uint32, createOptions uint32, eaBuffer *byte, eaLength uint32) (status uint32) { func NtCreateFile(handle *uintptr, accessMask uint32, oa *ObjectAttributes, iosb *IOStatusBlock, allocationSize *uint64, fileAttributes uint32, shareAccess uint32, createDisposition uint32, createOptions uint32, eaBuffer *byte, eaLength uint32) (status uint32) {
r0, _, _ := syscall.Syscall12(procNtCreateFile.Addr(), 11, uintptr(unsafe.Pointer(handle)), uintptr(accessMask), uintptr(unsafe.Pointer(oa)), uintptr(unsafe.Pointer(iosb)), uintptr(unsafe.Pointer(allocationSize)), uintptr(fileAttributes), uintptr(shareAccess), uintptr(createDisposition), uintptr(createOptions), uintptr(unsafe.Pointer(eaBuffer)), uintptr(eaLength), 0) r0, _, _ := syscall.SyscallN(procNtCreateFile.Addr(), uintptr(unsafe.Pointer(handle)), uintptr(accessMask), uintptr(unsafe.Pointer(oa)), uintptr(unsafe.Pointer(iosb)), uintptr(unsafe.Pointer(allocationSize)), uintptr(fileAttributes), uintptr(shareAccess), uintptr(createDisposition), uintptr(createOptions), uintptr(unsafe.Pointer(eaBuffer)), uintptr(eaLength))
status = uint32(r0) status = uint32(r0)
return return
} }
func NtCreateJobObject(jobHandle *windows.Handle, desiredAccess uint32, objAttributes *ObjectAttributes) (status uint32) { func NtCreateJobObject(jobHandle *windows.Handle, desiredAccess uint32, objAttributes *ObjectAttributes) (status uint32) {
r0, _, _ := syscall.Syscall(procNtCreateJobObject.Addr(), 3, uintptr(unsafe.Pointer(jobHandle)), uintptr(desiredAccess), uintptr(unsafe.Pointer(objAttributes))) r0, _, _ := syscall.SyscallN(procNtCreateJobObject.Addr(), uintptr(unsafe.Pointer(jobHandle)), uintptr(desiredAccess), uintptr(unsafe.Pointer(objAttributes)))
status = uint32(r0) status = uint32(r0)
return return
} }
func NtOpenDirectoryObject(handle *uintptr, accessMask uint32, oa *ObjectAttributes) (status uint32) { func NtOpenDirectoryObject(handle *uintptr, accessMask uint32, oa *ObjectAttributes) (status uint32) {
r0, _, _ := syscall.Syscall(procNtOpenDirectoryObject.Addr(), 3, uintptr(unsafe.Pointer(handle)), uintptr(accessMask), uintptr(unsafe.Pointer(oa))) r0, _, _ := syscall.SyscallN(procNtOpenDirectoryObject.Addr(), uintptr(unsafe.Pointer(handle)), uintptr(accessMask), uintptr(unsafe.Pointer(oa)))
status = uint32(r0) status = uint32(r0)
return return
} }
func NtOpenJobObject(jobHandle *windows.Handle, desiredAccess uint32, objAttributes *ObjectAttributes) (status uint32) { func NtOpenJobObject(jobHandle *windows.Handle, desiredAccess uint32, objAttributes *ObjectAttributes) (status uint32) {
r0, _, _ := syscall.Syscall(procNtOpenJobObject.Addr(), 3, uintptr(unsafe.Pointer(jobHandle)), uintptr(desiredAccess), uintptr(unsafe.Pointer(objAttributes))) r0, _, _ := syscall.SyscallN(procNtOpenJobObject.Addr(), uintptr(unsafe.Pointer(jobHandle)), uintptr(desiredAccess), uintptr(unsafe.Pointer(objAttributes)))
status = uint32(r0) status = uint32(r0)
return return
} }
@ -350,31 +347,31 @@ func NtQueryDirectoryObject(handle uintptr, buffer *byte, length uint32, singleE
if restartScan { if restartScan {
_p1 = 1 _p1 = 1
} }
r0, _, _ := syscall.Syscall9(procNtQueryDirectoryObject.Addr(), 7, uintptr(handle), uintptr(unsafe.Pointer(buffer)), uintptr(length), uintptr(_p0), uintptr(_p1), uintptr(unsafe.Pointer(context)), uintptr(unsafe.Pointer(returnLength)), 0, 0) r0, _, _ := syscall.SyscallN(procNtQueryDirectoryObject.Addr(), uintptr(handle), uintptr(unsafe.Pointer(buffer)), uintptr(length), uintptr(_p0), uintptr(_p1), uintptr(unsafe.Pointer(context)), uintptr(unsafe.Pointer(returnLength)))
status = uint32(r0) status = uint32(r0)
return return
} }
func NtQueryInformationProcess(processHandle windows.Handle, processInfoClass uint32, processInfo unsafe.Pointer, processInfoLength uint32, returnLength *uint32) (status uint32) { func NtQueryInformationProcess(processHandle windows.Handle, processInfoClass uint32, processInfo unsafe.Pointer, processInfoLength uint32, returnLength *uint32) (status uint32) {
r0, _, _ := syscall.Syscall6(procNtQueryInformationProcess.Addr(), 5, uintptr(processHandle), uintptr(processInfoClass), uintptr(processInfo), uintptr(processInfoLength), uintptr(unsafe.Pointer(returnLength)), 0) r0, _, _ := syscall.SyscallN(procNtQueryInformationProcess.Addr(), uintptr(processHandle), uintptr(processInfoClass), uintptr(processInfo), uintptr(processInfoLength), uintptr(unsafe.Pointer(returnLength)))
status = uint32(r0) status = uint32(r0)
return return
} }
func NtQuerySystemInformation(systemInfoClass int, systemInformation unsafe.Pointer, systemInfoLength uint32, returnLength *uint32) (status uint32) { func NtQuerySystemInformation(systemInfoClass int, systemInformation unsafe.Pointer, systemInfoLength uint32, returnLength *uint32) (status uint32) {
r0, _, _ := syscall.Syscall6(procNtQuerySystemInformation.Addr(), 4, uintptr(systemInfoClass), uintptr(systemInformation), uintptr(systemInfoLength), uintptr(unsafe.Pointer(returnLength)), 0, 0) r0, _, _ := syscall.SyscallN(procNtQuerySystemInformation.Addr(), uintptr(systemInfoClass), uintptr(systemInformation), uintptr(systemInfoLength), uintptr(unsafe.Pointer(returnLength)))
status = uint32(r0) status = uint32(r0)
return return
} }
func NtSetInformationFile(handle uintptr, iosb *IOStatusBlock, information uintptr, length uint32, class uint32) (status uint32) { func NtSetInformationFile(handle uintptr, iosb *IOStatusBlock, information uintptr, length uint32, class uint32) (status uint32) {
r0, _, _ := syscall.Syscall6(procNtSetInformationFile.Addr(), 5, uintptr(handle), uintptr(unsafe.Pointer(iosb)), uintptr(information), uintptr(length), uintptr(class), 0) r0, _, _ := syscall.SyscallN(procNtSetInformationFile.Addr(), uintptr(handle), uintptr(unsafe.Pointer(iosb)), uintptr(information), uintptr(length), uintptr(class))
status = uint32(r0) status = uint32(r0)
return return
} }
func RtlNtStatusToDosError(status uint32) (winerr error) { func RtlNtStatusToDosError(status uint32) (winerr error) {
r0, _, _ := syscall.Syscall(procRtlNtStatusToDosError.Addr(), 1, uintptr(status), 0, 0) r0, _, _ := syscall.SyscallN(procRtlNtStatusToDosError.Addr(), uintptr(status))
if r0 != 0 { if r0 != 0 {
winerr = syscall.Errno(r0) winerr = syscall.Errno(r0)
} }
@ -382,7 +379,7 @@ func RtlNtStatusToDosError(status uint32) (winerr error) {
} }
func ORCloseHive(key syscall.Handle) (regerrno error) { func ORCloseHive(key syscall.Handle) (regerrno error) {
r0, _, _ := syscall.Syscall(procORCloseHive.Addr(), 1, uintptr(key), 0, 0) r0, _, _ := syscall.SyscallN(procORCloseHive.Addr(), uintptr(key))
if r0 != 0 { if r0 != 0 {
regerrno = syscall.Errno(r0) regerrno = syscall.Errno(r0)
} }
@ -390,7 +387,7 @@ func ORCloseHive(key syscall.Handle) (regerrno error) {
} }
func ORCreateHive(key *syscall.Handle) (regerrno error) { func ORCreateHive(key *syscall.Handle) (regerrno error) {
r0, _, _ := syscall.Syscall(procORCreateHive.Addr(), 1, uintptr(unsafe.Pointer(key)), 0, 0) r0, _, _ := syscall.SyscallN(procORCreateHive.Addr(), uintptr(unsafe.Pointer(key)))
if r0 != 0 { if r0 != 0 {
regerrno = syscall.Errno(r0) regerrno = syscall.Errno(r0)
} }
@ -407,7 +404,7 @@ func ORSaveHive(key syscall.Handle, file string, OsMajorVersion uint32, OsMinorV
} }
func _ORSaveHive(key syscall.Handle, file *uint16, OsMajorVersion uint32, OsMinorVersion uint32) (regerrno error) { func _ORSaveHive(key syscall.Handle, file *uint16, OsMajorVersion uint32, OsMinorVersion uint32) (regerrno error) {
r0, _, _ := syscall.Syscall6(procORSaveHive.Addr(), 4, uintptr(key), uintptr(unsafe.Pointer(file)), uintptr(OsMajorVersion), uintptr(OsMinorVersion), 0, 0) r0, _, _ := syscall.SyscallN(procORSaveHive.Addr(), uintptr(key), uintptr(unsafe.Pointer(file)), uintptr(OsMajorVersion), uintptr(OsMinorVersion))
if r0 != 0 { if r0 != 0 {
regerrno = syscall.Errno(r0) regerrno = syscall.Errno(r0)
} }

View File

@ -0,0 +1,35 @@
package osversion
// List of stable ABI compliant ltsc releases
// Note: List must be sorted in ascending order
var compatLTSCReleases = []uint16{
V21H2Server,
}
// CheckHostAndContainerCompat checks if given host and container
// OS versions are compatible.
// It includes support for stable ABI compliant versions as well.
// Every release after WS 2022 will support the previous ltsc
// container image. Stable ABI is in preview mode for windows 11 client.
// Refer: https://learn.microsoft.com/en-us/virtualization/windowscontainers/deploy-containers/version-compatibility?tabs=windows-server-2022%2Cwindows-10#windows-server-host-os-compatibility
func CheckHostAndContainerCompat(host, ctr OSVersion) bool {
// check major minor versions of host and guest
if host.MajorVersion != ctr.MajorVersion ||
host.MinorVersion != ctr.MinorVersion {
return false
}
// If host is < WS 2022, exact version match is required
if host.Build < V21H2Server {
return host.Build == ctr.Build
}
var supportedLtscRelease uint16
for i := len(compatLTSCReleases) - 1; i >= 0; i-- {
if host.Build >= compatLTSCReleases[i] {
supportedLtscRelease = compatLTSCReleases[i]
break
}
}
return ctr.Build >= supportedLtscRelease && ctr.Build <= host.Build
}

View File

@ -1,5 +0,0 @@
//go:build tools
package hcsshim
import _ "github.com/Microsoft/go-winio/tools/mkwinsyscall"

View File

@ -33,9 +33,6 @@ func errnoErr(e syscall.Errno) error {
case errnoERROR_IO_PENDING: case errnoERROR_IO_PENDING:
return errERROR_IO_PENDING return errERROR_IO_PENDING
} }
// TODO: add more here, after collecting data on the common
// error values see on Windows. (perhaps when running
// all.bat?)
return e return e
} }
@ -46,7 +43,7 @@ var (
) )
func SetCurrentThreadCompartmentId(compartmentId uint32) (hr error) { func SetCurrentThreadCompartmentId(compartmentId uint32) (hr error) {
r0, _, _ := syscall.Syscall(procSetCurrentThreadCompartmentId.Addr(), 1, uintptr(compartmentId), 0, 0) r0, _, _ := syscall.SyscallN(procSetCurrentThreadCompartmentId.Addr(), uintptr(compartmentId))
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff

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