Update docker client dependency (#1877)

* chore: update docker client lib

Signed-off-by: Matej Vasek <mvasek@redhat.com>

* fixup: "host" OCI pusher

Signed-off-by: Matej Vasek <mvasek@redhat.com>

* fixup: downgrade github.com/containers/image/v5

Signed-off-by: Matej Vasek <mvasek@redhat.com>

* fixup: platform tests

Signed-off-by: Matej Vasek <mvasek@redhat.com>

---------

Signed-off-by: Matej Vasek <mvasek@redhat.com>
This commit is contained in:
Matej Vasek 2023-07-20 12:50:12 +02:00 committed by GitHub
parent 36489f3a55
commit 5948cf4a07
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1304 changed files with 49635 additions and 48684 deletions

160
go.mod
View File

@ -5,29 +5,29 @@ go 1.20
require (
github.com/AlecAivazis/survey/v2 v2.3.6
github.com/Masterminds/semver v1.5.0
github.com/Microsoft/go-winio v0.6.0
github.com/Microsoft/go-winio v0.6.1
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2
github.com/alecthomas/jsonschema v0.0.0-20220216202328-9eeeec9d044b
github.com/buildpacks/pack v0.29.0
github.com/buildpacks/pack v0.30.0-pre3
github.com/cloudevents/sdk-go/v2 v2.14.0
github.com/containerd/containerd v1.6.19
github.com/containers/image/v5 v5.19.1
github.com/containerd/containerd v1.7.2
github.com/containers/image/v5 v5.26.1
github.com/coreos/go-semver v0.3.0
github.com/docker/cli v23.0.6+incompatible
github.com/docker/docker v23.0.6+incompatible
github.com/docker/cli v24.0.2+incompatible
github.com/docker/docker v24.0.5-0.20230718221249-d4a26c153000+incompatible
github.com/docker/docker-credential-helpers v0.7.0
github.com/docker/go-connections v0.4.0
github.com/go-git/go-billy/v5 v5.4.1
github.com/go-git/go-git/v5 v5.6.1
github.com/go-git/go-git/v5 v5.7.0
github.com/google/go-cmp v0.5.9
github.com/google/go-containerregistry v0.14.1-0.20230409045903-ed5c185df419
github.com/google/go-containerregistry v0.15.2
github.com/google/go-github/v49 v49.1.0
github.com/google/uuid v1.3.0
github.com/heroku/color v0.0.6
github.com/hinshun/vt10x v0.0.0-20220228203356-1ab2cad5fd82
github.com/opencontainers/image-spec v1.1.0-rc2
github.com/opencontainers/image-spec v1.1.0-rc4
github.com/openshift-pipelines/pipelines-as-code v0.17.1
github.com/openshift/source-to-image v1.3.1
github.com/openshift/source-to-image v1.3.8
github.com/ory/viper v1.7.5
github.com/pkg/errors v0.9.1
github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06
@ -38,11 +38,11 @@ require (
github.com/tektoncd/pipeline v0.47.0
github.com/whilp/git-urls v1.0.0
github.com/xanzy/go-gitlab v0.83.0
golang.org/x/crypto v0.8.0
golang.org/x/net v0.9.0
golang.org/x/oauth2 v0.7.0
golang.org/x/sync v0.1.0
golang.org/x/term v0.8.0
golang.org/x/crypto v0.11.0
golang.org/x/net v0.11.0
golang.org/x/oauth2 v0.9.0
golang.org/x/sync v0.3.0
golang.org/x/term v0.10.0
gopkg.in/yaml.v2 v2.4.0
gotest.tools/v3 v3.4.0
k8s.io/api v0.26.5
@ -55,65 +55,70 @@ require (
knative.dev/serving v0.37.1-0.20230603021539-349b2d61b0e8
)
require sigs.k8s.io/controller-runtime v0.7.2 // indirect
require (
github.com/OneOfOne/xxhash v1.2.8 // indirect
github.com/moby/patternmatcher v0.5.0 // indirect
github.com/moby/sys/sequential v0.5.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc // indirect
sigs.k8s.io/controller-runtime v0.7.2 // indirect
)
require (
cloud.google.com/go/compute v1.19.0 // indirect
cloud.google.com/go/compute v1.20.0 // indirect
cloud.google.com/go/compute/metadata v0.2.3 // indirect
contrib.go.opencensus.io/exporter/ocagent v0.7.1-0.20200907061046-05415f1de66d // indirect
contrib.go.opencensus.io/exporter/prometheus v0.4.2 // indirect
github.com/Azure/azure-sdk-for-go v68.0.0+incompatible // indirect
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
github.com/Azure/go-autorest/autorest v0.11.28 // indirect
github.com/Azure/go-autorest/autorest/adal v0.9.22 // indirect
github.com/Azure/go-autorest/autorest v0.11.29 // indirect
github.com/Azure/go-autorest/autorest/adal v0.9.23 // indirect
github.com/Azure/go-autorest/autorest/azure/auth v0.5.12 // indirect
github.com/Azure/go-autorest/autorest/azure/cli v0.4.6 // indirect
github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect
github.com/Azure/go-autorest/logger v0.2.1 // indirect
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
github.com/BurntSushi/toml v1.2.1 // indirect
github.com/Microsoft/hcsshim v0.9.7 // indirect
github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 // indirect
github.com/BurntSushi/toml v1.3.2 // indirect
github.com/ProtonMail/go-crypto v0.0.0-20230518184743-7afd39499903 // indirect
github.com/acomagu/bufpipe v1.0.4 // indirect
github.com/agext/levenshtein v1.2.3 // indirect
github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 // indirect
github.com/apex/log v1.9.0 // indirect
github.com/aws/aws-sdk-go-v2 v1.17.8 // indirect
github.com/aws/aws-sdk-go-v2/config v1.18.21 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.13.20 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.2 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.32 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.26 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.33 // indirect
github.com/aws/aws-sdk-go-v2/service/ecr v1.18.1 // indirect
github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.15.0 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.26 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.12.8 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.8 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.18.9 // indirect
github.com/aws/aws-sdk-go-v2 v1.18.1 // indirect
github.com/aws/aws-sdk-go-v2/config v1.18.27 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.13.26 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.4 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.34 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.28 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.35 // indirect
github.com/aws/aws-sdk-go-v2/service/ecr v1.18.11 // indirect
github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.16.2 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.28 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.12.12 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.12 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.19.2 // indirect
github.com/aws/smithy-go v1.13.5 // indirect
github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20230110223219-40efa3093a22 // indirect
github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20230522190001-adf1bafd791a // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/blendle/zapdriver v1.3.1 // indirect
github.com/buildpacks/imgutil v0.0.0-20230221152838-4cf98dd677d2 // indirect
github.com/buildpacks/lifecycle v0.16.0 // indirect
github.com/buildpacks/imgutil v0.0.0-20230626185301-726f02e4225c // indirect
github.com/buildpacks/lifecycle v0.17.0-rc.3 // indirect
github.com/census-instrumentation/opencensus-proto v0.4.1 // indirect
github.com/cespare/xxhash v1.1.0 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/chrismellard/docker-credential-acr-env v0.0.0-20221129204813-6a4d6ed5d396 // indirect
github.com/chrismellard/docker-credential-acr-env v0.0.0-20230304212654-82a0ddb27589 // indirect
github.com/cloudevents/sdk-go/sql/v2 v2.13.0 // indirect
github.com/cloudflare/circl v1.1.0 // indirect
github.com/containerd/cgroups v1.0.4 // indirect
github.com/cloudflare/circl v1.3.3 // indirect
github.com/containerd/stargz-snapshotter/estargz v0.14.3 // indirect
github.com/containerd/typeurl v1.0.2 // indirect
github.com/containers/storage v1.38.2 // indirect
github.com/containers/storage v1.48.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
github.com/creack/pty v1.1.18 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dgraph-io/ristretto v0.0.1 // indirect
github.com/dimchansky/utfbom v1.1.1 // indirect
github.com/docker/distribution v2.8.1+incompatible // indirect
github.com/docker/distribution v2.8.2+incompatible // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/emicklei/go-restful/v3 v3.10.1 // indirect
@ -125,13 +130,13 @@ require (
github.com/gdamore/encoding v1.0.0 // indirect
github.com/gdamore/tcell/v2 v2.6.0 // indirect
github.com/go-errors/errors v1.4.2 // indirect
github.com/go-git/gcfg v1.5.0 // indirect
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
github.com/go-kit/log v0.2.1 // indirect
github.com/go-logfmt/logfmt v0.6.0 // indirect
github.com/go-logr/logr v1.2.4 // indirect
github.com/go-openapi/jsonpointer v0.19.6 // indirect
github.com/go-openapi/jsonreference v0.20.2 // indirect
github.com/go-openapi/swag v0.22.3 // indirect
github.com/go-openapi/swag v0.22.4 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
@ -148,11 +153,11 @@ require (
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/go-retryablehttp v0.7.2 // indirect
github.com/hashicorp/go-retryablehttp v0.7.4 // indirect
github.com/hashicorp/golang-lru v0.6.0 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0 // indirect
github.com/imdario/mergo v0.3.13 // indirect
github.com/imdario/mergo v0.3.15 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
@ -162,7 +167,7 @@ require (
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/kelseyhightower/envconfig v1.4.0 // indirect
github.com/kevinburke/ssh_config v1.2.0 // indirect
github.com/klauspost/compress v1.16.0 // indirect
github.com/klauspost/compress v1.16.6 // indirect
github.com/kr/pty v1.1.8 // indirect
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
@ -171,7 +176,7 @@ require (
github.com/manifestival/client-go-client v0.5.0
github.com/manifestival/manifestival v0.7.2
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.17 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/mattn/go-runewidth v0.0.14 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
@ -179,46 +184,45 @@ require (
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/ioprogress v0.0.0-20180201004757-6a23b12fa88e // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/moby/buildkit v0.11.1 // indirect
github.com/moby/buildkit v0.11.6 // indirect
github.com/moby/spdystream v0.2.0 // indirect
github.com/moby/sys/mount v0.3.3 // indirect
github.com/moby/sys/mountinfo v0.6.2 // indirect
github.com/moby/term v0.0.0-20221205130635-1aeaba878587 // indirect
github.com/moby/term v0.5.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
github.com/morikuni/aec v1.0.0 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/runc v1.1.4 // indirect
github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417 // indirect
github.com/opencontainers/selinux v1.10.2 // indirect
github.com/opencontainers/runc v1.1.7 // indirect
github.com/opencontainers/runtime-spec v1.1.0-rc.3 // indirect
github.com/opencontainers/selinux v1.11.0 // indirect
github.com/openzipkin/zipkin-go v0.4.1 // indirect
github.com/pelletier/go-toml v1.9.5 // indirect
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
github.com/pjbgf/sha1cd v0.3.0 // indirect
github.com/prometheus/client_golang v1.14.0 // indirect
github.com/prometheus/client_model v0.3.0 // indirect
github.com/prometheus/common v0.42.0 // indirect
github.com/prometheus/procfs v0.9.0 // indirect
github.com/prometheus/client_golang v1.15.1 // indirect
github.com/prometheus/client_model v0.4.0 // indirect
github.com/prometheus/common v0.44.0 // indirect
github.com/prometheus/procfs v0.10.1 // indirect
github.com/prometheus/statsd_exporter v0.23.0 // indirect
github.com/rickb777/date v1.20.1 // indirect
github.com/rickb777/plural v1.4.1 // indirect
github.com/rivo/tview v0.0.0-20220307222120-9994674d60a8 // indirect
github.com/rivo/uniseg v0.4.3 // indirect
github.com/rivo/uniseg v0.4.4 // indirect
github.com/robfig/cron/v3 v3.0.1 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/sergi/go-diff v1.2.0 // indirect
github.com/sirupsen/logrus v1.9.0 // indirect
github.com/skeema/knownhosts v1.1.0 // indirect
github.com/spf13/afero v1.9.3 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/skeema/knownhosts v1.1.1 // indirect
github.com/spf13/afero v1.9.5 // indirect
github.com/spf13/cast v1.5.0 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/stoewer/go-strcase v1.2.1 // indirect
github.com/subosito/gotenv v1.4.2 // indirect
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 // indirect
github.com/tektoncd/triggers v0.23.1-0.20230420080448-bf603123cc0f // indirect
github.com/vbatts/tar-split v0.11.2 // indirect
github.com/vbatts/tar-split v0.11.3 // indirect
github.com/xanzy/ssh-agent v0.3.3 // indirect
github.com/xlab/treeprint v1.1.0 // indirect
go.opencensus.io v0.24.0 // indirect
@ -226,17 +230,17 @@ require (
go.uber.org/atomic v1.10.0 // indirect
go.uber.org/multierr v1.9.0 // indirect
go.uber.org/zap v1.24.0 // indirect
golang.org/x/exp v0.0.0-20230307190834-24139beb5833 // indirect
golang.org/x/mod v0.9.0 // indirect
golang.org/x/sys v0.8.0 // indirect
golang.org/x/text v0.9.0 // indirect
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 // indirect
golang.org/x/mod v0.12.0 // indirect
golang.org/x/sys v0.10.0 // indirect
golang.org/x/text v0.11.0 // indirect
golang.org/x/time v0.3.0 // indirect
golang.org/x/tools v0.7.0 // indirect
golang.org/x/tools v0.9.1 // indirect
gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect
google.golang.org/api v0.119.0 // indirect
google.golang.org/api v0.125.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
google.golang.org/grpc v1.54.0 // indirect
google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc // indirect
google.golang.org/grpc v1.55.0 // indirect
google.golang.org/protobuf v1.30.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
@ -244,9 +248,9 @@ require (
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/apiextensions-apiserver v0.26.5 // indirect
k8s.io/cli-runtime v0.25.9 // indirect
k8s.io/klog/v2 v2.90.1 // indirect
k8s.io/klog/v2 v2.100.1 // indirect
k8s.io/kube-openapi v0.0.0-20230308215209-15aac26d736a // indirect
k8s.io/utils v0.0.0-20230209194617-a36077c30491 // indirect
k8s.io/utils v0.0.0-20230220204549-a5ecb0141aa5 // indirect
knative.dev/networking v0.0.0-20230524170920-2a2f7d2d7c60 // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
sigs.k8s.io/kustomize/api v0.12.1 // indirect
@ -259,11 +263,11 @@ replace (
// Version used in Eventing
github.com/cloudevents/sdk-go/sql/v2 => github.com/cloudevents/sdk-go/sql/v2 v2.0.0-20220930150014-52b12276cc4a
github.com/docker/docker => github.com/docker/docker v20.10.21+incompatible
// Use older version since it checks ~/.docker/config.json for credentials as opposed to later versions
github.com/containers/image/v5 => github.com/containers/image/v5 v5.23.1
// Tekton CLI uses newer version without currently used constructor code
github.com/hinshun/vt10x => github.com/hinshun/vt10x v0.0.0-20180809195222-d55458df857c
// update docker to be compatible with version used by pack and removes invalid pseudo-version
github.com/openshift/source-to-image => github.com/boson-project/source-to-image v1.3.2
// Pin k8s.io dependencies to align with Knative and Tekton needs
k8s.io/api => k8s.io/api v0.25.4
k8s.io/apimachinery => k8s.io/apimachinery v0.25.4

1412
go.sum

File diff suppressed because it is too large Load Diff

View File

@ -97,7 +97,7 @@ func NewClient(defaultHost string) (dockerClient client.CommonAPIClient, dockerH
}
if !isSSH {
opts := []client.Opt{client.FromEnv}
opts := []client.Opt{client.FromEnv, client.WithAPIVersionNegotiation()}
if isTCP {
if httpClient := newHttpClient(); httpClient != nil {
opts = append(opts, client.WithHTTPClient(httpClient))

View File

@ -16,8 +16,6 @@ import (
"github.com/google/go-containerregistry/pkg/v1/empty"
"github.com/google/go-containerregistry/pkg/v1/mutate"
"github.com/google/go-containerregistry/pkg/v1/remote"
gcrTypes "github.com/google/go-containerregistry/pkg/v1/types"
"knative.dev/func/pkg/docker"
)
@ -52,16 +50,9 @@ func TestPlatform(t *testing.T) {
t.Fatal(err)
}
zeroHash := v1.Hash{
Algorithm: "sha256",
Hex: "0000000000000000000000000000000000000000000000000000000000000000",
}
var imgIdx = mutate.AppendManifests(empty.Index, mutate.IndexAddendum{
Add: empty.Index,
Add: img,
Descriptor: v1.Descriptor{
MediaType: gcrTypes.DockerManifestList,
Digest: zeroHash,
Platform: &v1.Platform{
Architecture: "ppc64le",
OS: "linux",
@ -99,8 +90,13 @@ func TestPlatform(t *testing.T) {
if err != nil {
t.Errorf("unexpeced error: %v", err)
}
if ref != testRegistry+"/default/builder@sha256:0000000000000000000000000000000000000000000000000000000000000000" {
t.Error("incorrect reference")
imgDigest, err := img.Digest()
if err != nil {
t.Fatal(err)
}
if ref != testRegistry+"/default/builder@"+imgDigest.String() {
t.Errorf("incorrect reference: %q", ref)
}
}
@ -118,7 +114,7 @@ func startRegistry(t *testing.T) (addr string) {
go func() {
err = s.Serve(l)
if err != nil && !errors.Is(err, net.ErrClosed) {
if err != nil && !errors.Is(err, http.ErrServerClosed) {
fmt.Fprintln(os.Stderr, "ERROR: ", err)
}
}()

View File

@ -16,6 +16,7 @@ import (
fn "knative.dev/func/pkg/functions"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/registry"
"github.com/docker/docker/client"
"github.com/docker/docker/pkg/jsonmessage"
"github.com/google/go-containerregistry/pkg/authn"
@ -157,7 +158,7 @@ func (n *Pusher) daemonPush(ctx context.Context, f fn.Function, credentials Cred
}
defer cli.Close()
authConfig := types.AuthConfig{
authConfig := registry.AuthConfig{
Username: credentials.Username,
Password: credentials.Password,
}

View File

@ -14,6 +14,7 @@ import (
"crypto/x509/pkix"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"io"
"log"
@ -27,6 +28,7 @@ import (
"time"
"github.com/docker/docker/api/types"
api "github.com/docker/docker/api/types/image"
"github.com/google/go-containerregistry/pkg/authn"
"github.com/google/go-containerregistry/pkg/name"
"github.com/google/go-containerregistry/pkg/registry"
@ -316,6 +318,10 @@ func (m *mockPusherDockerClient) ImagePush(ctx context.Context, ref string, opti
return m.imagePush(ctx, ref, options)
}
func (m *mockPusherDockerClient) ImageHistory(context.Context, string) ([]api.HistoryResponseItem, error) {
return nil, errors.New("the ImageHistory() function is not implemented")
}
func (m *mockPusherDockerClient) Close() error {
return m.close()
}

View File

@ -60,7 +60,7 @@ func (n *Runner) Run(ctx context.Context, f fn.Function, startTimeout time.Durat
// Channels for gathering runtime errors from the container instance
copyErrCh = make(chan error, 10)
contBodyCh <-chan container.ContainerWaitOKBody
contBodyCh <-chan container.WaitResponse
contErrCh <-chan error
// Combined runtime error channel for sending all errors to caller
@ -116,7 +116,11 @@ func (n *Runner) Run(ctx context.Context, f fn.Function, startTimeout time.Durat
timeout = DefaultStopTimeout
ctx = context.Background()
)
if err = c.ContainerStop(ctx, id, &timeout); err != nil {
timeoutSecs := int(timeout.Seconds())
ctrStopOpts := container.StopOptions{
Timeout: &timeoutSecs,
}
if err = c.ContainerStop(ctx, id, ctrStopOpts); err != nil {
return fmt.Errorf("error stopping container %v: %v\n", id, err)
}
if err = c.ContainerRemove(ctx, id, types.ContainerRemoveOptions{}); err != nil {

View File

@ -5,7 +5,6 @@ import (
"io"
"net"
"net/http"
"time"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
@ -109,7 +108,7 @@ func (c *closeGuardingClient) ContainerCommit(arg0 context.Context, arg1 string,
return c.pimpl.ContainerCommit(arg0, arg1, arg2)
}
func (c *closeGuardingClient) ContainerCreate(arg0 context.Context, arg1 *container.Config, arg2 *container.HostConfig, arg3 *network.NetworkingConfig, arg4 *v1.Platform, arg5 string) (container.ContainerCreateCreatedBody, error) {
func (c *closeGuardingClient) ContainerCreate(arg0 context.Context, arg1 *container.Config, arg2 *container.HostConfig, arg3 *network.NetworkingConfig, arg4 *v1.Platform, arg5 string) (container.CreateResponse, error) {
c.m.RLock()
defer c.m.RUnlock()
if c.closed {
@ -118,7 +117,7 @@ func (c *closeGuardingClient) ContainerCreate(arg0 context.Context, arg1 *contai
return c.pimpl.ContainerCreate(arg0, arg1, arg2, arg3, arg4, arg5)
}
func (c *closeGuardingClient) ContainerDiff(arg0 context.Context, arg1 string) ([]container.ContainerChangeResponseItem, error) {
func (c *closeGuardingClient) ContainerDiff(arg0 context.Context, arg1 string) ([]container.FilesystemChange, error) {
c.m.RLock()
defer c.m.RUnlock()
if c.closed {
@ -262,7 +261,7 @@ func (c *closeGuardingClient) ContainerResize(arg0 context.Context, arg1 string,
return c.pimpl.ContainerResize(arg0, arg1, arg2)
}
func (c *closeGuardingClient) ContainerRestart(arg0 context.Context, arg1 string, arg2 *time.Duration) error {
func (c *closeGuardingClient) ContainerRestart(arg0 context.Context, arg1 string, arg2 container.StopOptions) error {
c.m.RLock()
defer c.m.RUnlock()
if c.closed {
@ -307,7 +306,7 @@ func (c *closeGuardingClient) ContainerStatsOneShot(arg0 context.Context, arg1 s
return c.pimpl.ContainerStatsOneShot(arg0, arg1)
}
func (c *closeGuardingClient) ContainerStop(arg0 context.Context, arg1 string, arg2 *time.Duration) error {
func (c *closeGuardingClient) ContainerStop(arg0 context.Context, arg1 string, arg2 container.StopOptions) error {
c.m.RLock()
defer c.m.RUnlock()
if c.closed {
@ -343,7 +342,7 @@ func (c *closeGuardingClient) ContainerUpdate(arg0 context.Context, arg1 string,
return c.pimpl.ContainerUpdate(arg0, arg1, arg2)
}
func (c *closeGuardingClient) ContainerWait(arg0 context.Context, arg1 string, arg2 container.WaitCondition) (<-chan container.ContainerWaitOKBody, <-chan error) {
func (c *closeGuardingClient) ContainerWait(arg0 context.Context, arg1 string, arg2 container.WaitCondition) (<-chan container.WaitResponse, <-chan error) {
c.m.RLock()
defer c.m.RUnlock()
if c.closed {
@ -406,13 +405,13 @@ func (c *closeGuardingClient) Dialer() func(context.Context) (net.Conn, error) {
return c.pimpl.Dialer()
}
func (c *closeGuardingClient) DiskUsage(arg0 context.Context) (types.DiskUsage, error) {
func (c *closeGuardingClient) DiskUsage(arg0 context.Context, arg1 types.DiskUsageOptions) (types.DiskUsage, error) {
c.m.RLock()
defer c.m.RUnlock()
if c.closed {
panic("use of closed client")
}
return c.pimpl.DiskUsage(arg0)
return c.pimpl.DiskUsage(arg0, arg1)
}
func (c *closeGuardingClient) DistributionInspect(arg0 context.Context, arg1 string, arg2 string) (registry.DistributionInspect, error) {
@ -802,7 +801,7 @@ func (c *closeGuardingClient) PluginUpgrade(arg0 context.Context, arg1 string, a
return c.pimpl.PluginUpgrade(arg0, arg1, arg2)
}
func (c *closeGuardingClient) RegistryLogin(arg0 context.Context, arg1 types.AuthConfig) (registry.AuthenticateOKBody, error) {
func (c *closeGuardingClient) RegistryLogin(arg0 context.Context, arg1 registry.AuthConfig) (registry.AuthenticateOKBody, error) {
c.m.RLock()
defer c.m.RUnlock()
if c.closed {
@ -1009,7 +1008,7 @@ func (c *closeGuardingClient) TaskLogs(arg0 context.Context, arg1 string, arg2 t
return c.pimpl.TaskLogs(arg0, arg1, arg2)
}
func (c *closeGuardingClient) VolumeCreate(arg0 context.Context, arg1 volume.VolumeCreateBody) (types.Volume, error) {
func (c *closeGuardingClient) VolumeCreate(arg0 context.Context, arg1 volume.CreateOptions) (volume.Volume, error) {
c.m.RLock()
defer c.m.RUnlock()
if c.closed {
@ -1018,7 +1017,7 @@ func (c *closeGuardingClient) VolumeCreate(arg0 context.Context, arg1 volume.Vol
return c.pimpl.VolumeCreate(arg0, arg1)
}
func (c *closeGuardingClient) VolumeInspect(arg0 context.Context, arg1 string) (types.Volume, error) {
func (c *closeGuardingClient) VolumeInspect(arg0 context.Context, arg1 string) (volume.Volume, error) {
c.m.RLock()
defer c.m.RUnlock()
if c.closed {
@ -1027,7 +1026,7 @@ func (c *closeGuardingClient) VolumeInspect(arg0 context.Context, arg1 string) (
return c.pimpl.VolumeInspect(arg0, arg1)
}
func (c *closeGuardingClient) VolumeInspectWithRaw(arg0 context.Context, arg1 string) (types.Volume, []uint8, error) {
func (c *closeGuardingClient) VolumeInspectWithRaw(arg0 context.Context, arg1 string) (volume.Volume, []uint8, error) {
c.m.RLock()
defer c.m.RUnlock()
if c.closed {
@ -1036,7 +1035,7 @@ func (c *closeGuardingClient) VolumeInspectWithRaw(arg0 context.Context, arg1 st
return c.pimpl.VolumeInspectWithRaw(arg0, arg1)
}
func (c *closeGuardingClient) VolumeList(arg0 context.Context, arg1 filters.Args) (volume.VolumeListOKBody, error) {
func (c *closeGuardingClient) VolumeList(arg0 context.Context, arg1 volume.ListOptions) (volume.ListResponse, error) {
c.m.RLock()
defer c.m.RUnlock()
if c.closed {
@ -1062,3 +1061,12 @@ func (c *closeGuardingClient) VolumesPrune(arg0 context.Context, arg1 filters.Ar
}
return c.pimpl.VolumesPrune(arg0, arg1)
}
func (c *closeGuardingClient) VolumeUpdate(arg0 context.Context, arg1 string, arg2 swarm.Version, arg3 volume.UpdateOptions) error {
c.m.RLock()
defer c.m.RUnlock()
if c.closed {
panic("use of closed client")
}
return c.pimpl.VolumeUpdate(arg0, arg1, arg2, arg3)
}

View File

@ -2,16 +2,17 @@ package oci
import (
"context"
"encoding/json"
"errors"
"fmt"
"io"
"log"
"net"
"net/http"
"net/http/httputil"
"os"
"testing"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/registry"
fn "knative.dev/func/pkg/functions"
. "knative.dev/func/pkg/testing"
)
@ -33,38 +34,17 @@ func TestPusher(t *testing.T) {
// Start a handler on an OS-chosen port which confirms that an incoming
// requests looks for the most part like what we'd expect to see from a
// container push.
regLog := io.Discard
if verbose {
regLog = os.Stderr
}
regHandler := registry.New(registry.Logger(log.New(regLog, "img reg handler: ", log.LstdFlags)))
handler := http.NewServeMux()
handler.HandleFunc("/", func(res http.ResponseWriter, req *http.Request) {
if verbose {
fmt.Println("Mock registry server received request:")
fmt.Println("--------------------------------------")
requestDump, err := httputil.DumpRequest(req, true)
if err != nil {
t.Fatal(err)
}
fmt.Println(string(requestDump))
}
// Ignore all requests except the PUTs
if req.Method != http.MethodPut {
return
}
// Ignore all PUTs except the the image index
if req.Header.Get("Content-Type") != "application/vnd.oci.image.index.v1+json" {
return
}
// Decode the request as an index JSON
index := v1.IndexManifest{}
d := json.NewDecoder(req.Body)
defer req.Body.Close()
if err := d.Decode(&index); err != nil {
t.Fatal(err)
}
regHandler.ServeHTTP(res, req)
if req.Method == http.MethodPut && req.URL.Path == "/v2/funcs/f/manifests/latest" {
success = true
}
})
l, err := net.Listen("tcp4", "127.0.0.1:")
if err != nil {

View File

@ -0,0 +1,9 @@
## 0.7.4 (Jun 6, 2023)
BUG FIXES
- client: fixing an issue where the Content-Type header wouldn't be sent with an empty payload when using HTTP/2 [GH-194]
## 0.7.3 (May 15, 2023)
Initial release

View File

@ -0,0 +1 @@
* @hashicorp/release-engineering

View File

@ -1,3 +1,5 @@
Copyright (c) 2015 HashiCorp, Inc.
Mozilla Public License, version 2.0
1. Definitions

View File

@ -1,3 +1,6 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
// Package retryablehttp provides a familiar HTTP client interface with
// automatic retries and exponential backoff. It is a thin wrapper over the
// standard net/http client library and exposes nearly the same public API.
@ -257,10 +260,17 @@ func getBodyReaderAndContentLength(rawBody interface{}) (ReaderFunc, int64, erro
if err != nil {
return nil, 0, err
}
if len(buf) == 0 {
bodyReader = func() (io.Reader, error) {
return http.NoBody, nil
}
contentLength = 0
} else {
bodyReader = func() (io.Reader, error) {
return bytes.NewReader(buf), nil
}
contentLength = int64(len(buf))
}
// No body provided, nothing to do
case nil:

View File

@ -1,3 +1,6 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package retryablehttp
import (

View File

@ -0,0 +1,191 @@
Apache License
Version 2.0, January 2004
https://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
Copyright 2013-2018 Docker, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -0,0 +1,16 @@
Docker
Copyright 2012-2017 Docker, Inc.
This product includes software developed at Docker, Inc. (https://www.docker.com).
The following is courtesy of our legal counsel:
Use and transfer of Docker may be subject to certain restrictions by the
United States and other governments.
It is your responsibility to ensure that your use and/or transfer does not
violate applicable laws.
For more information, please see https://www.bis.doc.gov
See also https://www.apache.org/dev/crypto.html and/or seek legal counsel.

View File

@ -1,4 +1,4 @@
Copyright 2022 Skeema LLC
Copyright 2023 Skeema LLC and the Skeema authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@ -1,3 +1,4 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/

View File

@ -15,4 +15,4 @@
package internal
// Version is the current tagged release of the library.
const Version = "1.19.0"
const Version = "1.20.0"

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

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

View File

@ -127,6 +127,9 @@ type TokenRefreshCallback func(Token) error
// TokenRefresh is a type representing a custom callback to refresh a token
type TokenRefresh func(ctx context.Context, resource string) (*Token, error)
// JWTCallback is the type representing callback that will be called to get the federated OIDC JWT
type JWTCallback func() (string, error)
// Token encapsulates the access token used to authorize Azure requests.
// https://docs.microsoft.com/en-us/azure/active-directory/develop/v1-oauth2-client-creds-grant-flow#service-to-service-access-token-response
type Token struct {
@ -367,14 +370,18 @@ func (secret ServicePrincipalAuthorizationCodeSecret) MarshalJSON() ([]byte, err
// ServicePrincipalFederatedSecret implements ServicePrincipalSecret for Federated JWTs.
type ServicePrincipalFederatedSecret struct {
jwt string
jwtCallback JWTCallback
}
// SetAuthenticationValues is a method of the interface ServicePrincipalSecret.
// It will populate the form submitted during OAuth Token Acquisition using a JWT signed by an OIDC issuer.
func (secret *ServicePrincipalFederatedSecret) SetAuthenticationValues(spt *ServicePrincipalToken, v *url.Values) error {
func (secret *ServicePrincipalFederatedSecret) SetAuthenticationValues(_ *ServicePrincipalToken, v *url.Values) error {
jwt, err := secret.jwtCallback()
if err != nil {
return err
}
v.Set("client_assertion", secret.jwt)
v.Set("client_assertion", jwt)
v.Set("client_assertion_type", "urn:ietf:params:oauth:client-assertion-type:jwt-bearer")
return nil
}
@ -687,6 +694,8 @@ func NewServicePrincipalTokenFromAuthorizationCode(oauthConfig OAuthConfig, clie
}
// NewServicePrincipalTokenFromFederatedToken creates a ServicePrincipalToken from the supplied federated OIDC JWT.
//
// Deprecated: Use NewServicePrincipalTokenFromFederatedTokenWithCallback to refresh jwt dynamically.
func NewServicePrincipalTokenFromFederatedToken(oauthConfig OAuthConfig, clientID string, jwt string, resource string, callbacks ...TokenRefreshCallback) (*ServicePrincipalToken, error) {
if err := validateOAuthConfig(oauthConfig); err != nil {
return nil, err
@ -700,12 +709,37 @@ func NewServicePrincipalTokenFromFederatedToken(oauthConfig OAuthConfig, clientI
if jwt == "" {
return nil, fmt.Errorf("parameter 'jwt' cannot be empty")
}
return NewServicePrincipalTokenFromFederatedTokenCallback(
oauthConfig,
clientID,
func() (string, error) {
return jwt, nil
},
resource,
callbacks...,
)
}
// NewServicePrincipalTokenFromFederatedTokenCallback creates a ServicePrincipalToken from the supplied federated OIDC JWTCallback.
func NewServicePrincipalTokenFromFederatedTokenCallback(oauthConfig OAuthConfig, clientID string, jwtCallback JWTCallback, resource string, callbacks ...TokenRefreshCallback) (*ServicePrincipalToken, error) {
if err := validateOAuthConfig(oauthConfig); err != nil {
return nil, err
}
if err := validateStringParam(clientID, "clientID"); err != nil {
return nil, err
}
if err := validateStringParam(resource, "resource"); err != nil {
return nil, err
}
if jwtCallback == nil {
return nil, fmt.Errorf("parameter 'jwtCallback' cannot be empty")
}
return NewServicePrincipalTokenWithSecret(
oauthConfig,
clientID,
resource,
&ServicePrincipalFederatedSecret{
jwt: jwt,
jwtCallback: jwtCallback,
},
callbacks...,
)

View File

@ -214,7 +214,7 @@ func (r Resource) String() string {
// See https://docs.microsoft.com/en-us/azure/azure-resource-manager/templates/template-functions-resource?tabs=json#resourceid.
func ParseResourceID(resourceID string) (Resource, error) {
const resourceIDPatternText = `(?i)subscriptions/(.+)/resourceGroups/(.+)/providers/(.+?)/(.+?)/(.+)`
const resourceIDPatternText = `(?i)^/subscriptions/(.+)/resourceGroups/(.+)/providers/(.+?)/(.+?)/(.+)$`
resourceIDPattern := regexp.MustCompile(resourceIDPatternText)
match := resourceIDPattern.FindStringSubmatch(resourceID)

View File

@ -60,9 +60,9 @@ func NewDecoder(encodedAs EncodedAs, r io.Reader) Decoder {
// is especially useful if there is a chance the data will fail to decode.
// encodedAs specifies the expected encoding, r provides the io.Reader to the data, and v
// is the decoding destination.
func CopyAndDecode(encodedAs EncodedAs, r io.Reader, v interface{}) (bytes.Buffer, error) {
b := bytes.Buffer{}
return b, NewDecoder(encodedAs, io.TeeReader(r, &b)).Decode(v)
func CopyAndDecode(encodedAs EncodedAs, r io.Reader, v interface{}) (b bytes.Buffer, err error) {
err = NewDecoder(encodedAs, io.TeeReader(r, &b)).Decode(v)
return
}
// TeeReadCloser returns a ReadCloser that writes to w what it reads from rc.

View File

@ -91,7 +91,7 @@ const (
// UnmarshalText method. See the Unmarshaler example for a demonstration with
// email addresses.
//
// ### Key mapping
// # Key mapping
//
// TOML keys can map to either keys in a Go map or field names in a Go struct.
// The special `toml` struct tag can be used to map TOML keys to struct fields
@ -248,7 +248,7 @@ func (md *MetaData) unify(data interface{}, rv reflect.Value) error {
case reflect.Bool:
return md.unifyBool(data, rv)
case reflect.Interface:
if rv.NumMethod() > 0 { // Only support empty interfaces are supported.
if rv.NumMethod() > 0 { /// Only empty interfaces are supported.
return md.e("unsupported type %s", rv.Type())
}
return md.unifyAnything(data, rv)

View File

@ -5,17 +5,25 @@ import (
"io"
)
// TextMarshaler is an alias for encoding.TextMarshaler.
//
// Deprecated: use encoding.TextMarshaler
type TextMarshaler encoding.TextMarshaler
// TextUnmarshaler is an alias for encoding.TextUnmarshaler.
//
// Deprecated: use encoding.TextUnmarshaler
type TextUnmarshaler encoding.TextUnmarshaler
// PrimitiveDecode is an alias for MetaData.PrimitiveDecode().
//
// Deprecated: use MetaData.PrimitiveDecode.
func PrimitiveDecode(primValue Primitive, v interface{}) error {
md := MetaData{decoded: make(map[string]struct{})}
return md.unify(primValue.undecoded, rvalue(v))
}
// DecodeReader is an alias for NewDecoder(r).Decode(v).
//
// Deprecated: use NewDecoder(reader).Decode(&value).
func DecodeReader(r io.Reader, v interface{}) (MetaData, error) { return NewDecoder(r).Decode(v) }

View File

@ -136,7 +136,8 @@ func NewEncoder(w io.Writer) *Encoder {
// document.
func (enc *Encoder) Encode(v interface{}) error {
rv := eindirect(reflect.ValueOf(v))
if err := enc.safeEncode(Key([]string{}), rv); err != nil {
err := enc.safeEncode(Key([]string{}), rv)
if err != nil {
return err
}
return enc.w.Flush()
@ -457,6 +458,16 @@ func (enc *Encoder) eStruct(key Key, rv reflect.Value, inline bool) {
frv := eindirect(rv.Field(i))
if is32Bit {
// Copy so it works correct on 32bit archs; not clear why this
// is needed. See #314, and https://www.reddit.com/r/golang/comments/pnx8v4
// This also works fine on 64bit, but 32bit archs are somewhat
// rare and this is a wee bit faster.
copyStart := make([]int, len(start))
copy(copyStart, start)
start = copyStart
}
// Treat anonymous struct fields with tag names as though they are
// not anonymous, like encoding/json does.
//
@ -470,44 +481,37 @@ func (enc *Encoder) eStruct(key Key, rv reflect.Value, inline bool) {
if typeIsTable(tomlTypeOfGo(frv)) {
fieldsSub = append(fieldsSub, append(start, f.Index...))
} else {
// Copy so it works correct on 32bit archs; not clear why this
// is needed. See #314, and https://www.reddit.com/r/golang/comments/pnx8v4
// This also works fine on 64bit, but 32bit archs are somewhat
// rare and this is a wee bit faster.
if is32Bit {
copyStart := make([]int, len(start))
copy(copyStart, start)
fieldsDirect = append(fieldsDirect, append(copyStart, f.Index...))
} else {
fieldsDirect = append(fieldsDirect, append(start, f.Index...))
}
}
}
}
addFields(rt, rv, nil)
writeFields := func(fields [][]int) {
for _, fieldIndex := range fields {
fieldType := rt.FieldByIndex(fieldIndex)
fieldVal := eindirect(rv.FieldByIndex(fieldIndex))
if isNil(fieldVal) { /// Don't write anything for nil fields.
continue
}
fieldVal := rv.FieldByIndex(fieldIndex)
opts := getOptions(fieldType.Tag)
if opts.skip {
continue
}
if opts.omitempty && isEmpty(fieldVal) {
continue
}
fieldVal = eindirect(fieldVal)
if isNil(fieldVal) { /// Don't write anything for nil fields.
continue
}
keyName := fieldType.Name
if opts.name != "" {
keyName = opts.name
}
if opts.omitempty && enc.isEmpty(fieldVal) {
continue
}
if opts.omitzero && isZero(fieldVal) {
continue
}
@ -649,7 +653,7 @@ func isZero(rv reflect.Value) bool {
return false
}
func (enc *Encoder) isEmpty(rv reflect.Value) bool {
func isEmpty(rv reflect.Value) bool {
switch rv.Kind() {
case reflect.Array, reflect.Slice, reflect.Map, reflect.String:
return rv.Len() == 0
@ -664,13 +668,15 @@ func (enc *Encoder) isEmpty(rv reflect.Value) bool {
// type b struct{ s []string }
// s := a{field: b{s: []string{"AAA"}}}
for i := 0; i < rv.NumField(); i++ {
if !enc.isEmpty(rv.Field(i)) {
if !isEmpty(rv.Field(i)) {
return false
}
}
return true
case reflect.Bool:
return !rv.Bool()
case reflect.Ptr:
return rv.IsNil()
}
return false
}
@ -693,8 +699,11 @@ func (enc *Encoder) newline() {
// v v v v vv
// key = {k = 1, k2 = 2}
func (enc *Encoder) writeKeyValue(key Key, val reflect.Value, inline bool) {
/// Marshaler used on top-level document; call eElement() to just call
/// Marshal{TOML,Text}.
if len(key) == 0 {
encPanic(errNoKey)
enc.eElement(val)
return
}
enc.wf("%s%s = ", enc.indentStr(key), key.maybeQuoted(len(key)-1))
enc.eElement(val)

View File

@ -84,7 +84,7 @@ func (pe ParseError) Error() string {
pe.Position.Line, pe.LastKey, msg)
}
// ErrorWithUsage() returns the error with detailed location context.
// ErrorWithPosition returns the error with detailed location context.
//
// See the documentation on [ParseError].
func (pe ParseError) ErrorWithPosition() string {
@ -124,7 +124,7 @@ func (pe ParseError) ErrorWithPosition() string {
return b.String()
}
// ErrorWithUsage() returns the error with detailed location context and usage
// ErrorWithUsage returns the error with detailed location context and usage
// guidance.
//
// See the documentation on [ParseError].

View File

@ -52,6 +52,7 @@ type lexer struct {
line int
state stateFn
items chan item
tomlNext bool
// Allow for backing up up to 4 runes. This is necessary because TOML
// contains 3-rune tokens (""" and ''').
@ -87,13 +88,14 @@ func (lx *lexer) nextItem() item {
}
}
func lex(input string) *lexer {
func lex(input string, tomlNext bool) *lexer {
lx := &lexer{
input: input,
state: lexTop,
items: make(chan item, 10),
stack: make([]stateFn, 0, 10),
line: 1,
tomlNext: tomlNext,
}
return lx
}
@ -408,7 +410,7 @@ func lexTableNameEnd(lx *lexer) stateFn {
// Lexes only one part, e.g. only 'a' inside 'a.b'.
func lexBareName(lx *lexer) stateFn {
r := lx.next()
if isBareKeyChar(r) {
if isBareKeyChar(r, lx.tomlNext) {
return lexBareName
}
lx.backup()
@ -618,6 +620,9 @@ func lexInlineTableValue(lx *lexer) stateFn {
case isWhitespace(r):
return lexSkip(lx, lexInlineTableValue)
case isNL(r):
if lx.tomlNext {
return lexSkip(lx, lexInlineTableValue)
}
return lx.errorPrevLine(errLexInlineTableNL{})
case r == '#':
lx.push(lexInlineTableValue)
@ -640,6 +645,9 @@ func lexInlineTableValueEnd(lx *lexer) stateFn {
case isWhitespace(r):
return lexSkip(lx, lexInlineTableValueEnd)
case isNL(r):
if lx.tomlNext {
return lexSkip(lx, lexInlineTableValueEnd)
}
return lx.errorPrevLine(errLexInlineTableNL{})
case r == '#':
lx.push(lexInlineTableValueEnd)
@ -648,6 +656,9 @@ func lexInlineTableValueEnd(lx *lexer) stateFn {
lx.ignore()
lx.skip(isWhitespace)
if lx.peek() == '}' {
if lx.tomlNext {
return lexInlineTableValueEnd
}
return lx.errorf("trailing comma not allowed in inline tables")
}
return lexInlineTableValue
@ -770,8 +781,8 @@ func lexRawString(lx *lexer) stateFn {
}
}
// lexMultilineRawString consumes a raw string. Nothing can be escaped in such
// a string. It assumes that the beginning ''' has already been consumed and
// lexMultilineRawString consumes a raw string. Nothing can be escaped in such a
// string. It assumes that the beginning triple-' has already been consumed and
// ignored.
func lexMultilineRawString(lx *lexer) stateFn {
r := lx.next()
@ -828,6 +839,11 @@ func lexMultilineStringEscape(lx *lexer) stateFn {
func lexStringEscape(lx *lexer) stateFn {
r := lx.next()
switch r {
case 'e':
if !lx.tomlNext {
return lx.error(errLexEscape{r})
}
fallthrough
case 'b':
fallthrough
case 't':
@ -846,6 +862,11 @@ func lexStringEscape(lx *lexer) stateFn {
fallthrough
case '\\':
return lx.pop()
case 'x':
if !lx.tomlNext {
return lx.error(errLexEscape{r})
}
return lexHexEscape
case 'u':
return lexShortUnicodeEscape
case 'U':
@ -854,6 +875,19 @@ func lexStringEscape(lx *lexer) stateFn {
return lx.error(errLexEscape{r})
}
func lexHexEscape(lx *lexer) stateFn {
var r rune
for i := 0; i < 2; i++ {
r = lx.next()
if !isHexadecimal(r) {
return lx.errorf(
`expected two hexadecimal digits after '\x', but got %q instead`,
lx.current())
}
}
return lx.pop()
}
func lexShortUnicodeEscape(lx *lexer) stateFn {
var r rune
for i := 0; i < 4; i++ {
@ -1225,7 +1259,23 @@ func isOctal(r rune) bool { return r >= '0' && r <= '7' }
func isHexadecimal(r rune) bool {
return (r >= '0' && r <= '9') || (r >= 'a' && r <= 'f') || (r >= 'A' && r <= 'F')
}
func isBareKeyChar(r rune) bool {
func isBareKeyChar(r rune, tomlNext bool) bool {
if tomlNext {
return (r >= 'A' && r <= 'Z') ||
(r >= 'a' && r <= 'z') ||
(r >= '0' && r <= '9') ||
r == '_' || r == '-' ||
r == 0xb2 || r == 0xb3 || r == 0xb9 || (r >= 0xbc && r <= 0xbe) ||
(r >= 0xc0 && r <= 0xd6) || (r >= 0xd8 && r <= 0xf6) || (r >= 0xf8 && r <= 0x037d) ||
(r >= 0x037f && r <= 0x1fff) ||
(r >= 0x200c && r <= 0x200d) || (r >= 0x203f && r <= 0x2040) ||
(r >= 0x2070 && r <= 0x218f) || (r >= 0x2460 && r <= 0x24ff) ||
(r >= 0x2c00 && r <= 0x2fef) || (r >= 0x3001 && r <= 0xd7ff) ||
(r >= 0xf900 && r <= 0xfdcf) || (r >= 0xfdf0 && r <= 0xfffd) ||
(r >= 0x10000 && r <= 0xeffff)
}
return (r >= 'A' && r <= 'Z') ||
(r >= 'a' && r <= 'z') ||
(r >= '0' && r <= '9') ||

View File

@ -106,7 +106,7 @@ func (k Key) maybeQuoted(i int) string {
return `""`
}
for _, c := range k[i] {
if !isBareKeyChar(c) {
if !isBareKeyChar(c, false) {
return `"` + dblQuotedReplacer.Replace(k[i]) + `"`
}
}

View File

@ -2,6 +2,7 @@ package toml
import (
"fmt"
"os"
"strconv"
"strings"
"time"
@ -15,6 +16,7 @@ type parser struct {
context Key // Full key for the current hash in scope.
currentKey string // Base key name for everything except hashes.
pos Position // Current position in the TOML file.
tomlNext bool
ordered []Key // List of keys in the order that they appear in the TOML data.
@ -29,6 +31,8 @@ type keyInfo struct {
}
func parse(data string) (p *parser, err error) {
_, tomlNext := os.LookupEnv("BURNTSUSHI_TOML_110")
defer func() {
if r := recover(); r != nil {
if pErr, ok := r.(ParseError); ok {
@ -41,9 +45,12 @@ func parse(data string) (p *parser, err error) {
}()
// Read over BOM; do this here as the lexer calls utf8.DecodeRuneInString()
// which mangles stuff.
if strings.HasPrefix(data, "\xff\xfe") || strings.HasPrefix(data, "\xfe\xff") {
// which mangles stuff. UTF-16 BOM isn't strictly valid, but some tools add
// it anyway.
if strings.HasPrefix(data, "\xff\xfe") || strings.HasPrefix(data, "\xfe\xff") { // UTF-16
data = data[2:]
} else if strings.HasPrefix(data, "\xef\xbb\xbf") { // UTF-8
data = data[3:]
}
// Examine first few bytes for NULL bytes; this probably means it's a UTF-16
@ -65,9 +72,10 @@ func parse(data string) (p *parser, err error) {
p = &parser{
keyInfo: make(map[string]keyInfo),
mapping: make(map[string]interface{}),
lx: lex(data),
lx: lex(data, tomlNext),
ordered: make([]Key, 0),
implicits: make(map[string]struct{}),
tomlNext: tomlNext,
}
for {
item := p.next()
@ -194,12 +202,12 @@ func (p *parser) topLevel(item item) {
for i := range context {
p.addImplicitContext(append(p.context, context[i:i+1]...))
}
p.ordered = append(p.ordered, p.context.add(p.currentKey))
/// Set value.
vItem := p.next()
val, typ := p.value(vItem, false)
p.set(p.currentKey, val, typ, vItem.pos)
p.ordered = append(p.ordered, p.context.add(p.currentKey))
/// Remove the context we added (preserving any context from [tbl] lines).
p.context = outerContext
@ -236,7 +244,7 @@ func (p *parser) value(it item, parentIsArray bool) (interface{}, tomlType) {
case itemString:
return p.replaceEscapes(it, it.val), p.typeOfPrimitive(it)
case itemMultilineString:
return p.replaceEscapes(it, stripFirstNewline(p.stripEscapedNewlines(it.val))), p.typeOfPrimitive(it)
return p.replaceEscapes(it, p.stripEscapedNewlines(stripFirstNewline(it.val))), p.typeOfPrimitive(it)
case itemRawString:
return it.val, p.typeOfPrimitive(it)
case itemRawMultilineString:
@ -331,11 +339,17 @@ func (p *parser) valueFloat(it item) (interface{}, tomlType) {
var dtTypes = []struct {
fmt string
zone *time.Location
next bool
}{
{time.RFC3339Nano, time.Local},
{"2006-01-02T15:04:05.999999999", internal.LocalDatetime},
{"2006-01-02", internal.LocalDate},
{"15:04:05.999999999", internal.LocalTime},
{time.RFC3339Nano, time.Local, false},
{"2006-01-02T15:04:05.999999999", internal.LocalDatetime, false},
{"2006-01-02", internal.LocalDate, false},
{"15:04:05.999999999", internal.LocalTime, false},
// tomlNext
{"2006-01-02T15:04Z07:00", time.Local, true},
{"2006-01-02T15:04", internal.LocalDatetime, true},
{"15:04", internal.LocalTime, true},
}
func (p *parser) valueDatetime(it item) (interface{}, tomlType) {
@ -346,6 +360,9 @@ func (p *parser) valueDatetime(it item) (interface{}, tomlType) {
err error
)
for _, dt := range dtTypes {
if dt.next && !p.tomlNext {
continue
}
t, err = time.ParseInLocation(dt.fmt, it.val, dt.zone)
if err == nil {
ok = true
@ -384,6 +401,7 @@ func (p *parser) valueArray(it item) (interface{}, tomlType) {
//
// Not entirely sure how to best store this; could use "key[0]",
// "key[1]" notation, or maybe store it on the Array type?
_ = types
}
return array, tomlArray
}
@ -426,11 +444,11 @@ func (p *parser) valueInlineTable(it item, parentIsArray bool) (interface{}, tom
for i := range context {
p.addImplicitContext(append(p.context, context[i:i+1]...))
}
p.ordered = append(p.ordered, p.context.add(p.currentKey))
/// Set the value.
val, typ := p.value(p.next(), false)
p.set(p.currentKey, val, typ, it.pos)
p.ordered = append(p.ordered, p.context.add(p.currentKey))
hash[p.currentKey] = val
/// Restore context.
@ -551,7 +569,6 @@ func (p *parser) addContext(key Key, array bool) {
func (p *parser) set(key string, val interface{}, typ tomlType, pos Position) {
p.setValue(key, val)
p.setType(key, typ, pos)
}
// setValue sets the given key to the given value in the current context.
@ -636,10 +653,7 @@ func (p *parser) addImplicit(key Key) { p.implicits[key.String()] = struct{}
func (p *parser) removeImplicit(key Key) { delete(p.implicits, key.String()) }
func (p *parser) isImplicit(key Key) bool { _, ok := p.implicits[key.String()]; return ok }
func (p *parser) isArray(key Key) bool { return p.keyInfo[key.String()].tomlType == tomlArray }
func (p *parser) addImplicitContext(key Key) {
p.addImplicit(key)
p.addContext(key, false)
}
func (p *parser) addImplicitContext(key Key) { p.addImplicit(key); p.addContext(key, false) }
// current returns the full key name of the current context.
func (p *parser) current() string {
@ -662,50 +676,55 @@ func stripFirstNewline(s string) string {
return s
}
// Remove newlines inside triple-quoted strings if a line ends with "\".
// stripEscapedNewlines removes whitespace after line-ending backslashes in
// multiline strings.
//
// A line-ending backslash is an unescaped \ followed only by whitespace until
// the next newline. After a line-ending backslash, all whitespace is removed
// until the next non-whitespace character.
func (p *parser) stripEscapedNewlines(s string) string {
split := strings.Split(s, "\n")
if len(split) < 1 {
return s
var b strings.Builder
var i int
for {
ix := strings.Index(s[i:], `\`)
if ix < 0 {
b.WriteString(s)
return b.String()
}
i += ix
escNL := false // Keep track of the last non-blank line was escaped.
for i, line := range split {
line = strings.TrimRight(line, " \t\r")
if len(line) == 0 || line[len(line)-1] != '\\' {
split[i] = strings.TrimRight(split[i], "\r")
if !escNL && i != len(split)-1 {
split[i] += "\n"
}
if len(s) > i+1 && s[i+1] == '\\' {
// Escaped backslash.
i += 2
continue
}
escBS := true
for j := len(line) - 1; j >= 0 && line[j] == '\\'; j-- {
escBS = !escBS
// Scan until the next non-whitespace.
j := i + 1
whitespaceLoop:
for ; j < len(s); j++ {
switch s[j] {
case ' ', '\t', '\r', '\n':
default:
break whitespaceLoop
}
if escNL {
line = strings.TrimLeft(line, " \t\r")
}
escNL = !escBS
if escBS {
split[i] += "\n"
if j == i+1 {
// Not a whitespace escape.
i++
continue
}
if i == len(split)-1 {
p.panicf("invalid escape: '\\ '")
if !strings.Contains(s[i:j], "\n") {
// This is not a line-ending backslash.
// (It's a bad escape sequence, but we can let
// replaceEscapes catch it.)
i++
continue
}
split[i] = line[:len(line)-1] // Remove \
if len(split)-1 > i {
split[i+1] = strings.TrimLeft(split[i+1], " \t\r")
b.WriteString(s[:i])
s = s[j:]
i = 0
}
}
return strings.Join(split, "")
}
func (p *parser) replaceEscapes(it item, str string) string {
replaced := make([]rune, 0, len(str))
@ -743,12 +762,23 @@ func (p *parser) replaceEscapes(it item, str string) string {
case 'r':
replaced = append(replaced, rune(0x000D))
r += 1
case 'e':
if p.tomlNext {
replaced = append(replaced, rune(0x001B))
r += 1
}
case '"':
replaced = append(replaced, rune(0x0022))
r += 1
case '\\':
replaced = append(replaced, rune(0x005C))
r += 1
case 'x':
if p.tomlNext {
escaped := p.asciiEscapeToUnicode(it, s[r+1:r+3])
replaced = append(replaced, escaped)
r += 3
}
case 'u':
// At this point, we know we have a Unicode escape of the form
// `uXXXX` at [r, r+5). (Because the lexer guarantees this

View File

@ -8,12 +8,8 @@ linters:
- containedctx # struct contains a context
- dupl # duplicate code
- errname # erorrs are named correctly
- goconst # strings that should be constants
- godot # comments end in a period
- misspell
- nolintlint # "//nolint" directives are properly explained
- revive # golint replacement
- stylecheck # golint replacement, less configurable than revive
- unconvert # unnecessary conversions
- wastedassign
@ -23,10 +19,7 @@ linters:
- exhaustive # check exhaustiveness of enum switch statements
- gofmt # files are gofmt'ed
- gosec # security
- nestif # deeply nested ifs
- nilerr # returns nil even with non-nil error
- prealloc # slices that can be pre-allocated
- structcheck # unused struct fields
- unparam # unused function params
issues:
@ -42,6 +35,18 @@ issues:
text: "^line-length-limit: "
source: "^//(go:generate|sys) "
#TODO: remove after upgrading to go1.18
# ignore comment spacing for nolint and sys directives
- linters:
- revive
text: "^comment-spacings: no space between comment delimiter and comment text"
source: "//(cspell:|nolint:|sys |todo)"
# not on go 1.18 yet, so no any
- linters:
- revive
text: "^use-any: since GO 1.18 'interface{}' can be replaced by 'any'"
# allow unjustified ignores of error checks in defer statements
- linters:
- nolintlint
@ -56,6 +61,8 @@ issues:
linters-settings:
exhaustive:
default-signifies-exhaustive: true
govet:
enable-all: true
disable:
@ -98,6 +105,8 @@ linters-settings:
disabled: true
- name: flag-parameter # excessive, and a common idiom we use
disabled: true
- name: unhandled-error # warns over common fmt.Print* and io.Close; rely on errcheck instead
disabled: true
# general config
- name: line-length-limit
arguments:
@ -138,7 +147,3 @@ linters-settings:
- VPCI
- WCOW
- WIM
stylecheck:
checks:
- "all"
- "-ST1003" # use revive's var naming

View File

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

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

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

View File

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

View File

@ -0,0 +1,64 @@
//go:build windows
// Code generated by 'go generate' using "github.com/Microsoft/go-winio/tools/mkwinsyscall"; DO NOT EDIT.
package fs
import (
"syscall"
"unsafe"
"golang.org/x/sys/windows"
)
var _ unsafe.Pointer
// Do the interface allocations only once for common
// Errno values.
const (
errnoERROR_IO_PENDING = 997
)
var (
errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
errERROR_EINVAL error = syscall.EINVAL
)
// errnoErr returns common boxed Errno values, to prevent
// allocations at runtime.
func errnoErr(e syscall.Errno) error {
switch e {
case 0:
return errERROR_EINVAL
case errnoERROR_IO_PENDING:
return errERROR_IO_PENDING
}
// TODO: add more here, after collecting data on the common
// error values see on Windows. (perhaps when running
// all.bat?)
return e
}
var (
modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
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) {
var _p0 *uint16
_p0, err = syscall.UTF16PtrFromString(name)
if err != nil {
return
}
return _CreateFile(_p0, access, mode, sa, createmode, attrs, templatefile)
}
func _CreateFile(name *uint16, access AccessMask, mode FileShareMode, sa *syscall.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)
handle = windows.Handle(r0)
if handle == windows.InvalidHandle {
err = errnoErr(e1)
}
return
}

View File

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

View File

@ -16,11 +16,12 @@ import (
"unsafe"
"golang.org/x/sys/windows"
"github.com/Microsoft/go-winio/internal/fs"
)
//sys connectNamedPipe(pipe syscall.Handle, o *syscall.Overlapped) (err error) = ConnectNamedPipe
//sys createNamedPipe(name string, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *syscall.SecurityAttributes) (handle syscall.Handle, err error) [failretval==syscall.InvalidHandle] = CreateNamedPipeW
//sys createFile(name string, access uint32, mode uint32, sa *syscall.SecurityAttributes, createmode uint32, attrs uint32, templatefile syscall.Handle) (handle syscall.Handle, err error) [failretval==syscall.InvalidHandle] = CreateFileW
//sys getNamedPipeInfo(pipe syscall.Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error) = GetNamedPipeInfo
//sys getNamedPipeHandleState(pipe syscall.Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) = GetNamedPipeHandleStateW
//sys localAlloc(uFlags uint32, length uint32) (ptr uintptr) = LocalAlloc
@ -163,19 +164,21 @@ func (s pipeAddress) String() string {
}
// tryDialPipe attempts to dial the pipe at `path` until `ctx` cancellation or timeout.
func tryDialPipe(ctx context.Context, path *string, access uint32) (syscall.Handle, error) {
func tryDialPipe(ctx context.Context, path *string, access fs.AccessMask) (syscall.Handle, error) {
for {
select {
case <-ctx.Done():
return syscall.Handle(0), ctx.Err()
default:
h, err := createFile(*path,
wh, err := fs.CreateFile(*path,
access,
0,
nil,
syscall.OPEN_EXISTING,
windows.FILE_FLAG_OVERLAPPED|windows.SECURITY_SQOS_PRESENT|windows.SECURITY_ANONYMOUS,
0)
0, // mode
nil, // security attributes
fs.OPEN_EXISTING,
fs.FILE_FLAG_OVERLAPPED|fs.SECURITY_SQOS_PRESENT|fs.SECURITY_ANONYMOUS,
0, // template file handle
)
h := syscall.Handle(wh)
if err == nil {
return h, nil
}
@ -219,7 +222,7 @@ func DialPipeContext(ctx context.Context, path string) (net.Conn, error) {
func DialPipeAccess(ctx context.Context, path string, access uint32) (net.Conn, error) {
var err error
var h syscall.Handle
h, err = tryDialPipe(ctx, &path, access)
h, err = tryDialPipe(ctx, &path, fs.AccessMask(access))
if err != nil {
return nil, err
}
@ -279,6 +282,7 @@ func makeServerPipeHandle(path string, sd []byte, c *PipeConfig, first bool) (sy
}
defer localFree(ntPath.Buffer)
oa.ObjectName = &ntPath
oa.Attributes = windows.OBJ_CASE_INSENSITIVE
// The security descriptor is only needed for the first pipe.
if first {

View File

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

View File

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

View File

@ -1,72 +0,0 @@
//go:build windows
// Code generated by 'go generate' using "github.com/Microsoft/go-winio/tools/mkwinsyscall"; DO NOT EDIT.
package security
import (
"syscall"
"unsafe"
"golang.org/x/sys/windows"
)
var _ unsafe.Pointer
// Do the interface allocations only once for common
// Errno values.
const (
errnoERROR_IO_PENDING = 997
)
var (
errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
errERROR_EINVAL error = syscall.EINVAL
)
// errnoErr returns common boxed Errno values, to prevent
// allocations at runtime.
func errnoErr(e syscall.Errno) error {
switch e {
case 0:
return errERROR_EINVAL
case errnoERROR_IO_PENDING:
return errERROR_IO_PENDING
}
// TODO: add more here, after collecting data on the common
// error values see on Windows. (perhaps when running
// all.bat?)
return e
}
var (
modadvapi32 = windows.NewLazySystemDLL("advapi32.dll")
procGetSecurityInfo = modadvapi32.NewProc("GetSecurityInfo")
procSetEntriesInAclW = modadvapi32.NewProc("SetEntriesInAclW")
procSetSecurityInfo = modadvapi32.NewProc("SetSecurityInfo")
)
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)
if r0 != 0 {
win32err = syscall.Errno(r0)
}
return
}
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)
if r0 != 0 {
win32err = syscall.Errno(r0)
}
return
}
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)
if r0 != 0 {
win32err = syscall.Errno(r0)
}
return
}

View File

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

View File

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

View File

@ -63,7 +63,6 @@ var (
procBackupWrite = modkernel32.NewProc("BackupWrite")
procCancelIoEx = modkernel32.NewProc("CancelIoEx")
procConnectNamedPipe = modkernel32.NewProc("ConnectNamedPipe")
procCreateFileW = modkernel32.NewProc("CreateFileW")
procCreateIoCompletionPort = modkernel32.NewProc("CreateIoCompletionPort")
procCreateNamedPipeW = modkernel32.NewProc("CreateNamedPipeW")
procGetCurrentThread = modkernel32.NewProc("GetCurrentThread")
@ -305,24 +304,6 @@ func connectNamedPipe(pipe syscall.Handle, o *syscall.Overlapped) (err error) {
return
}
func createFile(name string, access uint32, mode uint32, sa *syscall.SecurityAttributes, createmode uint32, attrs uint32, templatefile syscall.Handle) (handle syscall.Handle, err error) {
var _p0 *uint16
_p0, err = syscall.UTF16PtrFromString(name)
if err != nil {
return
}
return _createFile(_p0, access, mode, sa, createmode, attrs, templatefile)
}
func _createFile(name *uint16, access uint32, mode uint32, sa *syscall.SecurityAttributes, createmode uint32, attrs uint32, templatefile syscall.Handle) (handle syscall.Handle, err error) {
r0, _, e1 := syscall.Syscall9(procCreateFileW.Addr(), 7, uintptr(unsafe.Pointer(name)), uintptr(access), uintptr(mode), uintptr(unsafe.Pointer(sa)), uintptr(createmode), uintptr(attrs), uintptr(templatefile), 0, 0)
handle = syscall.Handle(r0)
if handle == syscall.InvalidHandle {
err = errnoErr(e1)
}
return
}
func createIoCompletionPort(file syscall.Handle, port syscall.Handle, key uintptr, threadCount uint32) (newport syscall.Handle, err error) {
r0, _, e1 := syscall.Syscall6(procCreateIoCompletionPort.Addr(), 4, uintptr(file), uintptr(port), uintptr(key), uintptr(threadCount), 0, 0)
newport = syscall.Handle(r0)

View File

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

View File

@ -1,38 +0,0 @@
# Binaries for programs and plugins
*.exe
*.dll
*.so
*.dylib
# Ignore vscode setting files
.vscode/
# Test binary, build with `go test -c`
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736
.glide/
# Ignore gcs bin directory
service/bin/
service/pkg/
*.img
*.vhd
*.tar.gz
# Make stuff
.rootfs-done
bin/*
rootfs/*
*.o
/build/
deps/*
out/*
.idea/
.vscode/

View File

@ -1,99 +0,0 @@
run:
timeout: 8m
linters:
enable:
- stylecheck
linters-settings:
stylecheck:
# https://staticcheck.io/docs/checks
checks: ["all"]
issues:
# This repo has a LOT of generated schema files, operating system bindings, and other things that ST1003 from stylecheck won't like
# (screaming case Windows api constants for example). There's also some structs that we *could* change the initialisms to be Go
# friendly (Id -> ID) but they're exported and it would be a breaking change. This makes it so that most new code, code that isn't
# supposed to be a pretty faithful mapping to an OS call/constants, or non-generated code still checks if we're following idioms,
# while ignoring the things that are just noise or would be more of a hassle than it'd be worth to change.
exclude-rules:
- path: layer.go
linters:
- stylecheck
Text: "ST1003:"
- path: hcsshim.go
linters:
- stylecheck
Text: "ST1003:"
- path: internal\\hcs\\schema2\\
linters:
- stylecheck
Text: "ST1003:"
- path: internal\\wclayer\\
linters:
- stylecheck
Text: "ST1003:"
- path: hcn\\
linters:
- stylecheck
Text: "ST1003:"
- path: internal\\hcs\\schema1\\
linters:
- stylecheck
Text: "ST1003:"
- path: internal\\hns\\
linters:
- stylecheck
Text: "ST1003:"
- path: ext4\\internal\\compactext4\\
linters:
- stylecheck
Text: "ST1003:"
- path: ext4\\internal\\format\\
linters:
- stylecheck
Text: "ST1003:"
- path: internal\\guestrequest\\
linters:
- stylecheck
Text: "ST1003:"
- path: internal\\guest\\prot\\
linters:
- stylecheck
Text: "ST1003:"
- path: internal\\windevice\\
linters:
- stylecheck
Text: "ST1003:"
- path: internal\\winapi\\
linters:
- stylecheck
Text: "ST1003:"
- path: internal\\vmcompute\\
linters:
- stylecheck
Text: "ST1003:"
- path: internal\\regstate\\
linters:
- stylecheck
Text: "ST1003:"
- path: internal\\hcserror\\
linters:
- stylecheck
Text: "ST1003:"

View File

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

View File

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

View File

@ -1,87 +0,0 @@
BASE:=base.tar.gz
GO:=go
GO_FLAGS:=-ldflags "-s -w" # strip Go binaries
CGO_ENABLED:=0
GOMODVENDOR:=
CFLAGS:=-O2 -Wall
LDFLAGS:=-static -s # strip C binaries
GO_FLAGS_EXTRA:=
ifeq "$(GOMODVENDOR)" "1"
GO_FLAGS_EXTRA += -mod=vendor
endif
GO_BUILD:=CGO_ENABLED=$(CGO_ENABLED) $(GO) build $(GO_FLAGS) $(GO_FLAGS_EXTRA)
SRCROOT=$(dir $(abspath $(firstword $(MAKEFILE_LIST))))
# The link aliases for gcstools
GCS_TOOLS=\
generichook
.PHONY: all always rootfs test
all: out/initrd.img out/rootfs.tar.gz
clean:
find -name '*.o' -print0 | xargs -0 -r rm
rm -rf bin deps rootfs out
test:
cd $(SRCROOT) && go test -v ./internal/guest/...
out/delta.tar.gz: bin/init bin/vsockexec bin/cmd/gcs bin/cmd/gcstools Makefile
@mkdir -p out
rm -rf rootfs
mkdir -p rootfs/bin/
cp bin/init rootfs/
cp bin/vsockexec rootfs/bin/
cp bin/cmd/gcs rootfs/bin/
cp bin/cmd/gcstools rootfs/bin/
for tool in $(GCS_TOOLS); do ln -s gcstools rootfs/bin/$$tool; done
git -C $(SRCROOT) rev-parse HEAD > rootfs/gcs.commit && \
git -C $(SRCROOT) rev-parse --abbrev-ref HEAD > rootfs/gcs.branch
tar -zcf $@ -C rootfs .
rm -rf rootfs
out/rootfs.tar.gz: out/initrd.img
rm -rf rootfs-conv
mkdir rootfs-conv
gunzip -c out/initrd.img | (cd rootfs-conv && cpio -imd)
tar -zcf $@ -C rootfs-conv .
rm -rf rootfs-conv
out/initrd.img: $(BASE) out/delta.tar.gz $(SRCROOT)/hack/catcpio.sh
$(SRCROOT)/hack/catcpio.sh "$(BASE)" out/delta.tar.gz > out/initrd.img.uncompressed
gzip -c out/initrd.img.uncompressed > $@
rm out/initrd.img.uncompressed
-include deps/cmd/gcs.gomake
-include deps/cmd/gcstools.gomake
# Implicit rule for includes that define Go targets.
%.gomake: $(SRCROOT)/Makefile
@mkdir -p $(dir $@)
@/bin/echo $(@:deps/%.gomake=bin/%): $(SRCROOT)/hack/gomakedeps.sh > $@.new
@/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 $@
VPATH=$(SRCROOT)
bin/vsockexec: vsockexec/vsockexec.o vsockexec/vsock.o
@mkdir -p bin
$(CC) $(LDFLAGS) -o $@ $^
bin/init: init/init.o vsockexec/vsock.o
@mkdir -p bin
$(CC) $(LDFLAGS) -o $@ $^
%.o: %.c
@mkdir -p $(dir $@)
$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<

View File

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

View File

@ -1,120 +0,0 @@
# hcsshim
[![Build status](https://github.com/microsoft/hcsshim/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/microsoft/hcsshim/actions?query=branch%3Amaster)
This package contains the Golang interface for using the Windows [Host Compute Service](https://techcommunity.microsoft.com/t5/containers/introducing-the-host-compute-service-hcs/ba-p/382332) (HCS) to launch and manage [Windows Containers](https://docs.microsoft.com/en-us/virtualization/windowscontainers/about/). It also contains other helpers and functions for managing Windows Containers such as the Golang interface for the Host Network Service (HNS), as well as code for the [guest agent](./internal/guest/README.md) (commonly referred to as the GCS or Guest Compute Service in the codebase) used to support running Linux Hyper-V containers.
It is primarily used in the [Moby](https://github.com/moby/moby) and [Containerd](https://github.com/containerd/containerd) projects, but it can be freely used by other projects as well.
## Building
While this repository can be used as a library of sorts to call the HCS apis, there are a couple binaries built out of the repository as well. The main ones being the Linux guest agent, and an implementation of the [runtime v2 containerd shim api](https://github.com/containerd/containerd/blob/master/runtime/v2/README.md).
### Linux Hyper-V Container Guest Agent
To build the Linux guest agent itself all that's needed is to set your GOOS to "Linux" and build out of ./cmd/gcs.
```powershell
C:\> $env:GOOS="linux"
C:\> go build .\cmd\gcs\
```
or on a Linux machine
```sh
> go build ./cmd/gcs
```
If you want it to be packaged inside of a rootfs to boot with alongside all of the other tools then you'll need to provide a rootfs that it can be packaged inside of. An easy way is to export the rootfs of a container.
```sh
docker pull busybox
docker run --name base_image_container busybox
docker export base_image_container | gzip > base.tar.gz
BASE=./base.tar.gz
make all
```
If the build is successful, in the `./out` folder you should see:
```sh
> ls ./out/
delta.tar.gz initrd.img rootfs.tar.gz
```
### Containerd Shim
For info on the Runtime V2 API: https://github.com/containerd/containerd/blob/master/runtime/v2/README.md.
Contrary to the typical Linux architecture of shim -> runc, the runhcs shim is used both to launch and manage the lifetime of containers.
```powershell
C:\> $env:GOOS="windows"
C:\> go build .\cmd\containerd-shim-runhcs-v1
```
Then place the binary in the same directory that Containerd is located at in your environment. A default Containerd configuration file can be generated by running:
```powershell
.\containerd.exe config default | Out-File "C:\Program Files\containerd\config.toml" -Encoding ascii
```
This config file will already have the shim set as the default runtime for cri interactions.
To trial using the shim out with ctr.exe:
```powershell
C:\> ctr.exe run --runtime io.containerd.runhcs.v1 --rm mcr.microsoft.com/windows/nanoserver:2004 windows-test cmd /c "echo Hello World!"
```
## Contributing
This project welcomes contributions and suggestions. Most contributions require you to agree to a
Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
the rights to use your contribution. For details, visit https://cla.microsoft.com.
When you submit a pull request, a CLA-bot will automatically determine whether you need to provide
a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions
provided by the bot. You will only need to do this once across all repos using our CLA.
We also require that contributors [sign their commits](https://git-scm.com/docs/git-commit) using `git commit -s` or `git commit --signoff` to
certify they either authored the work themselves or otherwise have permission to use it in this project. Please see https://developercertificate.org/ for
more info, as well as to make sure that you can attest to the rules listed. Our CI uses the [DCO Github app](https://github.com/apps/dco) to ensure
that all commits in a given PR are signed-off.
### Test Directory (Important to note)
This project has tried to trim some dependencies from the root Go modules file that would be cumbersome to get transitively included if this
project is being vendored/used as a library. Some of these dependencies were only being used for tests, so the /test directory in this project also has
its own go.mod file where these are now included to get around this issue. Our tests rely on the code in this project to run, so the test Go modules file
has a relative path replace directive to pull in the latest hcsshim code that the tests actually touch from this project
(which is the repo itself on your disk).
```
replace (
github.com/Microsoft/hcsshim => ../
)
```
Because of this, for most code changes you may need to run `go mod vendor` + `go mod tidy` in the /test directory in this repository, as the
CI in this project will check if the files are out of date and will fail if this is true.
## Code of Conduct
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
## Dependencies
This project requires Golang 1.9 or newer to build.
For system requirements to run this project, see the Microsoft docs on [Windows Container requirements](https://docs.microsoft.com/en-us/virtualization/windowscontainers/deploy-containers/system-requirements).
## Reporting Security Issues
Security issues and bugs should be reported privately, via email, to the Microsoft Security
Response Center (MSRC) at [secure@microsoft.com](mailto:secure@microsoft.com). You should
receive a response within 24 hours. If for some reason you do not, please follow up via
email to ensure we received your original message. Further information, including the
[MSRC PGP](https://technet.microsoft.com/en-us/security/dn606155) key, can be found in
the [Security TechCenter](https://technet.microsoft.com/en-us/security/default).
For additional details, see [Report a Computer Security Vulnerability](https://technet.microsoft.com/en-us/security/ff852094.aspx) on Technet
---------------
Copyright (c) 2018 Microsoft Corp. All rights reserved.

View File

@ -1,38 +0,0 @@
package computestorage
import (
"context"
"encoding/json"
"github.com/Microsoft/hcsshim/internal/oc"
"github.com/pkg/errors"
"go.opencensus.io/trace"
)
// AttachLayerStorageFilter sets up the layer storage filter on a writable
// container layer.
//
// `layerPath` is a path to a directory the writable layer is mounted. If the
// path does not end in a `\` the platform will append it automatically.
//
// `layerData` is the parent read-only layer data.
func AttachLayerStorageFilter(ctx context.Context, layerPath string, layerData LayerData) (err error) {
title := "hcsshim.AttachLayerStorageFilter"
ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
defer span.End()
defer func() { oc.SetSpanStatus(span, err) }()
span.AddAttributes(
trace.StringAttribute("layerPath", layerPath),
)
bytes, err := json.Marshal(layerData)
if err != nil {
return err
}
err = hcsAttachLayerStorageFilter(layerPath, string(bytes))
if err != nil {
return errors.Wrap(err, "failed to attach layer storage filter")
}
return nil
}

View File

@ -1,26 +0,0 @@
package computestorage
import (
"context"
"github.com/Microsoft/hcsshim/internal/oc"
"github.com/pkg/errors"
"go.opencensus.io/trace"
)
// DestroyLayer deletes a container layer.
//
// `layerPath` is a path to a directory containing the layer to export.
func DestroyLayer(ctx context.Context, layerPath string) (err error) {
title := "hcsshim.DestroyLayer"
ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
defer span.End()
defer func() { oc.SetSpanStatus(span, err) }()
span.AddAttributes(trace.StringAttribute("layerPath", layerPath))
err = hcsDestroyLayer(layerPath)
if err != nil {
return errors.Wrap(err, "failed to destroy layer")
}
return nil
}

View File

@ -1,26 +0,0 @@
package computestorage
import (
"context"
"github.com/Microsoft/hcsshim/internal/oc"
"github.com/pkg/errors"
"go.opencensus.io/trace"
)
// DetachLayerStorageFilter detaches the layer storage filter on a writable container layer.
//
// `layerPath` is a path to a directory containing the layer to export.
func DetachLayerStorageFilter(ctx context.Context, layerPath string) (err error) {
title := "hcsshim.DetachLayerStorageFilter"
ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
defer span.End()
defer func() { oc.SetSpanStatus(span, err) }()
span.AddAttributes(trace.StringAttribute("layerPath", layerPath))
err = hcsDetachLayerStorageFilter(layerPath)
if err != nil {
return errors.Wrap(err, "failed to detach layer storage filter")
}
return nil
}

View File

@ -1,46 +0,0 @@
package computestorage
import (
"context"
"encoding/json"
"github.com/Microsoft/hcsshim/internal/oc"
"github.com/pkg/errors"
"go.opencensus.io/trace"
)
// ExportLayer exports a container layer.
//
// `layerPath` is a path to a directory containing the layer to export.
//
// `exportFolderPath` is a pre-existing folder to export the layer to.
//
// `layerData` is the parent layer data.
//
// `options` are the export options applied to the exported layer.
func ExportLayer(ctx context.Context, layerPath, exportFolderPath string, layerData LayerData, options ExportLayerOptions) (err error) {
title := "hcsshim.ExportLayer"
ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
defer span.End()
defer func() { oc.SetSpanStatus(span, err) }()
span.AddAttributes(
trace.StringAttribute("layerPath", layerPath),
trace.StringAttribute("exportFolderPath", exportFolderPath),
)
ldbytes, err := json.Marshal(layerData)
if err != nil {
return err
}
obytes, err := json.Marshal(options)
if err != nil {
return err
}
err = hcsExportLayer(layerPath, exportFolderPath, string(ldbytes), string(obytes))
if err != nil {
return errors.Wrap(err, "failed to export layer")
}
return nil
}

View File

@ -1,26 +0,0 @@
package computestorage
import (
"context"
"github.com/Microsoft/hcsshim/internal/oc"
"github.com/pkg/errors"
"go.opencensus.io/trace"
"golang.org/x/sys/windows"
)
// FormatWritableLayerVhd formats a virtual disk for use as a writable container layer.
//
// If the VHD is not mounted it will be temporarily mounted.
func FormatWritableLayerVhd(ctx context.Context, vhdHandle windows.Handle) (err error) {
title := "hcsshim.FormatWritableLayerVhd"
ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
defer span.End()
defer func() { oc.SetSpanStatus(span, err) }()
err = hcsFormatWritableLayerVhd(vhdHandle)
if err != nil {
return errors.Wrap(err, "failed to format writable layer vhd")
}
return nil
}

View File

@ -1,193 +0,0 @@
package computestorage
import (
"context"
"os"
"path/filepath"
"syscall"
"github.com/Microsoft/go-winio/pkg/security"
"github.com/Microsoft/go-winio/vhd"
"github.com/pkg/errors"
"golang.org/x/sys/windows"
)
const defaultVHDXBlockSizeInMB = 1
// SetupContainerBaseLayer is a helper to setup a containers scratch. It
// will create and format the vhdx's inside and the size is configurable with the sizeInGB
// parameter.
//
// `layerPath` is the path to the base container layer on disk.
//
// `baseVhdPath` is the path to where the base vhdx for the base layer should be created.
//
// `diffVhdPath` is the path where the differencing disk for the base layer should be created.
//
// `sizeInGB` is the size in gigabytes to make the base vhdx.
func SetupContainerBaseLayer(ctx context.Context, layerPath, baseVhdPath, diffVhdPath string, sizeInGB uint64) (err error) {
var (
hivesPath = filepath.Join(layerPath, "Hives")
layoutPath = filepath.Join(layerPath, "Layout")
)
// We need to remove the hives directory and layout file as `SetupBaseOSLayer` fails if these files
// already exist. `SetupBaseOSLayer` will create these files internally. We also remove the base and
// differencing disks if they exist in case we're asking for a different size.
if _, err := os.Stat(hivesPath); err == nil {
if err := os.RemoveAll(hivesPath); err != nil {
return errors.Wrap(err, "failed to remove prexisting hives directory")
}
}
if _, err := os.Stat(layoutPath); err == nil {
if err := os.RemoveAll(layoutPath); err != nil {
return errors.Wrap(err, "failed to remove prexisting layout file")
}
}
if _, err := os.Stat(baseVhdPath); err == nil {
if err := os.RemoveAll(baseVhdPath); err != nil {
return errors.Wrap(err, "failed to remove base vhdx path")
}
}
if _, err := os.Stat(diffVhdPath); err == nil {
if err := os.RemoveAll(diffVhdPath); err != nil {
return errors.Wrap(err, "failed to remove differencing vhdx")
}
}
createParams := &vhd.CreateVirtualDiskParameters{
Version: 2,
Version2: vhd.CreateVersion2{
MaximumSize: sizeInGB * 1024 * 1024 * 1024,
BlockSizeInBytes: defaultVHDXBlockSizeInMB * 1024 * 1024,
},
}
handle, err := vhd.CreateVirtualDisk(baseVhdPath, vhd.VirtualDiskAccessNone, vhd.CreateVirtualDiskFlagNone, createParams)
if err != nil {
return errors.Wrap(err, "failed to create vhdx")
}
defer func() {
if err != nil {
_ = syscall.CloseHandle(handle)
os.RemoveAll(baseVhdPath)
os.RemoveAll(diffVhdPath)
}
}()
if err = FormatWritableLayerVhd(ctx, windows.Handle(handle)); err != nil {
return err
}
// Base vhd handle must be closed before calling SetupBaseLayer in case of Container layer
if err = syscall.CloseHandle(handle); err != nil {
return errors.Wrap(err, "failed to close vhdx handle")
}
options := OsLayerOptions{
Type: OsLayerTypeContainer,
}
// SetupBaseOSLayer expects an empty vhd handle for a container layer and will
// error out otherwise.
if err = SetupBaseOSLayer(ctx, layerPath, 0, options); err != nil {
return err
}
// Create the differencing disk that will be what's copied for the final rw layer
// for a container.
if err = vhd.CreateDiffVhd(diffVhdPath, baseVhdPath, defaultVHDXBlockSizeInMB); err != nil {
return errors.Wrap(err, "failed to create differencing disk")
}
if err = security.GrantVmGroupAccess(baseVhdPath); err != nil {
return errors.Wrapf(err, "failed to grant vm group access to %s", baseVhdPath)
}
if err = security.GrantVmGroupAccess(diffVhdPath); err != nil {
return errors.Wrapf(err, "failed to grant vm group access to %s", diffVhdPath)
}
return nil
}
// SetupUtilityVMBaseLayer is a helper to setup a UVMs scratch space. It will create and format
// the vhdx inside and the size is configurable by the sizeInGB parameter.
//
// `uvmPath` is the path to the UtilityVM filesystem.
//
// `baseVhdPath` is the path to where the base vhdx for the UVM should be created.
//
// `diffVhdPath` is the path where the differencing disk for the UVM should be created.
//
// `sizeInGB` specifies the size in gigabytes to make the base vhdx.
func SetupUtilityVMBaseLayer(ctx context.Context, uvmPath, baseVhdPath, diffVhdPath string, sizeInGB uint64) (err error) {
// Remove the base and differencing disks if they exist in case we're asking for a different size.
if _, err := os.Stat(baseVhdPath); err == nil {
if err := os.RemoveAll(baseVhdPath); err != nil {
return errors.Wrap(err, "failed to remove base vhdx")
}
}
if _, err := os.Stat(diffVhdPath); err == nil {
if err := os.RemoveAll(diffVhdPath); err != nil {
return errors.Wrap(err, "failed to remove differencing vhdx")
}
}
// Just create the vhdx for utilityVM layer, no need to format it.
createParams := &vhd.CreateVirtualDiskParameters{
Version: 2,
Version2: vhd.CreateVersion2{
MaximumSize: sizeInGB * 1024 * 1024 * 1024,
BlockSizeInBytes: defaultVHDXBlockSizeInMB * 1024 * 1024,
},
}
handle, err := vhd.CreateVirtualDisk(baseVhdPath, vhd.VirtualDiskAccessNone, vhd.CreateVirtualDiskFlagNone, createParams)
if err != nil {
return errors.Wrap(err, "failed to create vhdx")
}
defer func() {
if err != nil {
_ = syscall.CloseHandle(handle)
os.RemoveAll(baseVhdPath)
os.RemoveAll(diffVhdPath)
}
}()
// If it is a UtilityVM layer then the base vhdx must be attached when calling
// `SetupBaseOSLayer`
attachParams := &vhd.AttachVirtualDiskParameters{
Version: 2,
}
if err := vhd.AttachVirtualDisk(handle, vhd.AttachVirtualDiskFlagNone, attachParams); err != nil {
return errors.Wrapf(err, "failed to attach virtual disk")
}
options := OsLayerOptions{
Type: OsLayerTypeVM,
}
if err := SetupBaseOSLayer(ctx, uvmPath, windows.Handle(handle), options); err != nil {
return err
}
// Detach and close the handle after setting up the layer as we don't need the handle
// for anything else and we no longer need to be attached either.
if err = vhd.DetachVirtualDisk(handle); err != nil {
return errors.Wrap(err, "failed to detach vhdx")
}
if err = syscall.CloseHandle(handle); err != nil {
return errors.Wrap(err, "failed to close vhdx handle")
}
// Create the differencing disk that will be what's copied for the final rw layer
// for a container.
if err = vhd.CreateDiffVhd(diffVhdPath, baseVhdPath, defaultVHDXBlockSizeInMB); err != nil {
return errors.Wrap(err, "failed to create differencing disk")
}
if err := security.GrantVmGroupAccess(baseVhdPath); err != nil {
return errors.Wrapf(err, "failed to grant vm group access to %s", baseVhdPath)
}
if err := security.GrantVmGroupAccess(diffVhdPath); err != nil {
return errors.Wrapf(err, "failed to grant vm group access to %s", diffVhdPath)
}
return nil
}

View File

@ -1,41 +0,0 @@
package computestorage
import (
"context"
"encoding/json"
"github.com/Microsoft/hcsshim/internal/oc"
"github.com/pkg/errors"
"go.opencensus.io/trace"
)
// ImportLayer imports a container layer.
//
// `layerPath` is a path to a directory to import the layer to. If the directory
// does not exist it will be automatically created.
//
// `sourceFolderpath` is a pre-existing folder that contains the layer to
// import.
//
// `layerData` is the parent layer data.
func ImportLayer(ctx context.Context, layerPath, sourceFolderPath string, layerData LayerData) (err error) {
title := "hcsshim.ImportLayer"
ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
defer span.End()
defer func() { oc.SetSpanStatus(span, err) }()
span.AddAttributes(
trace.StringAttribute("layerPath", layerPath),
trace.StringAttribute("sourceFolderPath", sourceFolderPath),
)
bytes, err := json.Marshal(layerData)
if err != nil {
return err
}
err = hcsImportLayer(layerPath, sourceFolderPath, string(bytes))
if err != nil {
return errors.Wrap(err, "failed to import layer")
}
return nil
}

View File

@ -1,38 +0,0 @@
package computestorage
import (
"context"
"encoding/json"
"github.com/Microsoft/hcsshim/internal/oc"
"github.com/pkg/errors"
"go.opencensus.io/trace"
)
// InitializeWritableLayer initializes a writable layer for a container.
//
// `layerPath` is a path to a directory the layer is mounted. If the
// path does not end in a `\` the platform will append it automatically.
//
// `layerData` is the parent read-only layer data.
func InitializeWritableLayer(ctx context.Context, layerPath string, layerData LayerData) (err error) {
title := "hcsshim.InitializeWritableLayer"
ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
defer span.End()
defer func() { oc.SetSpanStatus(span, err) }()
span.AddAttributes(
trace.StringAttribute("layerPath", layerPath),
)
bytes, err := json.Marshal(layerData)
if err != nil {
return err
}
// Options are not used in the platform as of RS5
err = hcsInitializeWritableLayer(layerPath, string(bytes), "")
if err != nil {
return errors.Wrap(err, "failed to intitialize container layer")
}
return nil
}

View File

@ -1,27 +0,0 @@
package computestorage
import (
"context"
"github.com/Microsoft/hcsshim/internal/interop"
"github.com/Microsoft/hcsshim/internal/oc"
"github.com/pkg/errors"
"go.opencensus.io/trace"
"golang.org/x/sys/windows"
)
// GetLayerVhdMountPath returns the volume path for a virtual disk of a writable container layer.
func GetLayerVhdMountPath(ctx context.Context, vhdHandle windows.Handle) (path string, err error) {
title := "hcsshim.GetLayerVhdMountPath"
ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
defer span.End()
defer func() { oc.SetSpanStatus(span, err) }()
var mountPath *uint16
err = hcsGetLayerVhdMountPath(vhdHandle, &mountPath)
if err != nil {
return "", errors.Wrap(err, "failed to get vhd mount path")
}
path = interop.ConvertAndFreeCoTaskMemString(mountPath)
return path, nil
}

View File

@ -1,74 +0,0 @@
package computestorage
import (
"context"
"encoding/json"
"github.com/Microsoft/hcsshim/internal/oc"
"github.com/Microsoft/hcsshim/osversion"
"github.com/pkg/errors"
"go.opencensus.io/trace"
"golang.org/x/sys/windows"
)
// SetupBaseOSLayer sets up a layer that contains a base OS for a container.
//
// `layerPath` is a path to a directory containing the layer.
//
// `vhdHandle` is an empty file handle of `options.Type == OsLayerTypeContainer`
// or else it is a file handle to the 'SystemTemplateBase.vhdx' if `options.Type
// == OsLayerTypeVm`.
//
// `options` are the options applied while processing the layer.
func SetupBaseOSLayer(ctx context.Context, layerPath string, vhdHandle windows.Handle, options OsLayerOptions) (err error) {
title := "hcsshim.SetupBaseOSLayer"
ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
defer span.End()
defer func() { oc.SetSpanStatus(span, err) }()
span.AddAttributes(
trace.StringAttribute("layerPath", layerPath),
)
bytes, err := json.Marshal(options)
if err != nil {
return err
}
err = hcsSetupBaseOSLayer(layerPath, vhdHandle, string(bytes))
if err != nil {
return errors.Wrap(err, "failed to setup base OS layer")
}
return nil
}
// SetupBaseOSVolume sets up a volume that contains a base OS for a container.
//
// `layerPath` is a path to a directory containing the layer.
//
// `volumePath` is the path to the volume to be used for setup.
//
// `options` are the options applied while processing the layer.
func SetupBaseOSVolume(ctx context.Context, layerPath, volumePath string, options OsLayerOptions) (err error) {
if osversion.Build() < 19645 {
return errors.New("SetupBaseOSVolume is not present on builds older than 19645")
}
title := "hcsshim.SetupBaseOSVolume"
ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
defer span.End()
defer func() { oc.SetSpanStatus(span, err) }()
span.AddAttributes(
trace.StringAttribute("layerPath", layerPath),
trace.StringAttribute("volumePath", volumePath),
)
bytes, err := json.Marshal(options)
if err != nil {
return err
}
err = hcsSetupBaseOSVolume(layerPath, volumePath, string(bytes))
if err != nil {
return errors.Wrap(err, "failed to setup base OS layer")
}
return nil
}

View File

@ -1,50 +0,0 @@
// Package computestorage is a wrapper around the HCS storage APIs. These are new storage APIs introduced
// separate from the original graphdriver calls intended to give more freedom around creating
// and managing container layers and scratch spaces.
package computestorage
import (
hcsschema "github.com/Microsoft/hcsshim/internal/hcs/schema2"
)
//go:generate go run ../mksyscall_windows.go -output zsyscall_windows.go storage.go
//sys hcsImportLayer(layerPath string, sourceFolderPath string, layerData string) (hr error) = computestorage.HcsImportLayer?
//sys hcsExportLayer(layerPath string, exportFolderPath string, layerData string, options string) (hr error) = computestorage.HcsExportLayer?
//sys hcsDestroyLayer(layerPath string) (hr error) = computestorage.HcsDestoryLayer?
//sys hcsSetupBaseOSLayer(layerPath string, handle windows.Handle, options string) (hr error) = computestorage.HcsSetupBaseOSLayer?
//sys hcsInitializeWritableLayer(writableLayerPath string, layerData string, options string) (hr error) = computestorage.HcsInitializeWritableLayer?
//sys hcsAttachLayerStorageFilter(layerPath string, layerData string) (hr error) = computestorage.HcsAttachLayerStorageFilter?
//sys hcsDetachLayerStorageFilter(layerPath string) (hr error) = computestorage.HcsDetachLayerStorageFilter?
//sys hcsFormatWritableLayerVhd(handle windows.Handle) (hr error) = computestorage.HcsFormatWritableLayerVhd?
//sys hcsGetLayerVhdMountPath(vhdHandle windows.Handle, mountPath **uint16) (hr error) = computestorage.HcsGetLayerVhdMountPath?
//sys hcsSetupBaseOSVolume(layerPath string, volumePath string, options string) (hr error) = computestorage.HcsSetupBaseOSVolume?
// LayerData is the data used to describe parent layer information.
type LayerData struct {
SchemaVersion hcsschema.Version `json:"SchemaVersion,omitempty"`
Layers []hcsschema.Layer `json:"Layers,omitempty"`
}
// ExportLayerOptions are the set of options that are used with the `computestorage.HcsExportLayer` syscall.
type ExportLayerOptions struct {
IsWritableLayer bool `json:"IsWritableLayer,omitempty"`
}
// OsLayerType is the type of layer being operated on.
type OsLayerType string
const (
// OsLayerTypeContainer is a container layer.
OsLayerTypeContainer OsLayerType = "Container"
// OsLayerTypeVM is a virtual machine layer.
OsLayerTypeVM OsLayerType = "Vm"
)
// OsLayerOptions are the set of options that are used with the `SetupBaseOSLayer` and
// `SetupBaseOSVolume` calls.
type OsLayerOptions struct {
Type OsLayerType `json:"Type,omitempty"`
DisableCiCacheOptimization bool `json:"DisableCiCacheOptimization,omitempty"`
SkipUpdateBcdForBoot bool `json:"SkipUpdateBcdForBoot,omitempty"`
}

View File

@ -1,319 +0,0 @@
// Code generated mksyscall_windows.exe DO NOT EDIT
package computestorage
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)
)
// errnoErr returns common boxed Errno values, to prevent
// allocations at runtime.
func errnoErr(e syscall.Errno) error {
switch e {
case 0:
return nil
case errnoERROR_IO_PENDING:
return errERROR_IO_PENDING
}
// TODO: add more here, after collecting data on the common
// error values see on Windows. (perhaps when running
// all.bat?)
return e
}
var (
modcomputestorage = windows.NewLazySystemDLL("computestorage.dll")
procHcsImportLayer = modcomputestorage.NewProc("HcsImportLayer")
procHcsExportLayer = modcomputestorage.NewProc("HcsExportLayer")
procHcsDestoryLayer = modcomputestorage.NewProc("HcsDestoryLayer")
procHcsSetupBaseOSLayer = modcomputestorage.NewProc("HcsSetupBaseOSLayer")
procHcsInitializeWritableLayer = modcomputestorage.NewProc("HcsInitializeWritableLayer")
procHcsAttachLayerStorageFilter = modcomputestorage.NewProc("HcsAttachLayerStorageFilter")
procHcsDetachLayerStorageFilter = modcomputestorage.NewProc("HcsDetachLayerStorageFilter")
procHcsFormatWritableLayerVhd = modcomputestorage.NewProc("HcsFormatWritableLayerVhd")
procHcsGetLayerVhdMountPath = modcomputestorage.NewProc("HcsGetLayerVhdMountPath")
procHcsSetupBaseOSVolume = modcomputestorage.NewProc("HcsSetupBaseOSVolume")
)
func hcsImportLayer(layerPath string, sourceFolderPath string, layerData string) (hr error) {
var _p0 *uint16
_p0, hr = syscall.UTF16PtrFromString(layerPath)
if hr != nil {
return
}
var _p1 *uint16
_p1, hr = syscall.UTF16PtrFromString(sourceFolderPath)
if hr != nil {
return
}
var _p2 *uint16
_p2, hr = syscall.UTF16PtrFromString(layerData)
if hr != nil {
return
}
return _hcsImportLayer(_p0, _p1, _p2)
}
func _hcsImportLayer(layerPath *uint16, sourceFolderPath *uint16, layerData *uint16) (hr error) {
if hr = procHcsImportLayer.Find(); hr != nil {
return
}
r0, _, _ := syscall.Syscall(procHcsImportLayer.Addr(), 3, uintptr(unsafe.Pointer(layerPath)), uintptr(unsafe.Pointer(sourceFolderPath)), uintptr(unsafe.Pointer(layerData)))
if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
}
return
}
func hcsExportLayer(layerPath string, exportFolderPath string, layerData string, options string) (hr error) {
var _p0 *uint16
_p0, hr = syscall.UTF16PtrFromString(layerPath)
if hr != nil {
return
}
var _p1 *uint16
_p1, hr = syscall.UTF16PtrFromString(exportFolderPath)
if hr != nil {
return
}
var _p2 *uint16
_p2, hr = syscall.UTF16PtrFromString(layerData)
if hr != nil {
return
}
var _p3 *uint16
_p3, hr = syscall.UTF16PtrFromString(options)
if hr != nil {
return
}
return _hcsExportLayer(_p0, _p1, _p2, _p3)
}
func _hcsExportLayer(layerPath *uint16, exportFolderPath *uint16, layerData *uint16, options *uint16) (hr error) {
if hr = procHcsExportLayer.Find(); hr != nil {
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)
if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
}
return
}
func hcsDestroyLayer(layerPath string) (hr error) {
var _p0 *uint16
_p0, hr = syscall.UTF16PtrFromString(layerPath)
if hr != nil {
return
}
return _hcsDestroyLayer(_p0)
}
func _hcsDestroyLayer(layerPath *uint16) (hr error) {
if hr = procHcsDestoryLayer.Find(); hr != nil {
return
}
r0, _, _ := syscall.Syscall(procHcsDestoryLayer.Addr(), 1, uintptr(unsafe.Pointer(layerPath)), 0, 0)
if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
}
return
}
func hcsSetupBaseOSLayer(layerPath string, handle windows.Handle, options string) (hr error) {
var _p0 *uint16
_p0, hr = syscall.UTF16PtrFromString(layerPath)
if hr != nil {
return
}
var _p1 *uint16
_p1, hr = syscall.UTF16PtrFromString(options)
if hr != nil {
return
}
return _hcsSetupBaseOSLayer(_p0, handle, _p1)
}
func _hcsSetupBaseOSLayer(layerPath *uint16, handle windows.Handle, options *uint16) (hr error) {
if hr = procHcsSetupBaseOSLayer.Find(); hr != nil {
return
}
r0, _, _ := syscall.Syscall(procHcsSetupBaseOSLayer.Addr(), 3, uintptr(unsafe.Pointer(layerPath)), uintptr(handle), uintptr(unsafe.Pointer(options)))
if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
}
return
}
func hcsInitializeWritableLayer(writableLayerPath string, layerData string, options string) (hr error) {
var _p0 *uint16
_p0, hr = syscall.UTF16PtrFromString(writableLayerPath)
if hr != nil {
return
}
var _p1 *uint16
_p1, hr = syscall.UTF16PtrFromString(layerData)
if hr != nil {
return
}
var _p2 *uint16
_p2, hr = syscall.UTF16PtrFromString(options)
if hr != nil {
return
}
return _hcsInitializeWritableLayer(_p0, _p1, _p2)
}
func _hcsInitializeWritableLayer(writableLayerPath *uint16, layerData *uint16, options *uint16) (hr error) {
if hr = procHcsInitializeWritableLayer.Find(); hr != nil {
return
}
r0, _, _ := syscall.Syscall(procHcsInitializeWritableLayer.Addr(), 3, uintptr(unsafe.Pointer(writableLayerPath)), uintptr(unsafe.Pointer(layerData)), uintptr(unsafe.Pointer(options)))
if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
}
return
}
func hcsAttachLayerStorageFilter(layerPath string, layerData string) (hr error) {
var _p0 *uint16
_p0, hr = syscall.UTF16PtrFromString(layerPath)
if hr != nil {
return
}
var _p1 *uint16
_p1, hr = syscall.UTF16PtrFromString(layerData)
if hr != nil {
return
}
return _hcsAttachLayerStorageFilter(_p0, _p1)
}
func _hcsAttachLayerStorageFilter(layerPath *uint16, layerData *uint16) (hr error) {
if hr = procHcsAttachLayerStorageFilter.Find(); hr != nil {
return
}
r0, _, _ := syscall.Syscall(procHcsAttachLayerStorageFilter.Addr(), 2, uintptr(unsafe.Pointer(layerPath)), uintptr(unsafe.Pointer(layerData)), 0)
if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
}
return
}
func hcsDetachLayerStorageFilter(layerPath string) (hr error) {
var _p0 *uint16
_p0, hr = syscall.UTF16PtrFromString(layerPath)
if hr != nil {
return
}
return _hcsDetachLayerStorageFilter(_p0)
}
func _hcsDetachLayerStorageFilter(layerPath *uint16) (hr error) {
if hr = procHcsDetachLayerStorageFilter.Find(); hr != nil {
return
}
r0, _, _ := syscall.Syscall(procHcsDetachLayerStorageFilter.Addr(), 1, uintptr(unsafe.Pointer(layerPath)), 0, 0)
if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
}
return
}
func hcsFormatWritableLayerVhd(handle windows.Handle) (hr error) {
if hr = procHcsFormatWritableLayerVhd.Find(); hr != nil {
return
}
r0, _, _ := syscall.Syscall(procHcsFormatWritableLayerVhd.Addr(), 1, uintptr(handle), 0, 0)
if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
}
return
}
func hcsGetLayerVhdMountPath(vhdHandle windows.Handle, mountPath **uint16) (hr error) {
if hr = procHcsGetLayerVhdMountPath.Find(); hr != nil {
return
}
r0, _, _ := syscall.Syscall(procHcsGetLayerVhdMountPath.Addr(), 2, uintptr(vhdHandle), uintptr(unsafe.Pointer(mountPath)), 0)
if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
}
return
}
func hcsSetupBaseOSVolume(layerPath string, volumePath string, options string) (hr error) {
var _p0 *uint16
_p0, hr = syscall.UTF16PtrFromString(layerPath)
if hr != nil {
return
}
var _p1 *uint16
_p1, hr = syscall.UTF16PtrFromString(volumePath)
if hr != nil {
return
}
var _p2 *uint16
_p2, hr = syscall.UTF16PtrFromString(options)
if hr != nil {
return
}
return _hcsSetupBaseOSVolume(_p0, _p1, _p2)
}
func _hcsSetupBaseOSVolume(layerPath *uint16, volumePath *uint16, options *uint16) (hr error) {
if hr = procHcsSetupBaseOSVolume.Find(); hr != nil {
return
}
r0, _, _ := syscall.Syscall(procHcsSetupBaseOSVolume.Addr(), 3, uintptr(unsafe.Pointer(layerPath)), uintptr(unsafe.Pointer(volumePath)), uintptr(unsafe.Pointer(options)))
if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
}
return
}

View File

@ -1,223 +0,0 @@
package hcsshim
import (
"context"
"fmt"
"os"
"sync"
"time"
"github.com/Microsoft/hcsshim/internal/hcs"
"github.com/Microsoft/hcsshim/internal/hcs/schema1"
"github.com/Microsoft/hcsshim/internal/mergemaps"
)
// ContainerProperties holds the properties for a container and the processes running in that container
type ContainerProperties = schema1.ContainerProperties
// MemoryStats holds the memory statistics for a container
type MemoryStats = schema1.MemoryStats
// ProcessorStats holds the processor statistics for a container
type ProcessorStats = schema1.ProcessorStats
// StorageStats holds the storage statistics for a container
type StorageStats = schema1.StorageStats
// NetworkStats holds the network statistics for a container
type NetworkStats = schema1.NetworkStats
// Statistics is the structure returned by a statistics call on a container
type Statistics = schema1.Statistics
// ProcessList is the structure of an item returned by a ProcessList call on a container
type ProcessListItem = schema1.ProcessListItem
// MappedVirtualDiskController is the structure of an item returned by a MappedVirtualDiskList call on a container
type MappedVirtualDiskController = schema1.MappedVirtualDiskController
// Type of Request Support in ModifySystem
type RequestType = schema1.RequestType
// Type of Resource Support in ModifySystem
type ResourceType = schema1.ResourceType
// RequestType const
const (
Add = schema1.Add
Remove = schema1.Remove
Network = schema1.Network
)
// ResourceModificationRequestResponse is the structure used to send request to the container to modify the system
// Supported resource types are Network and Request Types are Add/Remove
type ResourceModificationRequestResponse = schema1.ResourceModificationRequestResponse
type container struct {
system *hcs.System
waitOnce sync.Once
waitErr error
waitCh chan struct{}
}
// createComputeSystemAdditionalJSON is read from the environment at initialisation
// time. It allows an environment variable to define additional JSON which
// is merged in the CreateComputeSystem call to HCS.
var createContainerAdditionalJSON []byte
func init() {
createContainerAdditionalJSON = ([]byte)(os.Getenv("HCSSHIM_CREATECONTAINER_ADDITIONALJSON"))
}
// CreateContainer creates a new container with the given configuration but does not start it.
func CreateContainer(id string, c *ContainerConfig) (Container, error) {
fullConfig, err := mergemaps.MergeJSON(c, createContainerAdditionalJSON)
if err != nil {
return nil, fmt.Errorf("failed to merge additional JSON '%s': %s", createContainerAdditionalJSON, err)
}
system, err := hcs.CreateComputeSystem(context.Background(), id, fullConfig)
if err != nil {
return nil, err
}
return &container{system: system}, err
}
// OpenContainer opens an existing container by ID.
func OpenContainer(id string) (Container, error) {
system, err := hcs.OpenComputeSystem(context.Background(), id)
if err != nil {
return nil, err
}
return &container{system: system}, err
}
// GetContainers gets a list of the containers on the system that match the query
func GetContainers(q ComputeSystemQuery) ([]ContainerProperties, error) {
return hcs.GetComputeSystems(context.Background(), q)
}
// Start synchronously starts the container.
func (container *container) Start() error {
return convertSystemError(container.system.Start(context.Background()), container)
}
// Shutdown requests a container shutdown, but it may not actually be shutdown until Wait() succeeds.
func (container *container) Shutdown() error {
err := container.system.Shutdown(context.Background())
if err != nil {
return convertSystemError(err, container)
}
return &ContainerError{Container: container, Err: ErrVmcomputeOperationPending, Operation: "hcsshim::ComputeSystem::Shutdown"}
}
// Terminate requests a container terminate, but it may not actually be terminated until Wait() succeeds.
func (container *container) Terminate() error {
err := container.system.Terminate(context.Background())
if err != nil {
return convertSystemError(err, container)
}
return &ContainerError{Container: container, Err: ErrVmcomputeOperationPending, Operation: "hcsshim::ComputeSystem::Terminate"}
}
// Waits synchronously waits for the container to shutdown or terminate.
func (container *container) Wait() error {
err := container.system.Wait()
if err == nil {
err = container.system.ExitError()
}
return convertSystemError(err, container)
}
// WaitTimeout synchronously waits for the container to terminate or the duration to elapse. It
// returns false if timeout occurs.
func (container *container) WaitTimeout(timeout time.Duration) error {
container.waitOnce.Do(func() {
container.waitCh = make(chan struct{})
go func() {
container.waitErr = container.Wait()
close(container.waitCh)
}()
})
t := time.NewTimer(timeout)
defer t.Stop()
select {
case <-t.C:
return &ContainerError{Container: container, Err: ErrTimeout, Operation: "hcsshim::ComputeSystem::Wait"}
case <-container.waitCh:
return container.waitErr
}
}
// Pause pauses the execution of a container.
func (container *container) Pause() error {
return convertSystemError(container.system.Pause(context.Background()), container)
}
// Resume resumes the execution of a container.
func (container *container) Resume() error {
return convertSystemError(container.system.Resume(context.Background()), container)
}
// HasPendingUpdates returns true if the container has updates pending to install
func (container *container) HasPendingUpdates() (bool, error) {
return false, nil
}
// Statistics returns statistics for the container. This is a legacy v1 call
func (container *container) Statistics() (Statistics, error) {
properties, err := container.system.Properties(context.Background(), schema1.PropertyTypeStatistics)
if err != nil {
return Statistics{}, convertSystemError(err, container)
}
return properties.Statistics, nil
}
// ProcessList returns an array of ProcessListItems for the container. This is a legacy v1 call
func (container *container) ProcessList() ([]ProcessListItem, error) {
properties, err := container.system.Properties(context.Background(), schema1.PropertyTypeProcessList)
if err != nil {
return nil, convertSystemError(err, container)
}
return properties.ProcessList, nil
}
// This is a legacy v1 call
func (container *container) MappedVirtualDisks() (map[int]MappedVirtualDiskController, error) {
properties, err := container.system.Properties(context.Background(), schema1.PropertyTypeMappedVirtualDisk)
if err != nil {
return nil, convertSystemError(err, container)
}
return properties.MappedVirtualDiskControllers, nil
}
// CreateProcess launches a new process within the container.
func (container *container) CreateProcess(c *ProcessConfig) (Process, error) {
p, err := container.system.CreateProcess(context.Background(), c)
if err != nil {
return nil, convertSystemError(err, container)
}
return &process{p: p.(*hcs.Process)}, nil
}
// OpenProcess gets an interface to an existing process within the container.
func (container *container) OpenProcess(pid int) (Process, error) {
p, err := container.system.OpenProcess(context.Background(), pid)
if err != nil {
return nil, convertSystemError(err, container)
}
return &process{p: p}, nil
}
// Close cleans up any state associated with the container but does not terminate or wait for it.
func (container *container) Close() error {
return convertSystemError(container.system.Close(), container)
}
// Modify the System
func (container *container) Modify(config *ResourceModificationRequestResponse) error {
return convertSystemError(container.system.Modify(context.Background(), config), container)
}

View File

@ -1,245 +0,0 @@
package hcsshim
import (
"fmt"
"syscall"
"github.com/Microsoft/hcsshim/internal/hns"
"github.com/Microsoft/hcsshim/internal/hcs"
"github.com/Microsoft/hcsshim/internal/hcserror"
)
var (
// ErrComputeSystemDoesNotExist is an error encountered when the container being operated on no longer exists = hcs.exist
ErrComputeSystemDoesNotExist = hcs.ErrComputeSystemDoesNotExist
// ErrElementNotFound is an error encountered when the object being referenced does not exist
ErrElementNotFound = hcs.ErrElementNotFound
// ErrElementNotFound is an error encountered when the object being referenced does not exist
ErrNotSupported = hcs.ErrNotSupported
// ErrInvalidData is an error encountered when the request being sent to hcs is invalid/unsupported
// decimal -2147024883 / hex 0x8007000d
ErrInvalidData = hcs.ErrInvalidData
// ErrHandleClose is an error encountered when the handle generating the notification being waited on has been closed
ErrHandleClose = hcs.ErrHandleClose
// ErrAlreadyClosed is an error encountered when using a handle that has been closed by the Close method
ErrAlreadyClosed = hcs.ErrAlreadyClosed
// ErrInvalidNotificationType is an error encountered when an invalid notification type is used
ErrInvalidNotificationType = hcs.ErrInvalidNotificationType
// ErrInvalidProcessState is an error encountered when the process is not in a valid state for the requested operation
ErrInvalidProcessState = hcs.ErrInvalidProcessState
// ErrTimeout is an error encountered when waiting on a notification times out
ErrTimeout = hcs.ErrTimeout
// ErrUnexpectedContainerExit is the error encountered when a container exits while waiting for
// a different expected notification
ErrUnexpectedContainerExit = hcs.ErrUnexpectedContainerExit
// ErrUnexpectedProcessAbort is the error encountered when communication with the compute service
// is lost while waiting for a notification
ErrUnexpectedProcessAbort = hcs.ErrUnexpectedProcessAbort
// ErrUnexpectedValue is an error encountered when hcs returns an invalid value
ErrUnexpectedValue = hcs.ErrUnexpectedValue
// ErrVmcomputeAlreadyStopped is an error encountered when a shutdown or terminate request is made on a stopped container
ErrVmcomputeAlreadyStopped = hcs.ErrVmcomputeAlreadyStopped
// ErrVmcomputeOperationPending is an error encountered when the operation is being completed asynchronously
ErrVmcomputeOperationPending = hcs.ErrVmcomputeOperationPending
// ErrVmcomputeOperationInvalidState is an error encountered when the compute system is not in a valid state for the requested operation
ErrVmcomputeOperationInvalidState = hcs.ErrVmcomputeOperationInvalidState
// ErrProcNotFound is an error encountered when a procedure look up fails.
ErrProcNotFound = hcs.ErrProcNotFound
// ErrVmcomputeOperationAccessIsDenied is an error which can be encountered when enumerating compute systems in RS1/RS2
// builds when the underlying silo might be in the process of terminating. HCS was fixed in RS3.
ErrVmcomputeOperationAccessIsDenied = hcs.ErrVmcomputeOperationAccessIsDenied
// ErrVmcomputeInvalidJSON is an error encountered when the compute system does not support/understand the messages sent by management
ErrVmcomputeInvalidJSON = hcs.ErrVmcomputeInvalidJSON
// ErrVmcomputeUnknownMessage is an error encountered guest compute system doesn't support the message
ErrVmcomputeUnknownMessage = hcs.ErrVmcomputeUnknownMessage
// ErrNotSupported is an error encountered when hcs doesn't support the request
ErrPlatformNotSupported = hcs.ErrPlatformNotSupported
)
type EndpointNotFoundError = hns.EndpointNotFoundError
type NetworkNotFoundError = hns.NetworkNotFoundError
// ProcessError is an error encountered in HCS during an operation on a Process object
type ProcessError struct {
Process *process
Operation string
Err error
Events []hcs.ErrorEvent
}
// ContainerError is an error encountered in HCS during an operation on a Container object
type ContainerError struct {
Container *container
Operation string
Err error
Events []hcs.ErrorEvent
}
func (e *ContainerError) Error() string {
if e == nil {
return "<nil>"
}
if e.Container == nil {
return "unexpected nil container for error: " + e.Err.Error()
}
s := "container " + e.Container.system.ID()
if e.Operation != "" {
s += " encountered an error during " + e.Operation
}
switch e.Err.(type) {
case nil:
break
case syscall.Errno:
s += fmt.Sprintf(": failure in a Windows system call: %s (0x%x)", e.Err, hcserror.Win32FromError(e.Err))
default:
s += fmt.Sprintf(": %s", e.Err.Error())
}
for _, ev := range e.Events {
s += "\n" + ev.String()
}
return s
}
func (e *ProcessError) Error() string {
if e == nil {
return "<nil>"
}
if e.Process == nil {
return "Unexpected nil process for error: " + e.Err.Error()
}
s := fmt.Sprintf("process %d in container %s", e.Process.p.Pid(), e.Process.p.SystemID())
if e.Operation != "" {
s += " encountered an error during " + e.Operation
}
switch e.Err.(type) {
case nil:
break
case syscall.Errno:
s += fmt.Sprintf(": failure in a Windows system call: %s (0x%x)", e.Err, hcserror.Win32FromError(e.Err))
default:
s += fmt.Sprintf(": %s", e.Err.Error())
}
for _, ev := range e.Events {
s += "\n" + ev.String()
}
return s
}
// IsNotExist checks if an error is caused by the Container or Process not existing.
// Note: Currently, ErrElementNotFound can mean that a Process has either
// already exited, or does not exist. Both IsAlreadyStopped and IsNotExist
// will currently return true when the error is ErrElementNotFound.
func IsNotExist(err error) bool {
if _, ok := err.(EndpointNotFoundError); ok {
return true
}
if _, ok := err.(NetworkNotFoundError); ok {
return true
}
return hcs.IsNotExist(getInnerError(err))
}
// IsAlreadyClosed checks if an error is caused by the Container or Process having been
// already closed by a call to the Close() method.
func IsAlreadyClosed(err error) bool {
return hcs.IsAlreadyClosed(getInnerError(err))
}
// IsPending returns a boolean indicating whether the error is that
// the requested operation is being completed in the background.
func IsPending(err error) bool {
return hcs.IsPending(getInnerError(err))
}
// IsTimeout returns a boolean indicating whether the error is caused by
// a timeout waiting for the operation to complete.
func IsTimeout(err error) bool {
return hcs.IsTimeout(getInnerError(err))
}
// IsAlreadyStopped returns a boolean indicating whether the error is caused by
// a Container or Process being already stopped.
// Note: Currently, ErrElementNotFound can mean that a Process has either
// already exited, or does not exist. Both IsAlreadyStopped and IsNotExist
// will currently return true when the error is ErrElementNotFound.
func IsAlreadyStopped(err error) bool {
return hcs.IsAlreadyStopped(getInnerError(err))
}
// IsNotSupported returns a boolean indicating whether the error is caused by
// unsupported platform requests
// Note: Currently Unsupported platform requests can be mean either
// ErrVmcomputeInvalidJSON, ErrInvalidData, ErrNotSupported or ErrVmcomputeUnknownMessage
// is thrown from the Platform
func IsNotSupported(err error) bool {
return hcs.IsNotSupported(getInnerError(err))
}
// IsOperationInvalidState returns true when err is caused by
// `ErrVmcomputeOperationInvalidState`.
func IsOperationInvalidState(err error) bool {
return hcs.IsOperationInvalidState(getInnerError(err))
}
// IsAccessIsDenied returns true when err is caused by
// `ErrVmcomputeOperationAccessIsDenied`.
func IsAccessIsDenied(err error) bool {
return hcs.IsAccessIsDenied(getInnerError(err))
}
func getInnerError(err error) error {
switch pe := err.(type) {
case nil:
return nil
case *ContainerError:
err = pe.Err
case *ProcessError:
err = pe.Err
}
return err
}
func convertSystemError(err error, c *container) error {
if serr, ok := err.(*hcs.SystemError); ok {
return &ContainerError{Container: c, Operation: serr.Op, Err: serr.Err, Events: serr.Events}
}
return err
}
func convertProcessError(err error, p *process) error {
if perr, ok := err.(*hcs.ProcessError); ok {
return &ProcessError{Process: p, Operation: perr.Op, Err: perr.Err, Events: perr.Events}
}
return err
}

View File

@ -1,12 +0,0 @@
# Requirements so far:
# dockerd running
# - image microsoft/nanoserver (matching host base image) docker load -i c:\baseimages\nanoserver.tar
# - image alpine (linux) docker pull --platform=linux alpine
# TODO: Add this a parameter for debugging. ie "functional-tests -debug=$true"
#$env:HCSSHIM_FUNCTIONAL_TESTS_DEBUG="yes please"
#pushd uvm
go test -v -tags "functional uvmcreate uvmscratch uvmscsi uvmvpmem uvmvsmb uvmp9" ./...
#popd

View File

@ -1,28 +0,0 @@
// Shim for the Host Compute Service (HCS) to manage Windows Server
// containers and Hyper-V containers.
package hcsshim
import (
"syscall"
"github.com/Microsoft/hcsshim/internal/hcserror"
)
//go:generate go run mksyscall_windows.go -output zsyscall_windows.go hcsshim.go
//sys SetCurrentThreadCompartmentId(compartmentId uint32) (hr error) = iphlpapi.SetCurrentThreadCompartmentId
const (
// Specific user-visible exit codes
WaitErrExecFailed = 32767
ERROR_GEN_FAILURE = hcserror.ERROR_GEN_FAILURE
ERROR_SHUTDOWN_IN_PROGRESS = syscall.Errno(1115)
WSAEINVAL = syscall.Errno(10022)
// Timeout on wait calls
TimeoutInfinite = 0xFFFFFFFF
)
type HcsError = hcserror.HcsError

View File

@ -1,118 +0,0 @@
package hcsshim
import (
"github.com/Microsoft/hcsshim/internal/hns"
)
// HNSEndpoint represents a network endpoint in HNS
type HNSEndpoint = hns.HNSEndpoint
// HNSEndpointStats represent the stats for an networkendpoint in HNS
type HNSEndpointStats = hns.EndpointStats
// Namespace represents a Compartment.
type Namespace = hns.Namespace
//SystemType represents the type of the system on which actions are done
type SystemType string
// SystemType const
const (
ContainerType SystemType = "Container"
VirtualMachineType SystemType = "VirtualMachine"
HostType SystemType = "Host"
)
// EndpointAttachDetachRequest is the structure used to send request to the container to modify the system
// Supported resource types are Network and Request Types are Add/Remove
type EndpointAttachDetachRequest = hns.EndpointAttachDetachRequest
// EndpointResquestResponse is object to get the endpoint request response
type EndpointResquestResponse = hns.EndpointResquestResponse
// HNSEndpointRequest makes a HNS call to modify/query a network endpoint
func HNSEndpointRequest(method, path, request string) (*HNSEndpoint, error) {
return hns.HNSEndpointRequest(method, path, request)
}
// HNSListEndpointRequest makes a HNS call to query the list of available endpoints
func HNSListEndpointRequest() ([]HNSEndpoint, error) {
return hns.HNSListEndpointRequest()
}
// HotAttachEndpoint makes a HCS Call to attach the endpoint to the container
func HotAttachEndpoint(containerID string, endpointID string) error {
endpoint, err := GetHNSEndpointByID(endpointID)
if err != nil {
return err
}
isAttached, err := endpoint.IsAttached(containerID)
if isAttached {
return err
}
return modifyNetworkEndpoint(containerID, endpointID, Add)
}
// HotDetachEndpoint makes a HCS Call to detach the endpoint from the container
func HotDetachEndpoint(containerID string, endpointID string) error {
endpoint, err := GetHNSEndpointByID(endpointID)
if err != nil {
return err
}
isAttached, err := endpoint.IsAttached(containerID)
if !isAttached {
return err
}
return modifyNetworkEndpoint(containerID, endpointID, Remove)
}
// ModifyContainer corresponding to the container id, by sending a request
func modifyContainer(id string, request *ResourceModificationRequestResponse) error {
container, err := OpenContainer(id)
if err != nil {
if IsNotExist(err) {
return ErrComputeSystemDoesNotExist
}
return getInnerError(err)
}
defer container.Close()
err = container.Modify(request)
if err != nil {
if IsNotSupported(err) {
return ErrPlatformNotSupported
}
return getInnerError(err)
}
return nil
}
func modifyNetworkEndpoint(containerID string, endpointID string, request RequestType) error {
requestMessage := &ResourceModificationRequestResponse{
Resource: Network,
Request: request,
Data: endpointID,
}
err := modifyContainer(containerID, requestMessage)
if err != nil {
return err
}
return nil
}
// GetHNSEndpointByID get the Endpoint by ID
func GetHNSEndpointByID(endpointID string) (*HNSEndpoint, error) {
return hns.GetHNSEndpointByID(endpointID)
}
// GetHNSEndpointByName gets the endpoint filtered by Name
func GetHNSEndpointByName(endpointName string) (*HNSEndpoint, error) {
return hns.GetHNSEndpointByName(endpointName)
}
// GetHNSEndpointStats gets the endpoint stats by ID
func GetHNSEndpointStats(endpointName string) (*HNSEndpointStats, error) {
return hns.GetHNSEndpointStats(endpointName)
}

View File

@ -1,16 +0,0 @@
package hcsshim
import (
"github.com/Microsoft/hcsshim/internal/hns"
)
type HNSGlobals = hns.HNSGlobals
type HNSVersion = hns.HNSVersion
var (
HNSVersion1803 = hns.HNSVersion1803
)
func GetHNSGlobals() (*HNSGlobals, error) {
return hns.GetHNSGlobals()
}

View File

@ -1,36 +0,0 @@
package hcsshim
import (
"github.com/Microsoft/hcsshim/internal/hns"
)
// Subnet is assoicated with a network and represents a list
// of subnets available to the network
type Subnet = hns.Subnet
// MacPool is assoicated with a network and represents a list
// of macaddresses available to the network
type MacPool = hns.MacPool
// HNSNetwork represents a network in HNS
type HNSNetwork = hns.HNSNetwork
// HNSNetworkRequest makes a call into HNS to update/query a single network
func HNSNetworkRequest(method, path, request string) (*HNSNetwork, error) {
return hns.HNSNetworkRequest(method, path, request)
}
// HNSListNetworkRequest makes a HNS call to query the list of available networks
func HNSListNetworkRequest(method, path, request string) ([]HNSNetwork, error) {
return hns.HNSListNetworkRequest(method, path, request)
}
// GetHNSNetworkByID
func GetHNSNetworkByID(networkID string) (*HNSNetwork, error) {
return hns.GetHNSNetworkByID(networkID)
}
// GetHNSNetworkName filtered by Name
func GetHNSNetworkByName(networkName string) (*HNSNetwork, error) {
return hns.GetHNSNetworkByName(networkName)
}

View File

@ -1,60 +0,0 @@
package hcsshim
import (
"github.com/Microsoft/hcsshim/internal/hns"
)
// Type of Request Support in ModifySystem
type PolicyType = hns.PolicyType
// RequestType const
const (
Nat = hns.Nat
ACL = hns.ACL
PA = hns.PA
VLAN = hns.VLAN
VSID = hns.VSID
VNet = hns.VNet
L2Driver = hns.L2Driver
Isolation = hns.Isolation
QOS = hns.QOS
OutboundNat = hns.OutboundNat
ExternalLoadBalancer = hns.ExternalLoadBalancer
Route = hns.Route
Proxy = hns.Proxy
)
type ProxyPolicy = hns.ProxyPolicy
type NatPolicy = hns.NatPolicy
type QosPolicy = hns.QosPolicy
type IsolationPolicy = hns.IsolationPolicy
type VlanPolicy = hns.VlanPolicy
type VsidPolicy = hns.VsidPolicy
type PaPolicy = hns.PaPolicy
type OutboundNatPolicy = hns.OutboundNatPolicy
type ActionType = hns.ActionType
type DirectionType = hns.DirectionType
type RuleType = hns.RuleType
const (
Allow = hns.Allow
Block = hns.Block
In = hns.In
Out = hns.Out
Host = hns.Host
Switch = hns.Switch
)
type ACLPolicy = hns.ACLPolicy
type Policy = hns.Policy

View File

@ -1,47 +0,0 @@
package hcsshim
import (
"github.com/Microsoft/hcsshim/internal/hns"
)
// RoutePolicy is a structure defining schema for Route based Policy
type RoutePolicy = hns.RoutePolicy
// ELBPolicy is a structure defining schema for ELB LoadBalancing based Policy
type ELBPolicy = hns.ELBPolicy
// LBPolicy is a structure defining schema for LoadBalancing based Policy
type LBPolicy = hns.LBPolicy
// PolicyList is a structure defining schema for Policy list request
type PolicyList = hns.PolicyList
// HNSPolicyListRequest makes a call into HNS to update/query a single network
func HNSPolicyListRequest(method, path, request string) (*PolicyList, error) {
return hns.HNSPolicyListRequest(method, path, request)
}
// HNSListPolicyListRequest gets all the policy list
func HNSListPolicyListRequest() ([]PolicyList, error) {
return hns.HNSListPolicyListRequest()
}
// PolicyListRequest makes a HNS call to modify/query a network policy list
func PolicyListRequest(method, path, request string) (*PolicyList, error) {
return hns.PolicyListRequest(method, path, request)
}
// GetPolicyListByID get the policy list by ID
func GetPolicyListByID(policyListID string) (*PolicyList, error) {
return hns.GetPolicyListByID(policyListID)
}
// AddLoadBalancer policy list for the specified endpoints
func AddLoadBalancer(endpoints []HNSEndpoint, isILB bool, sourceVIP, vip string, protocol uint16, internalPort uint16, externalPort uint16) (*PolicyList, error) {
return hns.AddLoadBalancer(endpoints, isILB, sourceVIP, vip, protocol, internalPort, externalPort)
}
// AddRoute adds route policy list for the specified endpoints
func AddRoute(endpoints []HNSEndpoint, destinationPrefix string, nextHop string, encapEnabled bool) (*PolicyList, error) {
return hns.AddRoute(endpoints, destinationPrefix, nextHop, encapEnabled)
}

View File

@ -1,13 +0,0 @@
package hcsshim
import (
"github.com/Microsoft/hcsshim/internal/hns"
)
type HNSSupportedFeatures = hns.HNSSupportedFeatures
type HNSAclFeatures = hns.HNSAclFeatures
func GetHNSSupportedFeatures() HNSSupportedFeatures {
return hns.GetHNSSupportedFeatures()
}

View File

@ -1,114 +0,0 @@
package hcsshim
import (
"io"
"time"
"github.com/Microsoft/hcsshim/internal/hcs/schema1"
)
// ProcessConfig is used as both the input of Container.CreateProcess
// and to convert the parameters to JSON for passing onto the HCS
type ProcessConfig = schema1.ProcessConfig
type Layer = schema1.Layer
type MappedDir = schema1.MappedDir
type MappedPipe = schema1.MappedPipe
type HvRuntime = schema1.HvRuntime
type MappedVirtualDisk = schema1.MappedVirtualDisk
// AssignedDevice represents a device that has been directly assigned to a container
//
// NOTE: Support added in RS5
type AssignedDevice = schema1.AssignedDevice
// ContainerConfig is used as both the input of CreateContainer
// and to convert the parameters to JSON for passing onto the HCS
type ContainerConfig = schema1.ContainerConfig
type ComputeSystemQuery = schema1.ComputeSystemQuery
// Container represents a created (but not necessarily running) container.
type Container interface {
// Start synchronously starts the container.
Start() error
// Shutdown requests a container shutdown, but it may not actually be shutdown until Wait() succeeds.
Shutdown() error
// Terminate requests a container terminate, but it may not actually be terminated until Wait() succeeds.
Terminate() error
// Waits synchronously waits for the container to shutdown or terminate.
Wait() error
// WaitTimeout synchronously waits for the container to terminate or the duration to elapse. It
// returns false if timeout occurs.
WaitTimeout(time.Duration) error
// Pause pauses the execution of a container.
Pause() error
// Resume resumes the execution of a container.
Resume() error
// HasPendingUpdates returns true if the container has updates pending to install.
HasPendingUpdates() (bool, error)
// Statistics returns statistics for a container.
Statistics() (Statistics, error)
// ProcessList returns details for the processes in a container.
ProcessList() ([]ProcessListItem, error)
// MappedVirtualDisks returns virtual disks mapped to a utility VM, indexed by controller
MappedVirtualDisks() (map[int]MappedVirtualDiskController, error)
// CreateProcess launches a new process within the container.
CreateProcess(c *ProcessConfig) (Process, error)
// OpenProcess gets an interface to an existing process within the container.
OpenProcess(pid int) (Process, error)
// Close cleans up any state associated with the container but does not terminate or wait for it.
Close() error
// Modify the System
Modify(config *ResourceModificationRequestResponse) error
}
// Process represents a running or exited process.
type Process interface {
// Pid returns the process ID of the process within the container.
Pid() int
// Kill signals the process to terminate but does not wait for it to finish terminating.
Kill() error
// Wait waits for the process to exit.
Wait() error
// WaitTimeout waits for the process to exit or the duration to elapse. It returns
// false if timeout occurs.
WaitTimeout(time.Duration) error
// ExitCode returns the exit code of the process. The process must have
// already terminated.
ExitCode() (int, error)
// ResizeConsole resizes the console of the process.
ResizeConsole(width, height uint16) error
// Stdio returns the stdin, stdout, and stderr pipes, respectively. Closing
// these pipes does not close the underlying pipes; it should be possible to
// call this multiple times to get multiple interfaces.
Stdio() (io.WriteCloser, io.ReadCloser, io.ReadCloser, error)
// CloseStdin closes the write side of the stdin pipe so that the process is
// notified on the read side that there is no more data in stdin.
CloseStdin() error
// Close cleans up any state associated with the process but does not kill
// or wait on it.
Close() error
}

View File

@ -1,97 +0,0 @@
package cow
import (
"context"
"io"
"github.com/Microsoft/hcsshim/internal/hcs/schema1"
hcsschema "github.com/Microsoft/hcsshim/internal/hcs/schema2"
)
// Process is the interface for an OS process running in a container or utility VM.
type Process interface {
// Close releases resources associated with the process and closes the
// writer and readers returned by Stdio. Depending on the implementation,
// this may also terminate the process.
Close() error
// CloseStdin causes the process's stdin handle to receive EOF/EPIPE/whatever
// is appropriate to indicate that no more data is available.
CloseStdin(ctx context.Context) error
// CloseStdout closes the stdout connection to the process. It is used to indicate
// that we are done receiving output on the shim side.
CloseStdout(ctx context.Context) error
// CloseStderr closes the stderr connection to the process. It is used to indicate
// that we are done receiving output on the shim side.
CloseStderr(ctx context.Context) error
// Pid returns the process ID.
Pid() int
// Stdio returns the stdio streams for a process. These may be nil if a stream
// was not requested during CreateProcess.
Stdio() (_ io.Writer, _ io.Reader, _ io.Reader)
// ResizeConsole resizes the virtual terminal associated with the process.
ResizeConsole(ctx context.Context, width, height uint16) error
// Kill sends a SIGKILL or equivalent signal to the process and returns whether
// the signal was delivered. It does not wait for the process to terminate.
Kill(ctx context.Context) (bool, error)
// Signal sends a signal to the process and returns whether the signal was
// delivered. The input is OS specific (either
// guestrequest.SignalProcessOptionsWCOW or
// guestrequest.SignalProcessOptionsLCOW). It does not wait for the process
// to terminate.
Signal(ctx context.Context, options interface{}) (bool, error)
// Wait waits for the process to complete, or for a connection to the process to be
// terminated by some error condition (including calling Close).
Wait() error
// ExitCode returns the exit code of the process. Returns an error if the process is
// not running.
ExitCode() (int, error)
}
// ProcessHost is the interface for creating processes.
type ProcessHost interface {
// CreateProcess creates a process. The configuration is host specific
// (either hcsschema.ProcessParameters or lcow.ProcessParameters).
CreateProcess(ctx context.Context, config interface{}) (Process, error)
// OS returns the host's operating system, "linux" or "windows".
OS() string
// IsOCI specifies whether this is an OCI-compliant process host. If true,
// then the configuration passed to CreateProcess should have an OCI process
// spec (or nil if this is the initial process in an OCI container).
// Otherwise, it should have the HCS-specific process parameters.
IsOCI() bool
}
// Container is the interface for container objects, either running on the host or
// in a utility VM.
type Container interface {
ProcessHost
// Close releases the resources associated with the container. Depending on
// the implementation, this may also terminate the container.
Close() error
// ID returns the container ID.
ID() string
// Properties returns the requested container properties targeting a V1 schema container.
Properties(ctx context.Context, types ...schema1.PropertyType) (*schema1.ContainerProperties, error)
// PropertiesV2 returns the requested container properties targeting a V2 schema container.
PropertiesV2(ctx context.Context, types ...hcsschema.PropertyType) (*hcsschema.Properties, error)
// Start starts a container.
Start(ctx context.Context) error
// Shutdown sends a shutdown request to the container (but does not wait for
// the shutdown to complete).
Shutdown(ctx context.Context) error
// Terminate sends a terminate request to the container (but does not wait
// for the terminate to complete).
Terminate(ctx context.Context) error
// Wait waits for the container to terminate, or for the connection to the
// container to be terminated by some error condition (including calling
// Close).
Wait() error
// WaitChannel returns the wait channel of the container
WaitChannel() <-chan struct{}
// WaitError returns the container termination error.
// This function should only be called after the channel in WaitChannel()
// is closed. Otherwise it is not thread safe.
WaitError() error
// Modify sends a request to modify container resources
Modify(ctx context.Context, config interface{}) error
}

View File

@ -1,161 +0,0 @@
package hcs
import (
"fmt"
"sync"
"syscall"
"github.com/Microsoft/hcsshim/internal/interop"
"github.com/Microsoft/hcsshim/internal/logfields"
"github.com/Microsoft/hcsshim/internal/vmcompute"
"github.com/sirupsen/logrus"
)
var (
nextCallback uintptr
callbackMap = map[uintptr]*notificationWatcherContext{}
callbackMapLock = sync.RWMutex{}
notificationWatcherCallback = syscall.NewCallback(notificationWatcher)
// Notifications for HCS_SYSTEM handles
hcsNotificationSystemExited hcsNotification = 0x00000001
hcsNotificationSystemCreateCompleted hcsNotification = 0x00000002
hcsNotificationSystemStartCompleted hcsNotification = 0x00000003
hcsNotificationSystemPauseCompleted hcsNotification = 0x00000004
hcsNotificationSystemResumeCompleted hcsNotification = 0x00000005
hcsNotificationSystemCrashReport hcsNotification = 0x00000006
hcsNotificationSystemSiloJobCreated hcsNotification = 0x00000007
hcsNotificationSystemSaveCompleted hcsNotification = 0x00000008
hcsNotificationSystemRdpEnhancedModeStateChanged hcsNotification = 0x00000009
hcsNotificationSystemShutdownFailed hcsNotification = 0x0000000A
hcsNotificationSystemGetPropertiesCompleted hcsNotification = 0x0000000B
hcsNotificationSystemModifyCompleted hcsNotification = 0x0000000C
hcsNotificationSystemCrashInitiated hcsNotification = 0x0000000D
hcsNotificationSystemGuestConnectionClosed hcsNotification = 0x0000000E
// Notifications for HCS_PROCESS handles
hcsNotificationProcessExited hcsNotification = 0x00010000
// Common notifications
hcsNotificationInvalid hcsNotification = 0x00000000
hcsNotificationServiceDisconnect hcsNotification = 0x01000000
)
type hcsNotification uint32
func (hn hcsNotification) String() string {
switch hn {
case hcsNotificationSystemExited:
return "SystemExited"
case hcsNotificationSystemCreateCompleted:
return "SystemCreateCompleted"
case hcsNotificationSystemStartCompleted:
return "SystemStartCompleted"
case hcsNotificationSystemPauseCompleted:
return "SystemPauseCompleted"
case hcsNotificationSystemResumeCompleted:
return "SystemResumeCompleted"
case hcsNotificationSystemCrashReport:
return "SystemCrashReport"
case hcsNotificationSystemSiloJobCreated:
return "SystemSiloJobCreated"
case hcsNotificationSystemSaveCompleted:
return "SystemSaveCompleted"
case hcsNotificationSystemRdpEnhancedModeStateChanged:
return "SystemRdpEnhancedModeStateChanged"
case hcsNotificationSystemShutdownFailed:
return "SystemShutdownFailed"
case hcsNotificationSystemGetPropertiesCompleted:
return "SystemGetPropertiesCompleted"
case hcsNotificationSystemModifyCompleted:
return "SystemModifyCompleted"
case hcsNotificationSystemCrashInitiated:
return "SystemCrashInitiated"
case hcsNotificationSystemGuestConnectionClosed:
return "SystemGuestConnectionClosed"
case hcsNotificationProcessExited:
return "ProcessExited"
case hcsNotificationInvalid:
return "Invalid"
case hcsNotificationServiceDisconnect:
return "ServiceDisconnect"
default:
return fmt.Sprintf("Unknown: %d", hn)
}
}
type notificationChannel chan error
type notificationWatcherContext struct {
channels notificationChannels
handle vmcompute.HcsCallback
systemID string
processID int
}
type notificationChannels map[hcsNotification]notificationChannel
func newSystemChannels() notificationChannels {
channels := make(notificationChannels)
for _, notif := range []hcsNotification{
hcsNotificationServiceDisconnect,
hcsNotificationSystemExited,
hcsNotificationSystemCreateCompleted,
hcsNotificationSystemStartCompleted,
hcsNotificationSystemPauseCompleted,
hcsNotificationSystemResumeCompleted,
hcsNotificationSystemSaveCompleted,
} {
channels[notif] = make(notificationChannel, 1)
}
return channels
}
func newProcessChannels() notificationChannels {
channels := make(notificationChannels)
for _, notif := range []hcsNotification{
hcsNotificationServiceDisconnect,
hcsNotificationProcessExited,
} {
channels[notif] = make(notificationChannel, 1)
}
return channels
}
func closeChannels(channels notificationChannels) {
for _, c := range channels {
close(c)
}
}
func notificationWatcher(notificationType hcsNotification, callbackNumber uintptr, notificationStatus uintptr, notificationData *uint16) uintptr {
var result error
if int32(notificationStatus) < 0 {
result = interop.Win32FromHresult(notificationStatus)
}
callbackMapLock.RLock()
context := callbackMap[callbackNumber]
callbackMapLock.RUnlock()
if context == nil {
return 0
}
log := logrus.WithFields(logrus.Fields{
"notification-type": notificationType.String(),
"system-id": context.systemID,
})
if context.processID != 0 {
log.Data[logfields.ProcessID] = context.processID
}
log.Debug("HCS notification")
if channel, ok := context.channels[notificationType]; ok {
channel <- result
}
return 0
}

View File

@ -1,343 +0,0 @@
package hcs
import (
"context"
"encoding/json"
"errors"
"fmt"
"net"
"syscall"
"github.com/Microsoft/hcsshim/internal/log"
)
var (
// ErrComputeSystemDoesNotExist is an error encountered when the container being operated on no longer exists
ErrComputeSystemDoesNotExist = syscall.Errno(0xc037010e)
// ErrElementNotFound is an error encountered when the object being referenced does not exist
ErrElementNotFound = syscall.Errno(0x490)
// ErrElementNotFound is an error encountered when the object being referenced does not exist
ErrNotSupported = syscall.Errno(0x32)
// ErrInvalidData is an error encountered when the request being sent to hcs is invalid/unsupported
// decimal -2147024883 / hex 0x8007000d
ErrInvalidData = syscall.Errno(0xd)
// ErrHandleClose is an error encountered when the handle generating the notification being waited on has been closed
ErrHandleClose = errors.New("hcsshim: the handle generating this notification has been closed")
// ErrAlreadyClosed is an error encountered when using a handle that has been closed by the Close method
ErrAlreadyClosed = errors.New("hcsshim: the handle has already been closed")
// ErrInvalidNotificationType is an error encountered when an invalid notification type is used
ErrInvalidNotificationType = errors.New("hcsshim: invalid notification type")
// ErrInvalidProcessState is an error encountered when the process is not in a valid state for the requested operation
ErrInvalidProcessState = errors.New("the process is in an invalid state for the attempted operation")
// ErrTimeout is an error encountered when waiting on a notification times out
ErrTimeout = errors.New("hcsshim: timeout waiting for notification")
// ErrUnexpectedContainerExit is the error encountered when a container exits while waiting for
// a different expected notification
ErrUnexpectedContainerExit = errors.New("unexpected container exit")
// ErrUnexpectedProcessAbort is the error encountered when communication with the compute service
// is lost while waiting for a notification
ErrUnexpectedProcessAbort = errors.New("lost communication with compute service")
// ErrUnexpectedValue is an error encountered when hcs returns an invalid value
ErrUnexpectedValue = errors.New("unexpected value returned from hcs")
// ErrVmcomputeAlreadyStopped is an error encountered when a shutdown or terminate request is made on a stopped container
ErrVmcomputeAlreadyStopped = syscall.Errno(0xc0370110)
// ErrVmcomputeOperationPending is an error encountered when the operation is being completed asynchronously
ErrVmcomputeOperationPending = syscall.Errno(0xC0370103)
// ErrVmcomputeOperationInvalidState is an error encountered when the compute system is not in a valid state for the requested operation
ErrVmcomputeOperationInvalidState = syscall.Errno(0xc0370105)
// ErrProcNotFound is an error encountered when a procedure look up fails.
ErrProcNotFound = syscall.Errno(0x7f)
// ErrVmcomputeOperationAccessIsDenied is an error which can be encountered when enumerating compute systems in RS1/RS2
// builds when the underlying silo might be in the process of terminating. HCS was fixed in RS3.
ErrVmcomputeOperationAccessIsDenied = syscall.Errno(0x5)
// ErrVmcomputeInvalidJSON is an error encountered when the compute system does not support/understand the messages sent by management
ErrVmcomputeInvalidJSON = syscall.Errno(0xc037010d)
// ErrVmcomputeUnknownMessage is an error encountered guest compute system doesn't support the message
ErrVmcomputeUnknownMessage = syscall.Errno(0xc037010b)
// ErrVmcomputeUnexpectedExit is an error encountered when the compute system terminates unexpectedly
ErrVmcomputeUnexpectedExit = syscall.Errno(0xC0370106)
// ErrNotSupported is an error encountered when hcs doesn't support the request
ErrPlatformNotSupported = errors.New("unsupported platform request")
// ErrProcessAlreadyStopped is returned by hcs if the process we're trying to kill has already been stopped.
ErrProcessAlreadyStopped = syscall.Errno(0x8037011f)
// ErrInvalidHandle is an error that can be encountrered when querying the properties of a compute system when the handle to that
// compute system has already been closed.
ErrInvalidHandle = syscall.Errno(0x6)
)
type ErrorEvent struct {
Message string `json:"Message,omitempty"` // Fully formated error message
StackTrace string `json:"StackTrace,omitempty"` // Stack trace in string form
Provider string `json:"Provider,omitempty"`
EventID uint16 `json:"EventId,omitempty"`
Flags uint32 `json:"Flags,omitempty"`
Source string `json:"Source,omitempty"`
//Data []EventData `json:"Data,omitempty"` // Omit this as HCS doesn't encode this well. It's more confusing to include. It is however logged in debug mode (see processHcsResult function)
}
type hcsResult struct {
Error int32
ErrorMessage string
ErrorEvents []ErrorEvent `json:"ErrorEvents,omitempty"`
}
func (ev *ErrorEvent) String() string {
evs := "[Event Detail: " + ev.Message
if ev.StackTrace != "" {
evs += " Stack Trace: " + ev.StackTrace
}
if ev.Provider != "" {
evs += " Provider: " + ev.Provider
}
if ev.EventID != 0 {
evs = fmt.Sprintf("%s EventID: %d", evs, ev.EventID)
}
if ev.Flags != 0 {
evs = fmt.Sprintf("%s flags: %d", evs, ev.Flags)
}
if ev.Source != "" {
evs += " Source: " + ev.Source
}
evs += "]"
return evs
}
func processHcsResult(ctx context.Context, resultJSON string) []ErrorEvent {
if resultJSON != "" {
result := &hcsResult{}
if err := json.Unmarshal([]byte(resultJSON), result); err != nil {
log.G(ctx).WithError(err).Warning("Could not unmarshal HCS result")
return nil
}
return result.ErrorEvents
}
return nil
}
type HcsError struct {
Op string
Err error
Events []ErrorEvent
}
var _ net.Error = &HcsError{}
func (e *HcsError) Error() string {
s := e.Op + ": " + e.Err.Error()
for _, ev := range e.Events {
s += "\n" + ev.String()
}
return s
}
func (e *HcsError) Temporary() bool {
err, ok := e.Err.(net.Error)
return ok && err.Temporary() //nolint:staticcheck
}
func (e *HcsError) Timeout() bool {
err, ok := e.Err.(net.Error)
return ok && err.Timeout()
}
// ProcessError is an error encountered in HCS during an operation on a Process object
type ProcessError struct {
SystemID string
Pid int
Op string
Err error
Events []ErrorEvent
}
var _ net.Error = &ProcessError{}
// SystemError is an error encountered in HCS during an operation on a Container object
type SystemError struct {
ID string
Op string
Err error
Events []ErrorEvent
}
var _ net.Error = &SystemError{}
func (e *SystemError) Error() string {
s := e.Op + " " + e.ID + ": " + e.Err.Error()
for _, ev := range e.Events {
s += "\n" + ev.String()
}
return s
}
func (e *SystemError) Temporary() bool {
err, ok := e.Err.(net.Error)
return ok && err.Temporary() //nolint:staticcheck
}
func (e *SystemError) Timeout() bool {
err, ok := e.Err.(net.Error)
return ok && err.Timeout()
}
func makeSystemError(system *System, op string, err error, events []ErrorEvent) error {
// Don't double wrap errors
if _, ok := err.(*SystemError); ok {
return err
}
return &SystemError{
ID: system.ID(),
Op: op,
Err: err,
Events: events,
}
}
func (e *ProcessError) Error() string {
s := fmt.Sprintf("%s %s:%d: %s", e.Op, e.SystemID, e.Pid, e.Err.Error())
for _, ev := range e.Events {
s += "\n" + ev.String()
}
return s
}
func (e *ProcessError) Temporary() bool {
err, ok := e.Err.(net.Error)
return ok && err.Temporary() //nolint:staticcheck
}
func (e *ProcessError) Timeout() bool {
err, ok := e.Err.(net.Error)
return ok && err.Timeout()
}
func makeProcessError(process *Process, op string, err error, events []ErrorEvent) error {
// Don't double wrap errors
if _, ok := err.(*ProcessError); ok {
return err
}
return &ProcessError{
Pid: process.Pid(),
SystemID: process.SystemID(),
Op: op,
Err: err,
Events: events,
}
}
// IsNotExist checks if an error is caused by the Container or Process not existing.
// Note: Currently, ErrElementNotFound can mean that a Process has either
// already exited, or does not exist. Both IsAlreadyStopped and IsNotExist
// will currently return true when the error is ErrElementNotFound.
func IsNotExist(err error) bool {
err = getInnerError(err)
return err == ErrComputeSystemDoesNotExist ||
err == ErrElementNotFound
}
// IsErrorInvalidHandle checks whether the error is the result of an operation carried
// out on a handle that is invalid/closed. This error popped up while trying to query
// stats on a container in the process of being stopped.
func IsErrorInvalidHandle(err error) bool {
err = getInnerError(err)
return err == ErrInvalidHandle
}
// IsAlreadyClosed checks if an error is caused by the Container or Process having been
// already closed by a call to the Close() method.
func IsAlreadyClosed(err error) bool {
err = getInnerError(err)
return err == ErrAlreadyClosed
}
// IsPending returns a boolean indicating whether the error is that
// the requested operation is being completed in the background.
func IsPending(err error) bool {
err = getInnerError(err)
return err == ErrVmcomputeOperationPending
}
// IsTimeout returns a boolean indicating whether the error is caused by
// a timeout waiting for the operation to complete.
func IsTimeout(err error) bool {
if err, ok := err.(net.Error); ok && err.Timeout() {
return true
}
err = getInnerError(err)
return err == ErrTimeout
}
// IsAlreadyStopped returns a boolean indicating whether the error is caused by
// a Container or Process being already stopped.
// Note: Currently, ErrElementNotFound can mean that a Process has either
// already exited, or does not exist. Both IsAlreadyStopped and IsNotExist
// will currently return true when the error is ErrElementNotFound.
func IsAlreadyStopped(err error) bool {
err = getInnerError(err)
return err == ErrVmcomputeAlreadyStopped ||
err == ErrProcessAlreadyStopped ||
err == ErrElementNotFound
}
// IsNotSupported returns a boolean indicating whether the error is caused by
// unsupported platform requests
// Note: Currently Unsupported platform requests can be mean either
// ErrVmcomputeInvalidJSON, ErrInvalidData, ErrNotSupported or ErrVmcomputeUnknownMessage
// is thrown from the Platform
func IsNotSupported(err error) bool {
err = getInnerError(err)
// If Platform doesn't recognize or support the request sent, below errors are seen
return err == ErrVmcomputeInvalidJSON ||
err == ErrInvalidData ||
err == ErrNotSupported ||
err == ErrVmcomputeUnknownMessage
}
// IsOperationInvalidState returns true when err is caused by
// `ErrVmcomputeOperationInvalidState`.
func IsOperationInvalidState(err error) bool {
err = getInnerError(err)
return err == ErrVmcomputeOperationInvalidState
}
// IsAccessIsDenied returns true when err is caused by
// `ErrVmcomputeOperationAccessIsDenied`.
func IsAccessIsDenied(err error) bool {
err = getInnerError(err)
return err == ErrVmcomputeOperationAccessIsDenied
}
func getInnerError(err error) error {
switch pe := err.(type) {
case nil:
return nil
case *HcsError:
err = pe.Err
case *SystemError:
err = pe.Err
case *ProcessError:
err = pe.Err
}
return err
}

View File

@ -1,589 +0,0 @@
package hcs
import (
"context"
"encoding/json"
"errors"
"io"
"os"
"sync"
"syscall"
"time"
"github.com/Microsoft/hcsshim/internal/log"
"github.com/Microsoft/hcsshim/internal/oc"
"github.com/Microsoft/hcsshim/internal/vmcompute"
"go.opencensus.io/trace"
)
// ContainerError is an error encountered in HCS
type Process struct {
handleLock sync.RWMutex
handle vmcompute.HcsProcess
processID int
system *System
hasCachedStdio bool
stdioLock sync.Mutex
stdin io.WriteCloser
stdout io.ReadCloser
stderr io.ReadCloser
callbackNumber uintptr
killSignalDelivered bool
closedWaitOnce sync.Once
waitBlock chan struct{}
exitCode int
waitError error
}
func newProcess(process vmcompute.HcsProcess, processID int, computeSystem *System) *Process {
return &Process{
handle: process,
processID: processID,
system: computeSystem,
waitBlock: make(chan struct{}),
}
}
type processModifyRequest struct {
Operation string
ConsoleSize *consoleSize `json:",omitempty"`
CloseHandle *closeHandle `json:",omitempty"`
}
type consoleSize struct {
Height uint16
Width uint16
}
type closeHandle struct {
Handle string
}
type processStatus struct {
ProcessID uint32
Exited bool
ExitCode uint32
LastWaitResult int32
}
const stdIn string = "StdIn"
const (
modifyConsoleSize string = "ConsoleSize"
modifyCloseHandle string = "CloseHandle"
)
// Pid returns the process ID of the process within the container.
func (process *Process) Pid() int {
return process.processID
}
// SystemID returns the ID of the process's compute system.
func (process *Process) SystemID() string {
return process.system.ID()
}
func (process *Process) processSignalResult(ctx context.Context, err error) (bool, error) {
switch err {
case nil:
return true, nil
case ErrVmcomputeOperationInvalidState, ErrComputeSystemDoesNotExist, ErrElementNotFound:
select {
case <-process.waitBlock:
// The process exit notification has already arrived.
default:
// The process should be gone, but we have not received the notification.
// After a second, force unblock the process wait to work around a possible
// deadlock in the HCS.
go func() {
time.Sleep(time.Second)
process.closedWaitOnce.Do(func() {
log.G(ctx).WithError(err).Warn("force unblocking process waits")
process.exitCode = -1
process.waitError = err
close(process.waitBlock)
})
}()
}
return false, nil
default:
return false, err
}
}
// Signal signals the process with `options`.
//
// For LCOW `guestrequest.SignalProcessOptionsLCOW`.
//
// For WCOW `guestrequest.SignalProcessOptionsWCOW`.
func (process *Process) Signal(ctx context.Context, options interface{}) (bool, error) {
process.handleLock.RLock()
defer process.handleLock.RUnlock()
operation := "hcs::Process::Signal"
if process.handle == 0 {
return false, makeProcessError(process, operation, ErrAlreadyClosed, nil)
}
optionsb, err := json.Marshal(options)
if err != nil {
return false, err
}
resultJSON, err := vmcompute.HcsSignalProcess(ctx, process.handle, string(optionsb))
events := processHcsResult(ctx, resultJSON)
delivered, err := process.processSignalResult(ctx, err)
if err != nil {
err = makeProcessError(process, operation, err, events)
}
return delivered, err
}
// Kill signals the process to terminate but does not wait for it to finish terminating.
func (process *Process) Kill(ctx context.Context) (bool, error) {
process.handleLock.RLock()
defer process.handleLock.RUnlock()
operation := "hcs::Process::Kill"
if process.handle == 0 {
return false, makeProcessError(process, operation, ErrAlreadyClosed, nil)
}
if process.killSignalDelivered {
// A kill signal has already been sent to this process. Sending a second
// one offers no real benefit, as processes cannot stop themselves from
// being terminated, once a TerminateProcess has been issued. Sending a
// second kill may result in a number of errors (two of which detailed bellow)
// and which we can avoid handling.
return true, nil
}
// HCS serializes the signals sent to a target pid per compute system handle.
// To avoid SIGKILL being serialized behind other signals, we open a new compute
// system handle to deliver the kill signal.
// If the calls to opening a new compute system handle fail, we forcefully
// terminate the container itself so that no container is left behind
hcsSystem, err := OpenComputeSystem(ctx, process.system.id)
if err != nil {
// log error and force termination of container
log.G(ctx).WithField("err", err).Error("OpenComputeSystem() call failed")
err = process.system.Terminate(ctx)
// if the Terminate() call itself ever failed, log and return error
if err != nil {
log.G(ctx).WithField("err", err).Error("Terminate() call failed")
return false, err
}
process.system.Close()
return true, nil
}
defer hcsSystem.Close()
newProcessHandle, err := hcsSystem.OpenProcess(ctx, process.Pid())
if err != nil {
// Return true only if the target process has either already
// exited, or does not exist.
if IsAlreadyStopped(err) {
return true, nil
} else {
return false, err
}
}
defer newProcessHandle.Close()
resultJSON, err := vmcompute.HcsTerminateProcess(ctx, newProcessHandle.handle)
if err != nil {
// We still need to check these two cases, as processes may still be killed by an
// external actor (human operator, OOM, random script etc).
if errors.Is(err, os.ErrPermission) || IsAlreadyStopped(err) {
// There are two cases where it should be safe to ignore an error returned
// by HcsTerminateProcess. The first one is cause by the fact that
// HcsTerminateProcess ends up calling TerminateProcess in the context
// of a container. According to the TerminateProcess documentation:
// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-terminateprocess#remarks
// After a process has terminated, call to TerminateProcess with open
// handles to the process fails with ERROR_ACCESS_DENIED (5) error code.
// It's safe to ignore this error here. HCS should always have permissions
// to kill processes inside any container. So an ERROR_ACCESS_DENIED
// is unlikely to be anything else than what the ending remarks in the
// documentation states.
//
// The second case is generated by hcs itself, if for any reason HcsTerminateProcess
// is called twice in a very short amount of time. In such cases, hcs may return
// HCS_E_PROCESS_ALREADY_STOPPED.
return true, nil
}
}
events := processHcsResult(ctx, resultJSON)
delivered, err := newProcessHandle.processSignalResult(ctx, err)
if err != nil {
err = makeProcessError(newProcessHandle, operation, err, events)
}
process.killSignalDelivered = delivered
return delivered, err
}
// waitBackground waits for the process exit notification. Once received sets
// `process.waitError` (if any) and unblocks all `Wait` calls.
//
// This MUST be called exactly once per `process.handle` but `Wait` is safe to
// call multiple times.
func (process *Process) waitBackground() {
operation := "hcs::Process::waitBackground"
ctx, span := trace.StartSpan(context.Background(), operation)
defer span.End()
span.AddAttributes(
trace.StringAttribute("cid", process.SystemID()),
trace.Int64Attribute("pid", int64(process.processID)))
var (
err error
exitCode = -1
propertiesJSON string
resultJSON string
)
err = waitForNotification(ctx, process.callbackNumber, hcsNotificationProcessExited, nil)
if err != nil {
err = makeProcessError(process, operation, err, nil)
log.G(ctx).WithError(err).Error("failed wait")
} else {
process.handleLock.RLock()
defer process.handleLock.RUnlock()
// Make sure we didnt race with Close() here
if process.handle != 0 {
propertiesJSON, resultJSON, err = vmcompute.HcsGetProcessProperties(ctx, process.handle)
events := processHcsResult(ctx, resultJSON)
if err != nil {
err = makeProcessError(process, operation, err, events) //nolint:ineffassign
} else {
properties := &processStatus{}
err = json.Unmarshal([]byte(propertiesJSON), properties)
if err != nil {
err = makeProcessError(process, operation, err, nil) //nolint:ineffassign
} else {
if properties.LastWaitResult != 0 {
log.G(ctx).WithField("wait-result", properties.LastWaitResult).Warning("non-zero last wait result")
} else {
exitCode = int(properties.ExitCode)
}
}
}
}
}
log.G(ctx).WithField("exitCode", exitCode).Debug("process exited")
process.closedWaitOnce.Do(func() {
process.exitCode = exitCode
process.waitError = err
close(process.waitBlock)
})
oc.SetSpanStatus(span, err)
}
// Wait waits for the process to exit. If the process has already exited returns
// the pervious error (if any).
func (process *Process) Wait() error {
<-process.waitBlock
return process.waitError
}
// ResizeConsole resizes the console of the process.
func (process *Process) ResizeConsole(ctx context.Context, width, height uint16) error {
process.handleLock.RLock()
defer process.handleLock.RUnlock()
operation := "hcs::Process::ResizeConsole"
if process.handle == 0 {
return makeProcessError(process, operation, ErrAlreadyClosed, nil)
}
modifyRequest := processModifyRequest{
Operation: modifyConsoleSize,
ConsoleSize: &consoleSize{
Height: height,
Width: width,
},
}
modifyRequestb, err := json.Marshal(modifyRequest)
if err != nil {
return err
}
resultJSON, err := vmcompute.HcsModifyProcess(ctx, process.handle, string(modifyRequestb))
events := processHcsResult(ctx, resultJSON)
if err != nil {
return makeProcessError(process, operation, err, events)
}
return nil
}
// ExitCode returns the exit code of the process. The process must have
// already terminated.
func (process *Process) ExitCode() (int, error) {
select {
case <-process.waitBlock:
if process.waitError != nil {
return -1, process.waitError
}
return process.exitCode, nil
default:
return -1, makeProcessError(process, "hcs::Process::ExitCode", ErrInvalidProcessState, nil)
}
}
// StdioLegacy returns the stdin, stdout, and stderr pipes, respectively. Closing
// these pipes does not close the underlying pipes. Once returned, these pipes
// are the responsibility of the caller to close.
func (process *Process) StdioLegacy() (_ io.WriteCloser, _ io.ReadCloser, _ io.ReadCloser, err error) {
operation := "hcs::Process::StdioLegacy"
ctx, span := trace.StartSpan(context.Background(), operation)
defer span.End()
defer func() { oc.SetSpanStatus(span, err) }()
span.AddAttributes(
trace.StringAttribute("cid", process.SystemID()),
trace.Int64Attribute("pid", int64(process.processID)))
process.handleLock.RLock()
defer process.handleLock.RUnlock()
if process.handle == 0 {
return nil, nil, nil, makeProcessError(process, operation, ErrAlreadyClosed, nil)
}
process.stdioLock.Lock()
defer process.stdioLock.Unlock()
if process.hasCachedStdio {
stdin, stdout, stderr := process.stdin, process.stdout, process.stderr
process.stdin, process.stdout, process.stderr = nil, nil, nil
process.hasCachedStdio = false
return stdin, stdout, stderr, nil
}
processInfo, resultJSON, err := vmcompute.HcsGetProcessInfo(ctx, process.handle)
events := processHcsResult(ctx, resultJSON)
if err != nil {
return nil, nil, nil, makeProcessError(process, operation, err, events)
}
pipes, err := makeOpenFiles([]syscall.Handle{processInfo.StdInput, processInfo.StdOutput, processInfo.StdError})
if err != nil {
return nil, nil, nil, makeProcessError(process, operation, err, nil)
}
return pipes[0], pipes[1], pipes[2], nil
}
// Stdio returns the stdin, stdout, and stderr pipes, respectively.
// To close them, close the process handle.
func (process *Process) Stdio() (stdin io.Writer, stdout, stderr io.Reader) {
process.stdioLock.Lock()
defer process.stdioLock.Unlock()
return process.stdin, process.stdout, process.stderr
}
// CloseStdin closes the write side of the stdin pipe so that the process is
// notified on the read side that there is no more data in stdin.
func (process *Process) CloseStdin(ctx context.Context) error {
process.handleLock.RLock()
defer process.handleLock.RUnlock()
operation := "hcs::Process::CloseStdin"
if process.handle == 0 {
return makeProcessError(process, operation, ErrAlreadyClosed, nil)
}
modifyRequest := processModifyRequest{
Operation: modifyCloseHandle,
CloseHandle: &closeHandle{
Handle: stdIn,
},
}
modifyRequestb, err := json.Marshal(modifyRequest)
if err != nil {
return err
}
resultJSON, err := vmcompute.HcsModifyProcess(ctx, process.handle, string(modifyRequestb))
events := processHcsResult(ctx, resultJSON)
if err != nil {
return makeProcessError(process, operation, err, events)
}
process.stdioLock.Lock()
if process.stdin != nil {
process.stdin.Close()
process.stdin = nil
}
process.stdioLock.Unlock()
return nil
}
func (process *Process) CloseStdout(ctx context.Context) (err error) {
ctx, span := trace.StartSpan(ctx, "hcs::Process::CloseStdout") //nolint:ineffassign,staticcheck
defer span.End()
defer func() { oc.SetSpanStatus(span, err) }()
span.AddAttributes(
trace.StringAttribute("cid", process.SystemID()),
trace.Int64Attribute("pid", int64(process.processID)))
process.handleLock.Lock()
defer process.handleLock.Unlock()
if process.handle == 0 {
return nil
}
process.stdioLock.Lock()
defer process.stdioLock.Unlock()
if process.stdout != nil {
process.stdout.Close()
process.stdout = nil
}
return nil
}
func (process *Process) CloseStderr(ctx context.Context) (err error) {
ctx, span := trace.StartSpan(ctx, "hcs::Process::CloseStderr") //nolint:ineffassign,staticcheck
defer span.End()
defer func() { oc.SetSpanStatus(span, err) }()
span.AddAttributes(
trace.StringAttribute("cid", process.SystemID()),
trace.Int64Attribute("pid", int64(process.processID)))
process.handleLock.Lock()
defer process.handleLock.Unlock()
if process.handle == 0 {
return nil
}
process.stdioLock.Lock()
defer process.stdioLock.Unlock()
if process.stderr != nil {
process.stderr.Close()
process.stderr = nil
}
return nil
}
// Close cleans up any state associated with the process but does not kill
// or wait on it.
func (process *Process) Close() (err error) {
operation := "hcs::Process::Close"
ctx, span := trace.StartSpan(context.Background(), operation)
defer span.End()
defer func() { oc.SetSpanStatus(span, err) }()
span.AddAttributes(
trace.StringAttribute("cid", process.SystemID()),
trace.Int64Attribute("pid", int64(process.processID)))
process.handleLock.Lock()
defer process.handleLock.Unlock()
// Don't double free this
if process.handle == 0 {
return nil
}
process.stdioLock.Lock()
if process.stdin != nil {
process.stdin.Close()
process.stdin = nil
}
if process.stdout != nil {
process.stdout.Close()
process.stdout = nil
}
if process.stderr != nil {
process.stderr.Close()
process.stderr = nil
}
process.stdioLock.Unlock()
if err = process.unregisterCallback(ctx); err != nil {
return makeProcessError(process, operation, err, nil)
}
if err = vmcompute.HcsCloseProcess(ctx, process.handle); err != nil {
return makeProcessError(process, operation, err, nil)
}
process.handle = 0
process.closedWaitOnce.Do(func() {
process.exitCode = -1
process.waitError = ErrAlreadyClosed
close(process.waitBlock)
})
return nil
}
func (process *Process) registerCallback(ctx context.Context) error {
callbackContext := &notificationWatcherContext{
channels: newProcessChannels(),
systemID: process.SystemID(),
processID: process.processID,
}
callbackMapLock.Lock()
callbackNumber := nextCallback
nextCallback++
callbackMap[callbackNumber] = callbackContext
callbackMapLock.Unlock()
callbackHandle, err := vmcompute.HcsRegisterProcessCallback(ctx, process.handle, notificationWatcherCallback, callbackNumber)
if err != nil {
return err
}
callbackContext.handle = callbackHandle
process.callbackNumber = callbackNumber
return nil
}
func (process *Process) unregisterCallback(ctx context.Context) error {
callbackNumber := process.callbackNumber
callbackMapLock.RLock()
callbackContext := callbackMap[callbackNumber]
callbackMapLock.RUnlock()
if callbackContext == nil {
return nil
}
handle := callbackContext.handle
if handle == 0 {
return nil
}
// vmcompute.HcsUnregisterProcessCallback has its own synchronization to
// wait for all callbacks to complete. We must NOT hold the callbackMapLock.
err := vmcompute.HcsUnregisterProcessCallback(ctx, handle)
if err != nil {
return err
}
closeChannels(callbackContext.channels)
callbackMapLock.Lock()
delete(callbackMap, callbackNumber)
callbackMapLock.Unlock()
handle = 0 //nolint:ineffassign
return nil
}

View File

@ -1,250 +0,0 @@
package schema1
import (
"encoding/json"
"time"
"github.com/Microsoft/go-winio/pkg/guid"
hcsschema "github.com/Microsoft/hcsshim/internal/hcs/schema2"
)
// ProcessConfig is used as both the input of Container.CreateProcess
// and to convert the parameters to JSON for passing onto the HCS
type ProcessConfig struct {
ApplicationName string `json:",omitempty"`
CommandLine string `json:",omitempty"`
CommandArgs []string `json:",omitempty"` // Used by Linux Containers on Windows
User string `json:",omitempty"`
WorkingDirectory string `json:",omitempty"`
Environment map[string]string `json:",omitempty"`
EmulateConsole bool `json:",omitempty"`
CreateStdInPipe bool `json:",omitempty"`
CreateStdOutPipe bool `json:",omitempty"`
CreateStdErrPipe bool `json:",omitempty"`
ConsoleSize [2]uint `json:",omitempty"`
CreateInUtilityVm bool `json:",omitempty"` // Used by Linux Containers on Windows
OCISpecification *json.RawMessage `json:",omitempty"` // Used by Linux Containers on Windows
}
type Layer struct {
ID string
Path string
}
type MappedDir struct {
HostPath string
ContainerPath string
ReadOnly bool
BandwidthMaximum uint64
IOPSMaximum uint64
CreateInUtilityVM bool
// LinuxMetadata - Support added in 1803/RS4+.
LinuxMetadata bool `json:",omitempty"`
}
type MappedPipe struct {
HostPath string
ContainerPipeName string
}
type HvRuntime struct {
ImagePath string `json:",omitempty"`
SkipTemplate bool `json:",omitempty"`
LinuxInitrdFile string `json:",omitempty"` // File under ImagePath on host containing an initrd image for starting a Linux utility VM
LinuxKernelFile string `json:",omitempty"` // File under ImagePath on host containing a kernel for starting a Linux utility VM
LinuxBootParameters string `json:",omitempty"` // Additional boot parameters for starting a Linux Utility VM in initrd mode
BootSource string `json:",omitempty"` // "Vhd" for Linux Utility VM booting from VHD
WritableBootSource bool `json:",omitempty"` // Linux Utility VM booting from VHD
}
type MappedVirtualDisk struct {
HostPath string `json:",omitempty"` // Path to VHD on the host
ContainerPath string // Platform-specific mount point path in the container
CreateInUtilityVM bool `json:",omitempty"`
ReadOnly bool `json:",omitempty"`
Cache string `json:",omitempty"` // "" (Unspecified); "Disabled"; "Enabled"; "Private"; "PrivateAllowSharing"
AttachOnly bool `json:",omitempty"`
}
// AssignedDevice represents a device that has been directly assigned to a container
//
// NOTE: Support added in RS5
type AssignedDevice struct {
// InterfaceClassGUID of the device to assign to container.
InterfaceClassGUID string `json:"InterfaceClassGuid,omitempty"`
}
// ContainerConfig is used as both the input of CreateContainer
// and to convert the parameters to JSON for passing onto the HCS
type ContainerConfig struct {
SystemType string // HCS requires this to be hard-coded to "Container"
Name string // Name of the container. We use the docker ID.
Owner string `json:",omitempty"` // The management platform that created this container
VolumePath string `json:",omitempty"` // Windows volume path for scratch space. Used by Windows Server Containers only. Format \\?\\Volume{GUID}
IgnoreFlushesDuringBoot bool `json:",omitempty"` // Optimization hint for container startup in Windows
LayerFolderPath string `json:",omitempty"` // Where the layer folders are located. Used by Windows Server Containers only. Format %root%\windowsfilter\containerID
Layers []Layer // List of storage layers. Required for Windows Server and Hyper-V Containers. Format ID=GUID;Path=%root%\windowsfilter\layerID
Credentials string `json:",omitempty"` // Credentials information
ProcessorCount uint32 `json:",omitempty"` // Number of processors to assign to the container.
ProcessorWeight uint64 `json:",omitempty"` // CPU shares (relative weight to other containers with cpu shares). Range is from 1 to 10000. A value of 0 results in default shares.
ProcessorMaximum int64 `json:",omitempty"` // Specifies the portion of processor cycles that this container can use as a percentage times 100. Range is from 1 to 10000. A value of 0 results in no limit.
StorageIOPSMaximum uint64 `json:",omitempty"` // Maximum Storage IOPS
StorageBandwidthMaximum uint64 `json:",omitempty"` // Maximum Storage Bandwidth in bytes per second
StorageSandboxSize uint64 `json:",omitempty"` // Size in bytes that the container system drive should be expanded to if smaller
MemoryMaximumInMB int64 `json:",omitempty"` // Maximum memory available to the container in Megabytes
HostName string `json:",omitempty"` // Hostname
MappedDirectories []MappedDir `json:",omitempty"` // List of mapped directories (volumes/mounts)
MappedPipes []MappedPipe `json:",omitempty"` // List of mapped Windows named pipes
HvPartition bool // True if it a Hyper-V Container
NetworkSharedContainerName string `json:",omitempty"` // Name (ID) of the container that we will share the network stack with.
EndpointList []string `json:",omitempty"` // List of networking endpoints to be attached to container
HvRuntime *HvRuntime `json:",omitempty"` // Hyper-V container settings. Used by Hyper-V containers only. Format ImagePath=%root%\BaseLayerID\UtilityVM
Servicing bool `json:",omitempty"` // True if this container is for servicing
AllowUnqualifiedDNSQuery bool `json:",omitempty"` // True to allow unqualified DNS name resolution
DNSSearchList string `json:",omitempty"` // Comma seperated list of DNS suffixes to use for name resolution
ContainerType string `json:",omitempty"` // "Linux" for Linux containers on Windows. Omitted otherwise.
TerminateOnLastHandleClosed bool `json:",omitempty"` // Should HCS terminate the container once all handles have been closed
MappedVirtualDisks []MappedVirtualDisk `json:",omitempty"` // Array of virtual disks to mount at start
AssignedDevices []AssignedDevice `json:",omitempty"` // Array of devices to assign. NOTE: Support added in RS5
}
type ComputeSystemQuery struct {
IDs []string `json:"Ids,omitempty"`
Types []string `json:",omitempty"`
Names []string `json:",omitempty"`
Owners []string `json:",omitempty"`
}
type PropertyType string
const (
PropertyTypeStatistics PropertyType = "Statistics" // V1 and V2
PropertyTypeProcessList PropertyType = "ProcessList" // V1 and V2
PropertyTypeMappedVirtualDisk PropertyType = "MappedVirtualDisk" // Not supported in V2 schema call
PropertyTypeGuestConnection PropertyType = "GuestConnection" // V1 and V2. Nil return from HCS before RS5
)
type PropertyQuery struct {
PropertyTypes []PropertyType `json:",omitempty"`
}
// ContainerProperties holds the properties for a container and the processes running in that container
type ContainerProperties struct {
ID string `json:"Id"`
State string
Name string
SystemType string
RuntimeOSType string `json:"RuntimeOsType,omitempty"`
Owner string
SiloGUID string `json:"SiloGuid,omitempty"`
RuntimeID guid.GUID `json:"RuntimeId,omitempty"`
IsRuntimeTemplate bool `json:",omitempty"`
RuntimeImagePath string `json:",omitempty"`
Stopped bool `json:",omitempty"`
ExitType string `json:",omitempty"`
AreUpdatesPending bool `json:",omitempty"`
ObRoot string `json:",omitempty"`
Statistics Statistics `json:",omitempty"`
ProcessList []ProcessListItem `json:",omitempty"`
MappedVirtualDiskControllers map[int]MappedVirtualDiskController `json:",omitempty"`
GuestConnectionInfo GuestConnectionInfo `json:",omitempty"`
}
// MemoryStats holds the memory statistics for a container
type MemoryStats struct {
UsageCommitBytes uint64 `json:"MemoryUsageCommitBytes,omitempty"`
UsageCommitPeakBytes uint64 `json:"MemoryUsageCommitPeakBytes,omitempty"`
UsagePrivateWorkingSetBytes uint64 `json:"MemoryUsagePrivateWorkingSetBytes,omitempty"`
}
// ProcessorStats holds the processor statistics for a container
type ProcessorStats struct {
TotalRuntime100ns uint64 `json:",omitempty"`
RuntimeUser100ns uint64 `json:",omitempty"`
RuntimeKernel100ns uint64 `json:",omitempty"`
}
// StorageStats holds the storage statistics for a container
type StorageStats struct {
ReadCountNormalized uint64 `json:",omitempty"`
ReadSizeBytes uint64 `json:",omitempty"`
WriteCountNormalized uint64 `json:",omitempty"`
WriteSizeBytes uint64 `json:",omitempty"`
}
// NetworkStats holds the network statistics for a container
type NetworkStats struct {
BytesReceived uint64 `json:",omitempty"`
BytesSent uint64 `json:",omitempty"`
PacketsReceived uint64 `json:",omitempty"`
PacketsSent uint64 `json:",omitempty"`
DroppedPacketsIncoming uint64 `json:",omitempty"`
DroppedPacketsOutgoing uint64 `json:",omitempty"`
EndpointId string `json:",omitempty"`
InstanceId string `json:",omitempty"`
}
// Statistics is the structure returned by a statistics call on a container
type Statistics struct {
Timestamp time.Time `json:",omitempty"`
ContainerStartTime time.Time `json:",omitempty"`
Uptime100ns uint64 `json:",omitempty"`
Memory MemoryStats `json:",omitempty"`
Processor ProcessorStats `json:",omitempty"`
Storage StorageStats `json:",omitempty"`
Network []NetworkStats `json:",omitempty"`
}
// ProcessList is the structure of an item returned by a ProcessList call on a container
type ProcessListItem struct {
CreateTimestamp time.Time `json:",omitempty"`
ImageName string `json:",omitempty"`
KernelTime100ns uint64 `json:",omitempty"`
MemoryCommitBytes uint64 `json:",omitempty"`
MemoryWorkingSetPrivateBytes uint64 `json:",omitempty"`
MemoryWorkingSetSharedBytes uint64 `json:",omitempty"`
ProcessId uint32 `json:",omitempty"`
UserTime100ns uint64 `json:",omitempty"`
}
// MappedVirtualDiskController is the structure of an item returned by a MappedVirtualDiskList call on a container
type MappedVirtualDiskController struct {
MappedVirtualDisks map[int]MappedVirtualDisk `json:",omitempty"`
}
// GuestDefinedCapabilities is part of the GuestConnectionInfo returned by a GuestConnection call on a utility VM
type GuestDefinedCapabilities struct {
NamespaceAddRequestSupported bool `json:",omitempty"`
SignalProcessSupported bool `json:",omitempty"`
DumpStacksSupported bool `json:",omitempty"`
DeleteContainerStateSupported bool `json:",omitempty"`
UpdateContainerSupported bool `json:",omitempty"`
}
// GuestConnectionInfo is the structure of an iterm return by a GuestConnection call on a utility VM
type GuestConnectionInfo struct {
SupportedSchemaVersions []hcsschema.Version `json:",omitempty"`
ProtocolVersion uint32 `json:",omitempty"`
GuestDefinedCapabilities GuestDefinedCapabilities `json:",omitempty"`
}
// Type of Request Support in ModifySystem
type RequestType string
// Type of Resource Support in ModifySystem
type ResourceType string
// RequestType const
const (
Add RequestType = "Add"
Remove RequestType = "Remove"
Network ResourceType = "Network"
)
// ResourceModificationRequestResponse is the structure used to send request to the container to modify the system
// Supported resource types are Network and Request Types are Add/Remove
type ResourceModificationRequestResponse struct {
Resource ResourceType `json:"ResourceType"`
Data interface{} `json:"Settings"`
Request RequestType `json:"RequestType,omitempty"`
}

View File

@ -1,36 +0,0 @@
/*
* HCS API
*
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
*
* API version: 2.1
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
*/
package hcsschema
type Attachment struct {
Type_ string `json:"Type,omitempty"`
Path string `json:"Path,omitempty"`
IgnoreFlushes bool `json:"IgnoreFlushes,omitempty"`
CachingMode string `json:"CachingMode,omitempty"`
NoWriteHardening bool `json:"NoWriteHardening,omitempty"`
DisableExpansionOptimization bool `json:"DisableExpansionOptimization,omitempty"`
IgnoreRelativeLocator bool `json:"IgnoreRelativeLocator,omitempty"`
CaptureIoAttributionContext bool `json:"CaptureIoAttributionContext,omitempty"`
ReadOnly bool `json:"ReadOnly,omitempty"`
SupportCompressedVolumes bool `json:"SupportCompressedVolumes,omitempty"`
AlwaysAllowSparseFiles bool `json:"AlwaysAllowSparseFiles,omitempty"`
ExtensibleVirtualDiskType string `json:"ExtensibleVirtualDiskType,omitempty"`
}

View File

@ -1,13 +0,0 @@
/*
* HCS API
*
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
*
* API version: 2.1
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
*/
package hcsschema
type Battery struct {
}

View File

@ -1,18 +0,0 @@
/*
* HCS API
*
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
*
* API version: 2.1
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
*/
package hcsschema
type CacheQueryStatsResponse struct {
L3OccupancyBytes int32 `json:"L3OccupancyBytes,omitempty"`
L3TotalBwBytes int32 `json:"L3TotalBwBytes,omitempty"`
L3LocalBwBytes int32 `json:"L3LocalBwBytes,omitempty"`
}

View File

@ -1,27 +0,0 @@
/*
* HCS API
*
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
*
* API version: 2.1
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
*/
package hcsschema
type Chipset struct {
Uefi *Uefi `json:"Uefi,omitempty"`
IsNumLockDisabled bool `json:"IsNumLockDisabled,omitempty"`
BaseBoardSerialNumber string `json:"BaseBoardSerialNumber,omitempty"`
ChassisSerialNumber string `json:"ChassisSerialNumber,omitempty"`
ChassisAssetTag string `json:"ChassisAssetTag,omitempty"`
UseUtc bool `json:"UseUtc,omitempty"`
// LinuxKernelDirect - Added in v2.2 Builds >=181117
LinuxKernelDirect *LinuxKernelDirect `json:"LinuxKernelDirect,omitempty"`
}

View File

@ -1,14 +0,0 @@
/*
* HCS API
*
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
*
* API version: 2.1
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
*/
package hcsschema
type CloseHandle struct {
Handle string `json:"Handle,omitempty"`
}

View File

@ -1,17 +0,0 @@
/*
* HCS API
*
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
*
* API version: 2.1
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
*/
package hcsschema
// ComPort specifies the named pipe that will be used for the port, with empty string indicating a disconnected port.
type ComPort struct {
NamedPipe string `json:"NamedPipe,omitempty"`
OptimizeForDebugger bool `json:"OptimizeForDebugger,omitempty"`
}

View File

@ -1,26 +0,0 @@
/*
* HCS API
*
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
*
* API version: 2.1
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
*/
package hcsschema
type ComputeSystem struct {
Owner string `json:"Owner,omitempty"`
SchemaVersion *Version `json:"SchemaVersion,omitempty"`
HostingSystemId string `json:"HostingSystemId,omitempty"`
HostedSystem interface{} `json:"HostedSystem,omitempty"`
Container *Container `json:"Container,omitempty"`
VirtualMachine *VirtualMachine `json:"VirtualMachine,omitempty"`
ShouldTerminateOnLastHandleClosed bool `json:"ShouldTerminateOnLastHandleClosed,omitempty"`
}

View File

@ -1,72 +0,0 @@
/*
* HCS API
*
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
*
* API version: 2.1
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
*/
package hcsschema
import (
"net/http"
)
// contextKeys are used to identify the type of value in the context.
// Since these are string, it is possible to get a short description of the
// context key for logging and debugging using key.String().
type contextKey string
func (c contextKey) String() string {
return "auth " + string(c)
}
var (
// ContextOAuth2 takes a oauth2.TokenSource as authentication for the request.
ContextOAuth2 = contextKey("token")
// ContextBasicAuth takes BasicAuth as authentication for the request.
ContextBasicAuth = contextKey("basic")
// ContextAccessToken takes a string oauth2 access token as authentication for the request.
ContextAccessToken = contextKey("accesstoken")
// ContextAPIKey takes an APIKey as authentication for the request
ContextAPIKey = contextKey("apikey")
)
// BasicAuth provides basic http authentication to a request passed via context using ContextBasicAuth
type BasicAuth struct {
UserName string `json:"userName,omitempty"`
Password string `json:"password,omitempty"`
}
// APIKey provides API key based authentication to a request passed via context using ContextAPIKey
type APIKey struct {
Key string
Prefix string
}
type Configuration struct {
BasePath string `json:"basePath,omitempty"`
Host string `json:"host,omitempty"`
Scheme string `json:"scheme,omitempty"`
DefaultHeader map[string]string `json:"defaultHeader,omitempty"`
UserAgent string `json:"userAgent,omitempty"`
HTTPClient *http.Client
}
func NewConfiguration() *Configuration {
cfg := &Configuration{
BasePath: "https://localhost",
DefaultHeader: make(map[string]string),
UserAgent: "Swagger-Codegen/2.1.0/go",
}
return cfg
}
func (c *Configuration) AddDefaultHeader(key string, value string) {
c.DefaultHeader[key] = value
}

View File

@ -1,16 +0,0 @@
/*
* HCS API
*
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
*
* API version: 2.1
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
*/
package hcsschema
type ConsoleSize struct {
Height int32 `json:"Height,omitempty"`
Width int32 `json:"Width,omitempty"`
}

View File

@ -1,36 +0,0 @@
/*
* HCS API
*
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
*
* API version: 2.1
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
*/
package hcsschema
type Container struct {
GuestOs *GuestOs `json:"GuestOs,omitempty"`
Storage *Storage `json:"Storage,omitempty"`
MappedDirectories []MappedDirectory `json:"MappedDirectories,omitempty"`
MappedPipes []MappedPipe `json:"MappedPipes,omitempty"`
Memory *Memory `json:"Memory,omitempty"`
Processor *Processor `json:"Processor,omitempty"`
Networking *Networking `json:"Networking,omitempty"`
HvSocket *HvSocket `json:"HvSocket,omitempty"`
ContainerCredentialGuard *ContainerCredentialGuardState `json:"ContainerCredentialGuard,omitempty"`
RegistryChanges *RegistryChanges `json:"RegistryChanges,omitempty"`
AssignedDevices []Device `json:"AssignedDevices,omitempty"`
AdditionalDeviceNamespace *ContainerDefinitionDevice `json:"AdditionalDeviceNamespace,omitempty"`
}

View File

@ -1,16 +0,0 @@
/*
* HCS API
*
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
*
* API version: 2.4
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
*/
package hcsschema
type ContainerCredentialGuardAddInstanceRequest struct {
Id string `json:"Id,omitempty"`
CredentialSpec string `json:"CredentialSpec,omitempty"`
Transport string `json:"Transport,omitempty"`
}

View File

@ -1,15 +0,0 @@
/*
* HCS API
*
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
*
* API version: 2.4
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
*/
package hcsschema
type ContainerCredentialGuardHvSocketServiceConfig struct {
ServiceId string `json:"ServiceId,omitempty"`
ServiceConfig *HvSocketServiceConfig `json:"ServiceConfig,omitempty"`
}

View File

@ -1,16 +0,0 @@
/*
* HCS API
*
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
*
* API version: 2.4
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
*/
package hcsschema
type ContainerCredentialGuardInstance struct {
Id string `json:"Id,omitempty"`
CredentialGuard *ContainerCredentialGuardState `json:"CredentialGuard,omitempty"`
HvSocketConfig *ContainerCredentialGuardHvSocketServiceConfig `json:"HvSocketConfig,omitempty"`
}

View File

@ -1,17 +0,0 @@
/*
* HCS API
*
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
*
* API version: 2.4
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
*/
package hcsschema
type ContainerCredentialGuardModifyOperation string
const (
AddInstance ContainerCredentialGuardModifyOperation = "AddInstance"
RemoveInstance ContainerCredentialGuardModifyOperation = "RemoveInstance"
)

View File

@ -1,15 +0,0 @@
/*
* HCS API
*
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
*
* API version: 2.4
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
*/
package hcsschema
type ContainerCredentialGuardOperationRequest struct {
Operation ContainerCredentialGuardModifyOperation `json:"Operation,omitempty"`
OperationDetails interface{} `json:"OperationDetails,omitempty"`
}

View File

@ -1,14 +0,0 @@
/*
* HCS API
*
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
*
* API version: 2.4
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
*/
package hcsschema
type ContainerCredentialGuardRemoveInstanceRequest struct {
Id string `json:"Id,omitempty"`
}

View File

@ -1,25 +0,0 @@
/*
* HCS API
*
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
*
* API version: 2.1
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
*/
package hcsschema
type ContainerCredentialGuardState struct {
// Authentication cookie for calls to a Container Credential Guard instance.
Cookie string `json:"Cookie,omitempty"`
// Name of the RPC endpoint of the Container Credential Guard instance.
RpcEndpoint string `json:"RpcEndpoint,omitempty"`
// Transport used for the configured Container Credential Guard instance.
Transport string `json:"Transport,omitempty"`
// Credential spec used for the configured Container Credential Guard instance.
CredentialSpec string `json:"CredentialSpec,omitempty"`
}

View File

@ -1,14 +0,0 @@
/*
* HCS API
*
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
*
* API version: 2.4
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
*/
package hcsschema
type ContainerCredentialGuardSystemInfo struct {
Instances []ContainerCredentialGuardInstance `json:"Instances,omitempty"`
}

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