From 403cffd8d44d4790a1c13d36e709beadeffc767e Mon Sep 17 00:00:00 2001 From: ksubrmnn Date: Thu, 31 Jan 2019 16:20:37 -0800 Subject: [PATCH] Update hcsshim for HostRoute policy in Windows VXLAN --- glide.lock | 2 +- glide.yaml | 1 - .../github.com/Microsoft/hcsshim/appveyor.yml | 17 +- .../Microsoft/hcsshim/cmd/go-runhcs/NOTICE | 22 - .../Microsoft/hcsshim/cmd/go-runhcs/runhcs.go | 125 - .../cmd/go-runhcs/runhcs_create-scratch.go | 10 - .../go-runhcs/runhcs_create-scratch_test.go | 65 - .../hcsshim/cmd/go-runhcs/runhcs_create.go | 91 - .../hcsshim/cmd/go-runhcs/runhcs_delete.go | 33 - .../hcsshim/cmd/go-runhcs/runhcs_exec.go | 82 - .../hcsshim/cmd/go-runhcs/runhcs_kill.go | 11 - .../hcsshim/cmd/go-runhcs/runhcs_list.go | 28 - .../hcsshim/cmd/go-runhcs/runhcs_list_test.go | 23 - .../hcsshim/cmd/go-runhcs/runhcs_pause.go | 10 - .../hcsshim/cmd/go-runhcs/runhcs_ps.go | 20 - .../cmd/go-runhcs/runhcs_resize-tty.go | 33 - .../hcsshim/cmd/go-runhcs/runhcs_resume.go | 10 - .../hcsshim/cmd/go-runhcs/runhcs_start.go | 10 - .../hcsshim/cmd/go-runhcs/runhcs_state.go | 20 - .../hcsshim/cmd/go-runhcs/runhcs_test.go | 103 - .../Microsoft/hcsshim/cmd/runhcs/container.go | 147 +- .../hcsshim/cmd/runhcs/create-scratch.go | 11 +- .../Microsoft/hcsshim/cmd/runhcs/kill.go | 31 +- .../Microsoft/hcsshim/cmd/runhcs/kill_test.go | 50 +- .../Microsoft/hcsshim/cmd/runhcs/main.go | 10 +- .../Microsoft/hcsshim/cmd/runhcs/tar2vhd.go | 120 - .../Microsoft/hcsshim/functional/manifest.go | 3 - .../github.com/Microsoft/hcsshim/hcn/hcn.go | 27 + .../Microsoft/hcsshim/hcn/hcnendpoint.go | 6 +- .../Microsoft/hcsshim/hcn/hcnendpoint_test.go | 38 +- .../Microsoft/hcsshim/hcn/hcnglobals.go | 6 + .../Microsoft/hcsshim/hcn/hcnloadbalancer.go | 64 +- .../hcsshim/hcn/hcnloadbalancer_test.go | 61 +- .../Microsoft/hcsshim/hcn/hcnnamespace.go | 6 +- .../hcsshim/hcn/hcnnamespace_test.go | 40 +- .../Microsoft/hcsshim/hcn/hcnnetwork.go | 19 +- .../Microsoft/hcsshim/hcn/hcnnetwork_test.go | 93 +- .../Microsoft/hcsshim/hcn/hcnpolicy.go | 1 + .../Microsoft/hcsshim/hcn/hcnsupport.go | 11 +- .../Microsoft/hcsshim/hcn/hcnsupport_test.go | 39 +- .../Microsoft/hcsshim/hcn/hcnutils_test.go | 16 +- .../Microsoft/hcsshim/hcn/hcnv1schema_test.go | 6 +- .../internal/cmd/createuvm/createuvm.go | 37 - .../internal/cmd/rootfs2vhd/rootfs2vhd.go | 210 -- .../hcsshim/internal/guestrequest/types.go | 17 +- .../Microsoft/hcsshim/internal/hcs/process.go | 21 +- .../Microsoft/hcsshim/internal/hcs/system.go | 114 +- .../Microsoft/hcsshim/internal/hcs/watcher.go | 32 +- .../hcsshim/internal/hcsoci/hcsdoc_lcow.go | 12 +- .../hcsshim/internal/hns/hnsendpoint.go | 2 + .../hcsshim/internal/osversion/osversion.go | 51 - .../internal/osversion/windowsbuilds.go | 11 - .../hcsshim/internal/schema2/plan9_share.go | 7 + .../internal/schema2/virtual_machine.go | 3 + .../schemaversion/schemaversion_test.go | 2 +- .../Microsoft/hcsshim/internal/uvm/create.go | 22 +- .../hcsshim/internal/uvm/create_lcow.go | 269 +- .../hcsshim/internal/uvm/create_test.go | 10 +- .../hcsshim/internal/uvm/create_wcow.go | 53 +- .../Microsoft/hcsshim/internal/uvm/network.go | 44 +- .../Microsoft/hcsshim/internal/uvm/plan9.go | 23 +- .../Microsoft/hcsshim/internal/uvm/start.go | 40 +- .../Microsoft/hcsshim/internal/uvm/types.go | 8 +- .../Microsoft/hcsshim/internal/uvm/wait.go | 19 + .../Microsoft/hcsshim/pkg/go-runhcs/runhcs.go | 19 +- .../pkg/go-runhcs/runhcs_integration_test.go | 7 - .../functional/assets/defaultlinuxspec.json | 0 .../functional/assets/defaultwindowsspec.json | 0 .../samples/config.justin.lcow.working.json | 0 .../samples/from-docker-linux/privileged.json | 0 .../assets/samples/from-docker-linux/sh.json | 0 .../{ => test}/functional/lcow_test.go | 56 +- .../functional/manifest/manifest.go | 0 .../functional/manifest/rsrc_amd64.syso | Bin .../hcsshim/test/functional/manifest_test.go | 3 + .../hcsshim/{ => test}/functional/test.go | 0 .../functional/utilities/createuvm.go | 15 +- .../functional/utilities/defaultlinuxspec.go | 0 .../utilities/defaultwindowsspec.go | 0 .../functional/utilities/layerfolders.go | 0 .../functional/utilities/requiresbuild.go | 0 .../functional/utilities/scratch.go | 0 .../functional/utilities/tempdir.go | 0 .../functional/uvm_mem_backingtype_test.go | 59 +- .../functional/uvm_plannine_test.go | 2 +- .../functional/uvm_properties_test.go | 2 +- .../{ => test}/functional/uvm_scratch_test.go | 2 +- .../{ => test}/functional/uvm_scsi_test.go | 2 +- .../{ => test}/functional/uvm_vpmem_test.go | 2 +- .../{ => test}/functional/uvm_vsmb_test.go | 2 +- .../{ => test}/functional/wcow_test.go | 12 +- .../functional/wcow_xenon_v2_test.go | 2 +- .../runhcs/create-scratch_test.go} | 8 +- .../runhcs/e2e_matrix_test.go} | 9 +- .../runhcs/list_test.go} | 4 +- .../hcsshim/test/runhcs/runhcs_test.go | 7 + .../Microsoft/hcsshim/tools/uvmboot/main.go | 55 +- .../github.com/Microsoft/hcsshim/vendor.conf | 21 + .../github.com/Microsoft/go-winio/LICENSE | 22 + .../github.com/Microsoft/go-winio/README.md | 22 + .../Microsoft/go-winio/archive/tar/LICENSE | 27 + .../Microsoft/go-winio/archive/tar/common.go | 344 ++ .../Microsoft/go-winio/archive/tar/reader.go | 1002 ++++++ .../go-winio/archive/tar/stat_atim.go | 20 + .../go-winio/archive/tar/stat_atimespec.go | 20 + .../go-winio/archive/tar/stat_unix.go | 32 + .../Microsoft/go-winio/archive/tar/writer.go | 444 +++ .../github.com/Microsoft/go-winio/backup.go | 280 ++ .../Microsoft/go-winio/backuptar/noop.go | 4 + .../Microsoft/go-winio/backuptar/tar.go | 439 +++ .../github.com/Microsoft/go-winio/ea.go | 137 + .../github.com/Microsoft/go-winio/file.go | 307 ++ .../github.com/Microsoft/go-winio/fileinfo.go | 61 + .../Microsoft/go-winio/internal/etw/etw.go | 14 + .../go-winio/internal/etw/eventdata.go | 65 + .../internal/etw/eventdatadescriptor.go | 29 + .../go-winio/internal/etw/eventdescriptor.go | 67 + .../go-winio/internal/etw/eventmetadata.go | 177 ++ .../go-winio/internal/etw/eventopt.go | 57 + .../go-winio/internal/etw/fieldopt.go | 379 +++ .../go-winio/internal/etw/provider.go | 260 ++ .../go-winio/internal/etw/providerglobal.go | 52 + .../go-winio/internal/etw/ptr64_32.go | 16 + .../go-winio/internal/etw/ptr64_64.go | 15 + .../go-winio/internal/etw/zsyscall_windows.go | 69 + .../github.com/Microsoft/go-winio/pipe.go | 421 +++ .../Microsoft/go-winio/pkg/etwlogrus/hook.go | 192 ++ .../Microsoft/go-winio/privilege.go | 202 ++ .../github.com/Microsoft/go-winio/reparse.go | 128 + .../github.com/Microsoft/go-winio/sd.go | 98 + .../github.com/Microsoft/go-winio/syscall.go | 3 + .../github.com/Microsoft/go-winio/vhd/vhd.go | 108 + .../github.com/Microsoft/go-winio/vhd/zvhd.go | 99 + .../Microsoft/go-winio/zsyscall_windows.go | 520 +++ .../github.com/Microsoft/opengcs/LICENSE | 21 + .../github.com/Microsoft/opengcs/README.md | 14 + .../Microsoft/opengcs/client/config.go | 274 ++ .../opengcs/client/createext4vhdx.go | 167 + .../Microsoft/opengcs/client/hotaddvhd.go | 42 + .../Microsoft/opengcs/client/hotremovevhd.go | 36 + .../Microsoft/opengcs/client/init.go | 24 + .../opengcs/client/layervhddetails.go | 31 + .../Microsoft/opengcs/client/process.go | 164 + .../Microsoft/opengcs/client/tartovhd.go | 46 + .../Microsoft/opengcs/client/unsupported.go | 3 + .../Microsoft/opengcs/client/utilities.go | 122 + .../Microsoft/opengcs/client/vhdtotar.go | 69 + .../Microsoft/opengcs/vsockexec/vsockexec.c | 129 + .../vendor/github.com/blang/semver/LICENSE | 22 + .../vendor/github.com/blang/semver/README.md | 191 ++ .../vendor/github.com/blang/semver/json.go | 23 + .../vendor/github.com/blang/semver/range.go | 224 ++ .../vendor/github.com/blang/semver/semver.go | 395 +++ .../vendor/github.com/blang/semver/sort.go | 28 + .../vendor/github.com/blang/semver/sql.go | 30 + .../github.com/containerd/console}/LICENSE | 0 .../github.com/containerd/console/README.md | 17 + .../github.com/containerd/console/console.go | 78 + .../containerd/console/console_linux.go | 275 ++ .../containerd/console/console_unix.go | 158 + .../containerd/console/console_windows.go | 216 ++ .../containerd/console/tc_darwin.go | 53 + .../containerd/console/tc_freebsd.go | 45 + .../github.com/containerd/console/tc_linux.go | 49 + .../containerd/console/tc_openbsd_cgo.go | 51 + .../containerd/console/tc_openbsd_nocgo.go | 47 + .../containerd/console/tc_solaris_cgo.go | 51 + .../containerd/console/tc_solaris_nocgo.go | 47 + .../github.com/containerd/console/tc_unix.go | 91 + .../github.com/containerd/go-runc/LICENSE | 201 ++ .../github.com/containerd/go-runc/README.md | 14 + .../containerd/go-runc/command_linux.go | 41 + .../containerd/go-runc/command_other.go | 35 + .../github.com/containerd/go-runc/console.go | 165 + .../containerd/go-runc/container.go | 30 + .../github.com/containerd/go-runc/events.go | 100 + .../github.com/containerd/go-runc/io.go | 218 ++ .../github.com/containerd/go-runc/io_unix.go | 76 + .../containerd/go-runc/io_windows.go | 62 + .../github.com/containerd/go-runc/monitor.go | 76 + .../github.com/containerd/go-runc/runc.go | 707 +++++ .../github.com/containerd/go-runc/utils.go | 107 + .../github.com/hashicorp/errwrap/LICENSE | 354 +++ .../github.com/hashicorp/errwrap/README.md | 89 + .../github.com/hashicorp/errwrap/errwrap.go | 169 + .../hashicorp/go-multierror/LICENSE | 353 +++ .../hashicorp/go-multierror/README.md | 97 + .../hashicorp/go-multierror/append.go | 41 + .../hashicorp/go-multierror/flatten.go | 26 + .../hashicorp/go-multierror/format.go | 27 + .../hashicorp/go-multierror/multierror.go | 51 + .../hashicorp/go-multierror/prefix.go | 37 + .../go-windows-terminal-sequences/LICENSE | 9 + .../go-windows-terminal-sequences/README.md | 40 + .../sequences.go | 36 + .../github.com/linuxkit/virtsock/LICENSE | 16 + .../github.com/linuxkit/virtsock/README.md | 100 + .../github.com/linuxkit/virtsock/c/README.md | 48 + .../github.com/linuxkit/virtsock/c/compat.h | 365 +++ .../github.com/linuxkit/virtsock/c/hvbench.c | 552 ++++ .../github.com/linuxkit/virtsock/c/hvecho.c | 331 ++ .../github.com/linuxkit/virtsock/c/hvstress.c | 607 ++++ .../linuxkit/virtsock/pkg/hvsock/hvsock.go | 115 + .../virtsock/pkg/hvsock/hvsock_fallback.go | 22 + .../virtsock/pkg/hvsock/hvsock_linux.go | 262 ++ .../virtsock/pkg/hvsock/hvsock_windows.go | 496 +++ .../virtsock/pkg/hvsock/zsyscall_windows.go | 171 + .../github.com/linuxkit/virtsock/vendor.conf | 2 + .../opencontainers/runtime-spec/LICENSE | 191 ++ .../opencontainers/runtime-spec/README.md | 153 + .../runtime-spec/specs-go/config.go | 632 ++++ .../runtime-spec/specs-go/state.go | 17 + .../runtime-spec/specs-go/version.go | 18 + .../opencontainers/runtime-tools/LICENSE | 191 ++ .../opencontainers/runtime-tools/README.md | 128 + .../runtime-tools/error/error.go | 122 + .../runtime-tools/filepath/abs.go | 48 + .../runtime-tools/filepath/ancestor.go | 32 + .../runtime-tools/filepath/clean.go | 74 + .../runtime-tools/filepath/doc.go | 6 + .../runtime-tools/filepath/join.go | 9 + .../runtime-tools/filepath/separator.go | 9 + .../runtime-tools/generate/config.go | 180 ++ .../runtime-tools/generate/generate.go | 1588 ++++++++++ .../runtime-tools/generate/seccomp/consts.go | 12 + .../generate/seccomp/parse_action.go | 135 + .../generate/seccomp/parse_architecture.go | 55 + .../generate/seccomp/parse_arguments.go | 73 + .../generate/seccomp/parse_remove.go | 52 + .../generate/seccomp/seccomp_default.go | 576 ++++ .../generate/seccomp/seccomp_default_linux.go | 15 + .../seccomp/seccomp_default_unsupported.go | 15 + .../generate/seccomp/syscall_compare.go | 140 + .../runtime-tools/specerror/bundle.go | 29 + .../runtime-tools/specerror/config-linux.go | 134 + .../runtime-tools/specerror/config-windows.go | 32 + .../runtime-tools/specerror/config.go | 188 ++ .../runtime-tools/specerror/error.go | 152 + .../runtime-tools/specerror/runtime-linux.go | 23 + .../runtime-tools/specerror/runtime.go | 179 ++ .../runtime-tools/validate/validate.go | 838 +++++ .../runtime-tools/validate/validate_linux.go | 230 ++ .../validate/validate_unsupported.go | 17 + .../vendor/github.com/pkg/errors/LICENSE | 23 + .../vendor/github.com/pkg/errors/README.md | 52 + .../vendor/github.com/pkg/errors/errors.go | 282 ++ .../vendor/github.com/pkg/errors/stack.go | 147 + .../vendor/github.com/sirupsen/logrus/LICENSE | 21 + .../github.com/sirupsen/logrus/README.md | 494 +++ .../github.com/sirupsen/logrus/alt_exit.go | 64 + .../vendor/github.com/sirupsen/logrus/doc.go | 26 + .../github.com/sirupsen/logrus/entry.go | 393 +++ .../github.com/sirupsen/logrus/exported.go | 219 ++ .../github.com/sirupsen/logrus/formatter.go | 78 + .../github.com/sirupsen/logrus/hooks.go | 34 + .../sirupsen/logrus/json_formatter.go | 105 + .../github.com/sirupsen/logrus/logger.go | 343 ++ .../github.com/sirupsen/logrus/logrus.go | 186 ++ .../sirupsen/logrus/terminal_check_aix.go | 9 + .../logrus/terminal_check_appengine.go | 11 + .../sirupsen/logrus/terminal_check_js.go | 11 + .../logrus/terminal_check_notappengine.go | 19 + .../sirupsen/logrus/terminal_check_windows.go | 20 + .../sirupsen/logrus/terminal_notwindows.go | 8 + .../sirupsen/logrus/terminal_windows.go | 18 + .../sirupsen/logrus/text_formatter.go | 273 ++ .../github.com/sirupsen/logrus/writer.go | 64 + .../github.com/syndtr/gocapability/LICENSE | 24 + .../gocapability/capability/capability.go | 72 + .../capability/capability_linux.go | 650 ++++ .../capability/capability_noop.go | 19 + .../syndtr/gocapability/capability/enum.go | 268 ++ .../gocapability/capability/enum_gen.go | 129 + .../gocapability/capability/syscall_linux.go | 154 + .../vendor/github.com/urfave/cli/LICENSE | 21 + .../vendor/github.com/urfave/cli/README.md | 1391 ++++++++ .../vendor/github.com/urfave/cli/app.go | 509 +++ .../vendor/github.com/urfave/cli/category.go | 44 + .../vendor/github.com/urfave/cli/cli.go | 22 + .../vendor/github.com/urfave/cli/command.go | 304 ++ .../vendor/github.com/urfave/cli/context.go | 278 ++ .../vendor/github.com/urfave/cli/errors.go | 115 + .../vendor/github.com/urfave/cli/flag.go | 807 +++++ .../github.com/urfave/cli/flag_generated.go | 627 ++++ .../vendor/github.com/urfave/cli/funcs.go | 41 + .../vendor/github.com/urfave/cli/help.go | 339 ++ .../gojsonpointer/LICENSE-APACHE-2.0.txt | 202 ++ .../xeipuuv/gojsonpointer/README.md | 41 + .../xeipuuv/gojsonpointer/pointer.go | 211 ++ .../gojsonreference/LICENSE-APACHE-2.0.txt | 202 ++ .../xeipuuv/gojsonreference/README.md | 10 + .../xeipuuv/gojsonreference/reference.go | 147 + .../gojsonschema/LICENSE-APACHE-2.0.txt | 202 ++ .../github.com/xeipuuv/gojsonschema/README.md | 351 ++ .../github.com/xeipuuv/gojsonschema/errors.go | 324 ++ .../xeipuuv/gojsonschema/format_checkers.go | 250 ++ .../xeipuuv/gojsonschema/internalLog.go | 37 + .../xeipuuv/gojsonschema/jsonContext.go | 72 + .../xeipuuv/gojsonschema/jsonLoader.go | 364 +++ .../xeipuuv/gojsonschema/locales.go | 313 ++ .../github.com/xeipuuv/gojsonschema/result.go | 195 ++ .../github.com/xeipuuv/gojsonschema/schema.go | 1034 ++++++ .../xeipuuv/gojsonschema/schemaPool.go | 192 ++ .../gojsonschema/schemaReferencePool.go | 68 + .../xeipuuv/gojsonschema/schemaType.go | 83 + .../xeipuuv/gojsonschema/subSchema.go | 255 ++ .../github.com/xeipuuv/gojsonschema/types.go | 58 + .../github.com/xeipuuv/gojsonschema/utils.go | 226 ++ .../xeipuuv/gojsonschema/validation.go | 930 ++++++ .../vendor/golang.org/x/crypto/LICENSE | 27 + .../vendor/golang.org/x/crypto/PATENTS | 22 + .../vendor/golang.org/x/crypto/README.md | 21 + .../x/crypto/curve25519/const_amd64.h | 8 + .../x/crypto/curve25519/const_amd64.s | 20 + .../x/crypto/curve25519/cswap_amd64.s | 65 + .../x/crypto/curve25519/curve25519.go | 834 +++++ .../golang.org/x/crypto/curve25519/doc.go | 23 + .../x/crypto/curve25519/freeze_amd64.s | 73 + .../x/crypto/curve25519/ladderstep_amd64.s | 1377 ++++++++ .../x/crypto/curve25519/mont25519_amd64.go | 240 ++ .../x/crypto/curve25519/mul_amd64.s | 169 + .../x/crypto/curve25519/square_amd64.s | 132 + .../x/crypto/otr/libotr_test_helper.c | 197 ++ .../vendor/golang.org/x/crypto/otr/otr.go | 1415 +++++++++ .../vendor/golang.org/x/crypto/otr/smp.go | 572 ++++ .../x/crypto/ssh/terminal/terminal.go | 951 ++++++ .../golang.org/x/crypto/ssh/terminal/util.go | 114 + .../x/crypto/ssh/terminal/util_aix.go | 12 + .../x/crypto/ssh/terminal/util_bsd.go | 12 + .../x/crypto/ssh/terminal/util_linux.go | 10 + .../x/crypto/ssh/terminal/util_plan9.go | 58 + .../x/crypto/ssh/terminal/util_solaris.go | 124 + .../x/crypto/ssh/terminal/util_windows.go | 103 + .../golang.org/x/crypto/ssh/test/doc.go | 7 + .../x/crypto/ssh/test/sshd_test_pw.c | 173 + .../hcsshim/vendor/golang.org/x/sync/LICENSE | 27 + .../hcsshim/vendor/golang.org/x/sync/PATENTS | 22 + .../vendor/golang.org/x/sync/README.md | 18 + .../golang.org/x/sync/errgroup/errgroup.go | 66 + .../hcsshim/vendor/golang.org/x/sys/LICENSE | 27 + .../hcsshim/vendor/golang.org/x/sys/PATENTS | 22 + .../hcsshim/vendor/golang.org/x/sys/README.md | 18 + .../vendor/golang.org/x/sys/cpu/cpu.go | 87 + .../vendor/golang.org/x/sys/cpu/cpu_arm.go | 9 + .../vendor/golang.org/x/sys/cpu/cpu_arm64.go | 67 + .../vendor/golang.org/x/sys/cpu/cpu_gc_x86.go | 16 + .../vendor/golang.org/x/sys/cpu/cpu_gccgo.c | 43 + .../vendor/golang.org/x/sys/cpu/cpu_gccgo.go | 26 + .../vendor/golang.org/x/sys/cpu/cpu_linux.go | 61 + .../golang.org/x/sys/cpu/cpu_mips64x.go | 11 + .../vendor/golang.org/x/sys/cpu/cpu_mipsx.go | 11 + .../vendor/golang.org/x/sys/cpu/cpu_ppc64x.go | 32 + .../vendor/golang.org/x/sys/cpu/cpu_s390x.go | 9 + .../vendor/golang.org/x/sys/cpu/cpu_x86.go | 55 + .../vendor/golang.org/x/sys/cpu/cpu_x86.s | 27 + .../vendor/golang.org/x/sys/unix/README.md | 173 + .../golang.org/x/sys/unix/affinity_linux.go | 124 + .../vendor/golang.org/x/sys/unix/aliases.go | 14 + .../golang.org/x/sys/unix/asm_aix_ppc64.s | 17 + .../golang.org/x/sys/unix/asm_darwin_386.s | 29 + .../golang.org/x/sys/unix/asm_darwin_amd64.s | 29 + .../golang.org/x/sys/unix/asm_darwin_arm.s | 30 + .../golang.org/x/sys/unix/asm_darwin_arm64.s | 30 + .../x/sys/unix/asm_dragonfly_amd64.s | 29 + .../golang.org/x/sys/unix/asm_freebsd_386.s | 29 + .../golang.org/x/sys/unix/asm_freebsd_amd64.s | 29 + .../golang.org/x/sys/unix/asm_freebsd_arm.s | 29 + .../golang.org/x/sys/unix/asm_freebsd_arm64.s | 29 + .../golang.org/x/sys/unix/asm_linux_386.s | 65 + .../golang.org/x/sys/unix/asm_linux_amd64.s | 57 + .../golang.org/x/sys/unix/asm_linux_arm.s | 56 + .../golang.org/x/sys/unix/asm_linux_arm64.s | 52 + .../golang.org/x/sys/unix/asm_linux_mips64x.s | 56 + .../golang.org/x/sys/unix/asm_linux_mipsx.s | 54 + .../golang.org/x/sys/unix/asm_linux_ppc64x.s | 44 + .../golang.org/x/sys/unix/asm_linux_s390x.s | 56 + .../golang.org/x/sys/unix/asm_netbsd_386.s | 29 + .../golang.org/x/sys/unix/asm_netbsd_amd64.s | 29 + .../golang.org/x/sys/unix/asm_netbsd_arm.s | 29 + .../golang.org/x/sys/unix/asm_openbsd_386.s | 29 + .../golang.org/x/sys/unix/asm_openbsd_amd64.s | 29 + .../golang.org/x/sys/unix/asm_openbsd_arm.s | 29 + .../golang.org/x/sys/unix/asm_solaris_amd64.s | 17 + .../golang.org/x/sys/unix/bluetooth_linux.go | 35 + .../golang.org/x/sys/unix/cap_freebsd.go | 195 ++ .../vendor/golang.org/x/sys/unix/constants.go | 13 + .../golang.org/x/sys/unix/dev_aix_ppc.go | 27 + .../golang.org/x/sys/unix/dev_aix_ppc64.go | 29 + .../golang.org/x/sys/unix/dev_darwin.go | 24 + .../golang.org/x/sys/unix/dev_dragonfly.go | 30 + .../golang.org/x/sys/unix/dev_freebsd.go | 30 + .../vendor/golang.org/x/sys/unix/dev_linux.go | 42 + .../golang.org/x/sys/unix/dev_netbsd.go | 29 + .../golang.org/x/sys/unix/dev_openbsd.go | 29 + .../vendor/golang.org/x/sys/unix/dirent.go | 17 + .../golang.org/x/sys/unix/endian_big.go | 9 + .../golang.org/x/sys/unix/endian_little.go | 9 + .../vendor/golang.org/x/sys/unix/env_unix.go | 31 + .../x/sys/unix/errors_freebsd_386.go | 227 ++ .../x/sys/unix/errors_freebsd_amd64.go | 227 ++ .../x/sys/unix/errors_freebsd_arm.go | 226 ++ .../vendor/golang.org/x/sys/unix/fcntl.go | 32 + .../golang.org/x/sys/unix/fcntl_darwin.go | 18 + .../x/sys/unix/fcntl_linux_32bit.go | 13 + .../vendor/golang.org/x/sys/unix/gccgo.go | 62 + .../vendor/golang.org/x/sys/unix/gccgo_c.c | 39 + .../x/sys/unix/gccgo_linux_amd64.go | 20 + .../vendor/golang.org/x/sys/unix/ioctl.go | 30 + .../golang.org/x/sys/unix/openbsd_pledge.go | 166 + .../golang.org/x/sys/unix/openbsd_unveil.go | 44 + .../golang.org/x/sys/unix/pagesize_unix.go | 15 + .../vendor/golang.org/x/sys/unix/race.go | 30 + .../vendor/golang.org/x/sys/unix/race0.go | 25 + .../golang.org/x/sys/unix/sockcmsg_linux.go | 36 + .../golang.org/x/sys/unix/sockcmsg_unix.go | 117 + .../vendor/golang.org/x/sys/unix/str.go | 26 + .../vendor/golang.org/x/sys/unix/syscall.go | 54 + .../golang.org/x/sys/unix/syscall_aix.go | 547 ++++ .../golang.org/x/sys/unix/syscall_aix_ppc.go | 34 + .../x/sys/unix/syscall_aix_ppc64.go | 34 + .../golang.org/x/sys/unix/syscall_bsd.go | 624 ++++ .../golang.org/x/sys/unix/syscall_darwin.go | 688 ++++ .../x/sys/unix/syscall_darwin_386.go | 63 + .../x/sys/unix/syscall_darwin_amd64.go | 63 + .../x/sys/unix/syscall_darwin_arm.go | 64 + .../x/sys/unix/syscall_darwin_arm64.go | 66 + .../x/sys/unix/syscall_darwin_libSystem.go | 31 + .../x/sys/unix/syscall_dragonfly.go | 539 ++++ .../x/sys/unix/syscall_dragonfly_amd64.go | 52 + .../golang.org/x/sys/unix/syscall_freebsd.go | 824 +++++ .../x/sys/unix/syscall_freebsd_386.go | 52 + .../x/sys/unix/syscall_freebsd_amd64.go | 52 + .../x/sys/unix/syscall_freebsd_arm.go | 52 + .../x/sys/unix/syscall_freebsd_arm64.go | 52 + .../golang.org/x/sys/unix/syscall_linux.go | 1704 ++++++++++ .../x/sys/unix/syscall_linux_386.go | 386 +++ .../x/sys/unix/syscall_linux_amd64.go | 190 ++ .../x/sys/unix/syscall_linux_amd64_gc.go | 13 + .../x/sys/unix/syscall_linux_arm.go | 268 ++ .../x/sys/unix/syscall_linux_arm64.go | 210 ++ .../golang.org/x/sys/unix/syscall_linux_gc.go | 14 + .../x/sys/unix/syscall_linux_gc_386.go | 16 + .../x/sys/unix/syscall_linux_gccgo_386.go | 30 + .../x/sys/unix/syscall_linux_gccgo_arm.go | 20 + .../x/sys/unix/syscall_linux_mips64x.go | 222 ++ .../x/sys/unix/syscall_linux_mipsx.go | 234 ++ .../x/sys/unix/syscall_linux_ppc64x.go | 152 + .../x/sys/unix/syscall_linux_riscv64.go | 213 ++ .../x/sys/unix/syscall_linux_s390x.go | 338 ++ .../x/sys/unix/syscall_linux_sparc64.go | 147 + .../golang.org/x/sys/unix/syscall_netbsd.go | 622 ++++ .../x/sys/unix/syscall_netbsd_386.go | 33 + .../x/sys/unix/syscall_netbsd_amd64.go | 33 + .../x/sys/unix/syscall_netbsd_arm.go | 33 + .../golang.org/x/sys/unix/syscall_openbsd.go | 399 +++ .../x/sys/unix/syscall_openbsd_386.go | 37 + .../x/sys/unix/syscall_openbsd_amd64.go | 37 + .../x/sys/unix/syscall_openbsd_arm.go | 37 + .../golang.org/x/sys/unix/syscall_solaris.go | 737 +++++ .../x/sys/unix/syscall_solaris_amd64.go | 23 + .../golang.org/x/sys/unix/syscall_unix.go | 379 +++ .../golang.org/x/sys/unix/syscall_unix_gc.go | 15 + .../x/sys/unix/syscall_unix_gc_ppc64x.go | 24 + .../golang.org/x/sys/unix/timestruct.go | 82 + .../vendor/golang.org/x/sys/unix/xattr_bsd.go | 240 ++ .../golang.org/x/sys/unix/zerrors_aix_ppc.go | 1372 ++++++++ .../x/sys/unix/zerrors_aix_ppc64.go | 1373 ++++++++ .../x/sys/unix/zerrors_darwin_386.go | 1783 +++++++++++ .../x/sys/unix/zerrors_darwin_amd64.go | 1783 +++++++++++ .../x/sys/unix/zerrors_darwin_arm.go | 1783 +++++++++++ .../x/sys/unix/zerrors_darwin_arm64.go | 1783 +++++++++++ .../x/sys/unix/zerrors_dragonfly_amd64.go | 1650 ++++++++++ .../x/sys/unix/zerrors_freebsd_386.go | 1793 +++++++++++ .../x/sys/unix/zerrors_freebsd_amd64.go | 1794 +++++++++++ .../x/sys/unix/zerrors_freebsd_arm.go | 1802 +++++++++++ .../x/sys/unix/zerrors_freebsd_arm64.go | 1794 +++++++++++ .../x/sys/unix/zerrors_linux_386.go | 2756 ++++++++++++++++ .../x/sys/unix/zerrors_linux_amd64.go | 2756 ++++++++++++++++ .../x/sys/unix/zerrors_linux_arm.go | 2762 ++++++++++++++++ .../x/sys/unix/zerrors_linux_arm64.go | 2747 ++++++++++++++++ .../x/sys/unix/zerrors_linux_mips.go | 2763 ++++++++++++++++ .../x/sys/unix/zerrors_linux_mips64.go | 2763 ++++++++++++++++ .../x/sys/unix/zerrors_linux_mips64le.go | 2763 ++++++++++++++++ .../x/sys/unix/zerrors_linux_mipsle.go | 2763 ++++++++++++++++ .../x/sys/unix/zerrors_linux_ppc64.go | 2818 +++++++++++++++++ .../x/sys/unix/zerrors_linux_ppc64le.go | 2818 +++++++++++++++++ .../x/sys/unix/zerrors_linux_riscv64.go | 2743 ++++++++++++++++ .../x/sys/unix/zerrors_linux_s390x.go | 2816 ++++++++++++++++ .../x/sys/unix/zerrors_linux_sparc64.go | 2812 ++++++++++++++++ .../x/sys/unix/zerrors_netbsd_386.go | 1772 +++++++++++ .../x/sys/unix/zerrors_netbsd_amd64.go | 1762 +++++++++++ .../x/sys/unix/zerrors_netbsd_arm.go | 1751 ++++++++++ .../x/sys/unix/zerrors_openbsd_386.go | 1654 ++++++++++ .../x/sys/unix/zerrors_openbsd_amd64.go | 1765 +++++++++++ .../x/sys/unix/zerrors_openbsd_arm.go | 1656 ++++++++++ .../x/sys/unix/zerrors_solaris_amd64.go | 1532 +++++++++ .../golang.org/x/sys/unix/zptrace386_linux.go | 80 + .../golang.org/x/sys/unix/zptracearm_linux.go | 41 + .../x/sys/unix/zptracemips_linux.go | 50 + .../x/sys/unix/zptracemipsle_linux.go | 50 + .../golang.org/x/sys/unix/zsyscall_aix_ppc.go | 1450 +++++++++ .../x/sys/unix/zsyscall_aix_ppc64.go | 1408 ++++++++ .../x/sys/unix/zsyscall_aix_ppc64_gc.go | 1162 +++++++ .../x/sys/unix/zsyscall_aix_ppc64_gccgo.go | 1042 ++++++ .../x/sys/unix/zsyscall_darwin_386.1_11.go | 1810 +++++++++++ .../x/sys/unix/zsyscall_darwin_386.go | 2505 +++++++++++++++ .../x/sys/unix/zsyscall_darwin_386.s | 284 ++ .../x/sys/unix/zsyscall_darwin_amd64.1_11.go | 1810 +++++++++++ .../x/sys/unix/zsyscall_darwin_amd64.go | 2505 +++++++++++++++ .../x/sys/unix/zsyscall_darwin_amd64.s | 284 ++ .../x/sys/unix/zsyscall_darwin_arm.1_11.go | 1793 +++++++++++ .../x/sys/unix/zsyscall_darwin_arm.go | 2483 +++++++++++++++ .../x/sys/unix/zsyscall_darwin_arm.s | 282 ++ .../x/sys/unix/zsyscall_darwin_arm64.1_11.go | 1793 +++++++++++ .../x/sys/unix/zsyscall_darwin_arm64.go | 2483 +++++++++++++++ .../x/sys/unix/zsyscall_darwin_arm64.s | 282 ++ .../x/sys/unix/zsyscall_dragonfly_amd64.go | 1659 ++++++++++ .../x/sys/unix/zsyscall_freebsd_386.go | 2015 ++++++++++++ .../x/sys/unix/zsyscall_freebsd_amd64.go | 2015 ++++++++++++ .../x/sys/unix/zsyscall_freebsd_arm.go | 2015 ++++++++++++ .../x/sys/unix/zsyscall_freebsd_arm64.go | 2015 ++++++++++++ .../x/sys/unix/zsyscall_linux_386.go | 2199 +++++++++++++ .../x/sys/unix/zsyscall_linux_amd64.go | 2366 ++++++++++++++ .../x/sys/unix/zsyscall_linux_arm.go | 2311 ++++++++++++++ .../x/sys/unix/zsyscall_linux_arm64.go | 2208 +++++++++++++ .../x/sys/unix/zsyscall_linux_mips.go | 2379 ++++++++++++++ .../x/sys/unix/zsyscall_linux_mips64.go | 2350 ++++++++++++++ .../x/sys/unix/zsyscall_linux_mips64le.go | 2350 ++++++++++++++ .../x/sys/unix/zsyscall_linux_mipsle.go | 2379 ++++++++++++++ .../x/sys/unix/zsyscall_linux_ppc64.go | 2428 ++++++++++++++ .../x/sys/unix/zsyscall_linux_ppc64le.go | 2428 ++++++++++++++ .../x/sys/unix/zsyscall_linux_riscv64.go | 2188 +++++++++++++ .../x/sys/unix/zsyscall_linux_s390x.go | 2198 +++++++++++++ .../x/sys/unix/zsyscall_linux_sparc64.go | 2361 ++++++++++++++ .../x/sys/unix/zsyscall_netbsd_386.go | 1826 +++++++++++ .../x/sys/unix/zsyscall_netbsd_amd64.go | 1826 +++++++++++ .../x/sys/unix/zsyscall_netbsd_arm.go | 1826 +++++++++++ .../x/sys/unix/zsyscall_openbsd_386.go | 1692 ++++++++++ .../x/sys/unix/zsyscall_openbsd_amd64.go | 1692 ++++++++++ .../x/sys/unix/zsyscall_openbsd_arm.go | 1692 ++++++++++ .../x/sys/unix/zsyscall_solaris_amd64.go | 1953 ++++++++++++ .../x/sys/unix/zsysctl_openbsd_386.go | 270 ++ .../x/sys/unix/zsysctl_openbsd_amd64.go | 270 ++ .../x/sys/unix/zsysctl_openbsd_arm.go | 270 ++ .../x/sys/unix/zsysnum_darwin_386.go | 436 +++ .../x/sys/unix/zsysnum_darwin_amd64.go | 436 +++ .../x/sys/unix/zsysnum_darwin_arm.go | 436 +++ .../x/sys/unix/zsysnum_darwin_arm64.go | 436 +++ .../x/sys/unix/zsysnum_dragonfly_amd64.go | 315 ++ .../x/sys/unix/zsysnum_freebsd_386.go | 403 +++ .../x/sys/unix/zsysnum_freebsd_amd64.go | 403 +++ .../x/sys/unix/zsysnum_freebsd_arm.go | 403 +++ .../x/sys/unix/zsysnum_freebsd_arm64.go | 395 +++ .../x/sys/unix/zsysnum_linux_386.go | 392 +++ .../x/sys/unix/zsysnum_linux_amd64.go | 344 ++ .../x/sys/unix/zsysnum_linux_arm.go | 364 +++ .../x/sys/unix/zsysnum_linux_arm64.go | 288 ++ .../x/sys/unix/zsysnum_linux_mips.go | 377 +++ .../x/sys/unix/zsysnum_linux_mips64.go | 337 ++ .../x/sys/unix/zsysnum_linux_mips64le.go | 337 ++ .../x/sys/unix/zsysnum_linux_mipsle.go | 377 +++ .../x/sys/unix/zsysnum_linux_ppc64.go | 375 +++ .../x/sys/unix/zsysnum_linux_ppc64le.go | 375 +++ .../x/sys/unix/zsysnum_linux_riscv64.go | 287 ++ .../x/sys/unix/zsysnum_linux_s390x.go | 337 ++ .../x/sys/unix/zsysnum_linux_sparc64.go | 350 ++ .../x/sys/unix/zsysnum_netbsd_386.go | 274 ++ .../x/sys/unix/zsysnum_netbsd_amd64.go | 274 ++ .../x/sys/unix/zsysnum_netbsd_arm.go | 274 ++ .../x/sys/unix/zsysnum_openbsd_386.go | 218 ++ .../x/sys/unix/zsysnum_openbsd_amd64.go | 218 ++ .../x/sys/unix/zsysnum_openbsd_arm.go | 218 ++ .../golang.org/x/sys/unix/ztypes_aix_ppc.go | 345 ++ .../golang.org/x/sys/unix/ztypes_aix_ppc64.go | 354 +++ .../x/sys/unix/ztypes_darwin_386.go | 489 +++ .../x/sys/unix/ztypes_darwin_amd64.go | 499 +++ .../x/sys/unix/ztypes_darwin_arm.go | 490 +++ .../x/sys/unix/ztypes_darwin_arm64.go | 499 +++ .../x/sys/unix/ztypes_dragonfly_amd64.go | 469 +++ .../x/sys/unix/ztypes_freebsd_386.go | 603 ++++ .../x/sys/unix/ztypes_freebsd_amd64.go | 602 ++++ .../x/sys/unix/ztypes_freebsd_arm.go | 602 ++++ .../x/sys/unix/ztypes_freebsd_arm64.go | 602 ++++ .../golang.org/x/sys/unix/ztypes_linux_386.go | 2006 ++++++++++++ .../x/sys/unix/ztypes_linux_amd64.go | 2019 ++++++++++++ .../golang.org/x/sys/unix/ztypes_linux_arm.go | 1997 ++++++++++++ .../x/sys/unix/ztypes_linux_arm64.go | 1998 ++++++++++++ .../x/sys/unix/ztypes_linux_mips.go | 2003 ++++++++++++ .../x/sys/unix/ztypes_linux_mips64.go | 2000 ++++++++++++ .../x/sys/unix/ztypes_linux_mips64le.go | 2000 ++++++++++++ .../x/sys/unix/ztypes_linux_mipsle.go | 2003 ++++++++++++ .../x/sys/unix/ztypes_linux_ppc64.go | 2008 ++++++++++++ .../x/sys/unix/ztypes_linux_ppc64le.go | 2008 ++++++++++++ .../x/sys/unix/ztypes_linux_riscv64.go | 2025 ++++++++++++ .../x/sys/unix/ztypes_linux_s390x.go | 2022 ++++++++++++ .../x/sys/unix/ztypes_linux_sparc64.go | 2003 ++++++++++++ .../x/sys/unix/ztypes_netbsd_386.go | 465 +++ .../x/sys/unix/ztypes_netbsd_amd64.go | 472 +++ .../x/sys/unix/ztypes_netbsd_arm.go | 470 +++ .../x/sys/unix/ztypes_openbsd_386.go | 560 ++++ .../x/sys/unix/ztypes_openbsd_amd64.go | 560 ++++ .../x/sys/unix/ztypes_openbsd_arm.go | 561 ++++ .../x/sys/unix/ztypes_solaris_amd64.go | 442 +++ .../golang.org/x/sys/windows/aliases.go | 13 + .../x/sys/windows/asm_windows_386.s | 13 + .../x/sys/windows/asm_windows_amd64.s | 13 + .../x/sys/windows/asm_windows_arm.s | 11 + .../golang.org/x/sys/windows/dll_windows.go | 378 +++ .../golang.org/x/sys/windows/env_windows.go | 29 + .../golang.org/x/sys/windows/eventlog.go | 20 + .../golang.org/x/sys/windows/exec_windows.go | 97 + .../x/sys/windows/memory_windows.go | 26 + .../golang.org/x/sys/windows/mksyscall.go | 7 + .../vendor/golang.org/x/sys/windows/race.go | 30 + .../vendor/golang.org/x/sys/windows/race0.go | 25 + .../golang.org/x/sys/windows/registry/key.go | 198 ++ .../x/sys/windows/registry/mksyscall.go | 7 + .../x/sys/windows/registry/syscall.go | 32 + .../x/sys/windows/registry/value.go | 384 +++ .../sys/windows/registry/zsyscall_windows.go | 120 + .../x/sys/windows/security_windows.go | 478 +++ .../golang.org/x/sys/windows/service.go | 183 ++ .../vendor/golang.org/x/sys/windows/str.go | 22 + .../golang.org/x/sys/windows/svc/event.go | 48 + .../golang.org/x/sys/windows/svc/go12.c | 24 + .../golang.org/x/sys/windows/svc/go12.go | 11 + .../golang.org/x/sys/windows/svc/go13.go | 31 + .../golang.org/x/sys/windows/svc/security.go | 62 + .../golang.org/x/sys/windows/svc/service.go | 363 +++ .../golang.org/x/sys/windows/svc/sys_386.s | 68 + .../golang.org/x/sys/windows/svc/sys_amd64.s | 42 + .../golang.org/x/sys/windows/svc/sys_arm.s | 38 + .../golang.org/x/sys/windows/syscall.go | 74 + .../x/sys/windows/syscall_windows.go | 1205 +++++++ .../golang.org/x/sys/windows/types_windows.go | 1469 +++++++++ .../x/sys/windows/types_windows_386.go | 22 + .../x/sys/windows/types_windows_amd64.go | 22 + .../x/sys/windows/types_windows_arm.go | 22 + .../x/sys/windows/zsyscall_windows.go | 2700 ++++++++++++++++ .../github.com/Microsoft/hcsshim/version.go | 6 - 640 files changed, 255337 insertions(+), 1791 deletions(-) delete mode 100644 vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/NOTICE delete mode 100644 vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs.go delete mode 100644 vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_create-scratch.go delete mode 100644 vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_create-scratch_test.go delete mode 100644 vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_create.go delete mode 100644 vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_delete.go delete mode 100644 vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_exec.go delete mode 100644 vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_kill.go delete mode 100644 vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_list.go delete mode 100644 vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_list_test.go delete mode 100644 vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_pause.go delete mode 100644 vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_ps.go delete mode 100644 vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_resize-tty.go delete mode 100644 vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_resume.go delete mode 100644 vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_start.go delete mode 100644 vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_state.go delete mode 100644 vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_test.go delete mode 100644 vendor/github.com/Microsoft/hcsshim/cmd/runhcs/tar2vhd.go delete mode 100644 vendor/github.com/Microsoft/hcsshim/functional/manifest.go delete mode 100644 vendor/github.com/Microsoft/hcsshim/internal/cmd/createuvm/createuvm.go delete mode 100644 vendor/github.com/Microsoft/hcsshim/internal/cmd/rootfs2vhd/rootfs2vhd.go delete mode 100644 vendor/github.com/Microsoft/hcsshim/internal/osversion/osversion.go delete mode 100644 vendor/github.com/Microsoft/hcsshim/internal/osversion/windowsbuilds.go delete mode 100644 vendor/github.com/Microsoft/hcsshim/pkg/go-runhcs/runhcs_integration_test.go rename vendor/github.com/Microsoft/hcsshim/{ => test}/functional/assets/defaultlinuxspec.json (100%) rename vendor/github.com/Microsoft/hcsshim/{ => test}/functional/assets/defaultwindowsspec.json (100%) rename vendor/github.com/Microsoft/hcsshim/{ => test}/functional/assets/samples/config.justin.lcow.working.json (100%) rename vendor/github.com/Microsoft/hcsshim/{ => test}/functional/assets/samples/from-docker-linux/privileged.json (100%) rename vendor/github.com/Microsoft/hcsshim/{ => test}/functional/assets/samples/from-docker-linux/sh.json (100%) rename vendor/github.com/Microsoft/hcsshim/{ => test}/functional/lcow_test.go (88%) rename vendor/github.com/Microsoft/hcsshim/{ => test}/functional/manifest/manifest.go (100%) rename vendor/github.com/Microsoft/hcsshim/{ => test}/functional/manifest/rsrc_amd64.syso (100%) create mode 100644 vendor/github.com/Microsoft/hcsshim/test/functional/manifest_test.go rename vendor/github.com/Microsoft/hcsshim/{ => test}/functional/test.go (100%) rename vendor/github.com/Microsoft/hcsshim/{ => test}/functional/utilities/createuvm.go (82%) rename vendor/github.com/Microsoft/hcsshim/{ => test}/functional/utilities/defaultlinuxspec.go (100%) rename vendor/github.com/Microsoft/hcsshim/{ => test}/functional/utilities/defaultwindowsspec.go (100%) rename vendor/github.com/Microsoft/hcsshim/{ => test}/functional/utilities/layerfolders.go (100%) rename vendor/github.com/Microsoft/hcsshim/{ => test}/functional/utilities/requiresbuild.go (100%) rename vendor/github.com/Microsoft/hcsshim/{ => test}/functional/utilities/scratch.go (100%) rename vendor/github.com/Microsoft/hcsshim/{ => test}/functional/utilities/tempdir.go (100%) rename vendor/github.com/Microsoft/hcsshim/{ => test}/functional/uvm_mem_backingtype_test.go (54%) rename vendor/github.com/Microsoft/hcsshim/{ => test}/functional/uvm_plannine_test.go (94%) rename vendor/github.com/Microsoft/hcsshim/{ => test}/functional/uvm_properties_test.go (96%) rename vendor/github.com/Microsoft/hcsshim/{ => test}/functional/uvm_scratch_test.go (98%) rename vendor/github.com/Microsoft/hcsshim/{ => test}/functional/uvm_scsi_test.go (98%) rename vendor/github.com/Microsoft/hcsshim/{ => test}/functional/uvm_vpmem_test.go (95%) rename vendor/github.com/Microsoft/hcsshim/{ => test}/functional/uvm_vsmb_test.go (94%) rename vendor/github.com/Microsoft/hcsshim/{ => test}/functional/wcow_test.go (98%) rename vendor/github.com/Microsoft/hcsshim/{ => test}/functional/wcow_xenon_v2_test.go (96%) rename vendor/github.com/Microsoft/hcsshim/{pkg/go-runhcs/runhcs_create-scratch_test.go => test/runhcs/create-scratch_test.go} (90%) rename vendor/github.com/Microsoft/hcsshim/{pkg/go-runhcs/runhcs_e2e_matrix_test.go => test/runhcs/e2e_matrix_test.go} (97%) rename vendor/github.com/Microsoft/hcsshim/{pkg/go-runhcs/runhcs_list_test.go => test/runhcs/list_test.go} (82%) create mode 100644 vendor/github.com/Microsoft/hcsshim/test/runhcs/runhcs_test.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor.conf create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/LICENSE create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/README.md create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/archive/tar/LICENSE create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/archive/tar/common.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/archive/tar/reader.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/archive/tar/stat_atim.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/archive/tar/stat_atimespec.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/archive/tar/stat_unix.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/archive/tar/writer.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/backup.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/backuptar/noop.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/backuptar/tar.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/ea.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/file.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/fileinfo.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/internal/etw/etw.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/internal/etw/eventdata.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/internal/etw/eventdatadescriptor.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/internal/etw/eventdescriptor.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/internal/etw/eventmetadata.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/internal/etw/eventopt.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/internal/etw/fieldopt.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/internal/etw/provider.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/internal/etw/providerglobal.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/internal/etw/ptr64_32.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/internal/etw/ptr64_64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/internal/etw/zsyscall_windows.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/pipe.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/pkg/etwlogrus/hook.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/privilege.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/reparse.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/sd.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/syscall.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/vhd/vhd.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/vhd/zvhd.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/zsyscall_windows.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/opengcs/LICENSE create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/opengcs/README.md create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/opengcs/client/config.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/opengcs/client/createext4vhdx.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/opengcs/client/hotaddvhd.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/opengcs/client/hotremovevhd.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/opengcs/client/init.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/opengcs/client/layervhddetails.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/opengcs/client/process.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/opengcs/client/tartovhd.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/opengcs/client/unsupported.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/opengcs/client/utilities.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/opengcs/client/vhdtotar.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/opengcs/vsockexec/vsockexec.c create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/blang/semver/LICENSE create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/blang/semver/README.md create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/blang/semver/json.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/blang/semver/range.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/blang/semver/semver.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/blang/semver/sort.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/blang/semver/sql.go rename vendor/github.com/Microsoft/hcsshim/{cmd/go-runhcs => vendor/github.com/containerd/console}/LICENSE (100%) create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/console/README.md create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/console/console.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/console/console_linux.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/console/console_unix.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/console/console_windows.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/console/tc_darwin.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/console/tc_freebsd.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/console/tc_linux.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/console/tc_openbsd_cgo.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/console/tc_openbsd_nocgo.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/console/tc_solaris_cgo.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/console/tc_solaris_nocgo.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/console/tc_unix.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/go-runc/LICENSE create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/go-runc/README.md create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/go-runc/command_linux.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/go-runc/command_other.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/go-runc/console.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/go-runc/container.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/go-runc/events.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/go-runc/io.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/go-runc/io_unix.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/go-runc/io_windows.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/go-runc/monitor.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/go-runc/runc.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/go-runc/utils.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/hashicorp/errwrap/LICENSE create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/hashicorp/errwrap/README.md create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/hashicorp/errwrap/errwrap.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/hashicorp/go-multierror/LICENSE create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/hashicorp/go-multierror/README.md create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/hashicorp/go-multierror/append.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/hashicorp/go-multierror/flatten.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/hashicorp/go-multierror/format.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/hashicorp/go-multierror/multierror.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/hashicorp/go-multierror/prefix.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/konsorten/go-windows-terminal-sequences/LICENSE create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/konsorten/go-windows-terminal-sequences/README.md create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/konsorten/go-windows-terminal-sequences/sequences.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/linuxkit/virtsock/LICENSE create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/linuxkit/virtsock/README.md create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/linuxkit/virtsock/c/README.md create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/linuxkit/virtsock/c/compat.h create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/linuxkit/virtsock/c/hvbench.c create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/linuxkit/virtsock/c/hvecho.c create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/linuxkit/virtsock/c/hvstress.c create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/linuxkit/virtsock/pkg/hvsock/hvsock.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/linuxkit/virtsock/pkg/hvsock/hvsock_fallback.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/linuxkit/virtsock/pkg/hvsock/hvsock_linux.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/linuxkit/virtsock/pkg/hvsock/hvsock_windows.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/linuxkit/virtsock/pkg/hvsock/zsyscall_windows.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/linuxkit/virtsock/vendor.conf create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-spec/LICENSE create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-spec/README.md create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-spec/specs-go/config.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-spec/specs-go/state.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-spec/specs-go/version.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/LICENSE create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/README.md create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/error/error.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/filepath/abs.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/filepath/ancestor.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/filepath/clean.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/filepath/doc.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/filepath/join.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/filepath/separator.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/generate/config.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/generate/generate.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/consts.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/parse_action.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/parse_architecture.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/parse_arguments.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/parse_remove.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/seccomp_default.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/seccomp_default_linux.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/seccomp_default_unsupported.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/syscall_compare.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/specerror/bundle.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/specerror/config-linux.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/specerror/config-windows.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/specerror/config.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/specerror/error.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/specerror/runtime-linux.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/specerror/runtime.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/validate/validate.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/validate/validate_linux.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/validate/validate_unsupported.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/pkg/errors/LICENSE create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/pkg/errors/README.md create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/pkg/errors/errors.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/pkg/errors/stack.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/LICENSE create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/README.md create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/alt_exit.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/doc.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/entry.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/exported.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/formatter.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/hooks.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/json_formatter.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/logger.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/logrus.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/terminal_check_aix.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/terminal_check_appengine.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/terminal_check_js.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/terminal_check_notappengine.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/terminal_check_windows.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/terminal_notwindows.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/terminal_windows.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/text_formatter.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/writer.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/syndtr/gocapability/LICENSE create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/syndtr/gocapability/capability/capability.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/syndtr/gocapability/capability/capability_linux.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/syndtr/gocapability/capability/capability_noop.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/syndtr/gocapability/capability/enum.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/syndtr/gocapability/capability/enum_gen.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/syndtr/gocapability/capability/syscall_linux.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/urfave/cli/LICENSE create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/urfave/cli/README.md create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/urfave/cli/app.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/urfave/cli/category.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/urfave/cli/cli.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/urfave/cli/command.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/urfave/cli/context.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/urfave/cli/errors.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/urfave/cli/flag.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/urfave/cli/flag_generated.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/urfave/cli/funcs.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/urfave/cli/help.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonpointer/LICENSE-APACHE-2.0.txt create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonpointer/README.md create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonpointer/pointer.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonreference/LICENSE-APACHE-2.0.txt create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonreference/README.md create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonreference/reference.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/LICENSE-APACHE-2.0.txt create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/README.md create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/errors.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/format_checkers.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/internalLog.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/jsonContext.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/jsonLoader.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/locales.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/result.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/schema.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/schemaPool.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/schemaReferencePool.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/schemaType.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/subSchema.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/types.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/utils.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/validation.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/LICENSE create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/PATENTS create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/README.md create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/curve25519/const_amd64.h create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/curve25519/const_amd64.s create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/curve25519/cswap_amd64.s create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/curve25519/curve25519.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/curve25519/doc.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/curve25519/freeze_amd64.s create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/curve25519/ladderstep_amd64.s create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/curve25519/mont25519_amd64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/curve25519/mul_amd64.s create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/curve25519/square_amd64.s create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/otr/libotr_test_helper.c create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/otr/otr.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/otr/smp.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/ssh/terminal/terminal.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/ssh/terminal/util.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/ssh/terminal/util_aix.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/ssh/terminal/util_bsd.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/ssh/terminal/util_linux.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/ssh/terminal/util_plan9.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/ssh/terminal/util_solaris.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/ssh/terminal/util_windows.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/ssh/test/doc.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/ssh/test/sshd_test_pw.c create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sync/LICENSE create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sync/PATENTS create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sync/README.md create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sync/errgroup/errgroup.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/LICENSE create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/PATENTS create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/README.md create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/cpu/cpu.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/cpu/cpu_arm.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/cpu/cpu_arm64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/cpu/cpu_gc_x86.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/cpu/cpu_gccgo.c create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/cpu/cpu_gccgo.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/cpu/cpu_linux.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/cpu/cpu_mips64x.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/cpu/cpu_mipsx.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/cpu/cpu_ppc64x.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/cpu/cpu_s390x.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/cpu/cpu_x86.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/cpu/cpu_x86.s create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/README.md create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/affinity_linux.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/aliases.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/asm_aix_ppc64.s create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/asm_darwin_386.s create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/asm_darwin_amd64.s create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/asm_darwin_arm.s create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/asm_darwin_arm64.s create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/asm_dragonfly_amd64.s create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/asm_freebsd_386.s create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/asm_freebsd_amd64.s create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/asm_freebsd_arm.s create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/asm_freebsd_arm64.s create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/asm_linux_386.s create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/asm_linux_amd64.s create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/asm_linux_arm.s create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/asm_linux_arm64.s create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/asm_linux_mips64x.s create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/asm_linux_mipsx.s create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/asm_linux_ppc64x.s create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/asm_linux_s390x.s create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/asm_netbsd_386.s create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/asm_netbsd_amd64.s create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/asm_netbsd_arm.s create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/asm_openbsd_386.s create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/asm_openbsd_amd64.s create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/asm_openbsd_arm.s create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/asm_solaris_amd64.s create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/bluetooth_linux.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/cap_freebsd.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/constants.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/dev_aix_ppc.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/dev_aix_ppc64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/dev_darwin.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/dev_dragonfly.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/dev_freebsd.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/dev_linux.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/dev_netbsd.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/dev_openbsd.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/dirent.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/endian_big.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/endian_little.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/env_unix.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/errors_freebsd_386.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/errors_freebsd_amd64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/errors_freebsd_arm.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/fcntl.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/fcntl_darwin.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/fcntl_linux_32bit.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/gccgo.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/gccgo_c.c create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/gccgo_linux_amd64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/ioctl.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/openbsd_pledge.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/openbsd_unveil.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/pagesize_unix.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/race.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/race0.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/sockcmsg_linux.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/sockcmsg_unix.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/str.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/syscall.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/syscall_aix.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/syscall_aix_ppc.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/syscall_aix_ppc64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/syscall_bsd.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/syscall_darwin.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/syscall_darwin_386.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/syscall_darwin_amd64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/syscall_darwin_arm.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/syscall_darwin_arm64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/syscall_darwin_libSystem.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/syscall_dragonfly.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/syscall_dragonfly_amd64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/syscall_freebsd.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/syscall_freebsd_386.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/syscall_freebsd_amd64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/syscall_freebsd_arm.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/syscall_freebsd_arm64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/syscall_linux.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/syscall_linux_386.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/syscall_linux_amd64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/syscall_linux_amd64_gc.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/syscall_linux_arm.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/syscall_linux_arm64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/syscall_linux_gc.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/syscall_linux_gc_386.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/syscall_linux_gccgo_386.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/syscall_linux_gccgo_arm.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/syscall_linux_mips64x.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/syscall_linux_mipsx.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/syscall_linux_ppc64x.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/syscall_linux_riscv64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/syscall_linux_s390x.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/syscall_linux_sparc64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/syscall_netbsd.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/syscall_netbsd_386.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/syscall_netbsd_amd64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/syscall_netbsd_arm.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/syscall_openbsd.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/syscall_openbsd_386.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/syscall_openbsd_amd64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/syscall_openbsd_arm.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/syscall_solaris.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/syscall_solaris_amd64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/syscall_unix.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/syscall_unix_gc.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/syscall_unix_gc_ppc64x.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/timestruct.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/xattr_bsd.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zerrors_aix_ppc.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zerrors_aix_ppc64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zerrors_darwin_386.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zerrors_darwin_amd64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zerrors_darwin_arm.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zerrors_darwin_arm64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zerrors_dragonfly_amd64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zerrors_freebsd_386.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zerrors_freebsd_amd64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zerrors_freebsd_arm.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zerrors_freebsd_arm64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zerrors_linux_386.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zerrors_netbsd_386.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zerrors_netbsd_amd64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zerrors_netbsd_arm.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zerrors_openbsd_386.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zerrors_openbsd_amd64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zerrors_openbsd_arm.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zerrors_solaris_amd64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zptrace386_linux.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zptracearm_linux.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zptracemips_linux.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zptracemipsle_linux.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsyscall_aix_ppc.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsyscall_aix_ppc64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsyscall_aix_ppc64_gc.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsyscall_aix_ppc64_gccgo.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsyscall_darwin_386.1_11.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsyscall_darwin_386.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsyscall_darwin_386.s create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.1_11.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm.1_11.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm.s create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.1_11.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.s create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsyscall_dragonfly_amd64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsyscall_freebsd_386.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsyscall_freebsd_amd64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsyscall_freebsd_arm.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsyscall_freebsd_arm64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsyscall_linux_386.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsyscall_linux_amd64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsyscall_linux_arm.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsyscall_linux_arm64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsyscall_linux_mips.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64le.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64le.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsyscall_linux_riscv64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsyscall_linux_s390x.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsyscall_linux_sparc64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsyscall_netbsd_386.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsyscall_netbsd_amd64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsyscall_netbsd_arm.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsyscall_solaris_amd64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsysctl_openbsd_386.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsysctl_openbsd_amd64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsysctl_openbsd_arm.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsysnum_darwin_386.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsysnum_darwin_amd64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsysnum_darwin_arm.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsysnum_darwin_arm64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsysnum_dragonfly_amd64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsysnum_freebsd_386.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsysnum_freebsd_amd64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsysnum_freebsd_arm.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsysnum_freebsd_arm64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsysnum_linux_386.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsysnum_linux_arm.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsysnum_netbsd_386.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsysnum_netbsd_amd64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsysnum_netbsd_arm.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsysnum_openbsd_386.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsysnum_openbsd_amd64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/zsysnum_openbsd_arm.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/ztypes_aix_ppc.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/ztypes_aix_ppc64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/ztypes_darwin_386.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/ztypes_darwin_amd64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/ztypes_darwin_arm.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/ztypes_darwin_arm64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/ztypes_dragonfly_amd64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/ztypes_freebsd_386.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/ztypes_freebsd_amd64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/ztypes_linux_386.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/ztypes_linux_arm.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/ztypes_linux_mips.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/ztypes_linux_riscv64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/ztypes_linux_sparc64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/ztypes_netbsd_386.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/ztypes_netbsd_amd64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/ztypes_netbsd_arm.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/ztypes_openbsd_386.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/ztypes_openbsd_amd64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/ztypes_openbsd_arm.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/unix/ztypes_solaris_amd64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/windows/aliases.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/windows/asm_windows_386.s create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/windows/asm_windows_amd64.s create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/windows/asm_windows_arm.s create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/windows/dll_windows.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/windows/env_windows.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/windows/eventlog.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/windows/exec_windows.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/windows/memory_windows.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/windows/mksyscall.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/windows/race.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/windows/race0.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/windows/registry/key.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/windows/registry/mksyscall.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/windows/registry/syscall.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/windows/registry/value.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/windows/registry/zsyscall_windows.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/windows/security_windows.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/windows/service.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/windows/str.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/windows/svc/event.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/windows/svc/go12.c create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/windows/svc/go12.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/windows/svc/go13.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/windows/svc/security.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/windows/svc/service.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/windows/svc/sys_386.s create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/windows/svc/sys_amd64.s create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/windows/svc/sys_arm.s create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/windows/syscall.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/windows/syscall_windows.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/windows/types_windows.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/windows/types_windows_386.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/windows/types_windows_amd64.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/windows/types_windows_arm.go create mode 100644 vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/windows/zsyscall_windows.go delete mode 100644 vendor/github.com/Microsoft/hcsshim/version.go diff --git a/glide.lock b/glide.lock index 12ba6894e4..7fc8f75188 100644 --- a/glide.lock +++ b/glide.lock @@ -139,7 +139,7 @@ imports: - name: github.com/Microsoft/go-winio version: 97e4973ce50b2ff5f09635a57e2b88a037aae829 - name: github.com/Microsoft/hcsshim - version: 2bf3a7ac42318aacfffd0805be705ff2e4d1138f + version: bc49f75c72216a28ffc7443177f477aae7e61d1f subpackages: - internal/guid - internal/hcs diff --git a/glide.yaml b/glide.yaml index 4a9c1c1c2a..28d47e4c79 100644 --- a/glide.yaml +++ b/glide.yaml @@ -63,7 +63,6 @@ import: - package: github.com/bronze1man/goStrongswanVici version: 4d72634a2f113aa48347dbc7dcb14adb806b6534 - package: github.com/Microsoft/hcsshim - version: v0.8.3 - package: github.com/Microsoft/go-winio version: v0.4.11 - pacakge: github.com/sirupsen/logrus diff --git a/vendor/github.com/Microsoft/hcsshim/appveyor.yml b/vendor/github.com/Microsoft/hcsshim/appveyor.yml index 85b086a43c..a8ec5a5939 100644 --- a/vendor/github.com/Microsoft/hcsshim/appveyor.yml +++ b/vendor/github.com/Microsoft/hcsshim/appveyor.yml @@ -6,23 +6,24 @@ clone_folder: c:\gopath\src\github.com\Microsoft\hcsshim environment: GOPATH: c:\gopath - PATH: C:\mingw-w64\x86_64-7.2.0-posix-seh-rt_v5-rev1\mingw64\bin;%GOPATH%\bin;%PATH% + PATH: C:\mingw-w64\x86_64-7.2.0-posix-seh-rt_v5-rev1\mingw64\bin;%GOPATH%\bin;C:\gometalinter-2.0.12-windows-amd64;%PATH% + +stack: go 1.11 build_script: - - go get -u github.com/alecthomas/gometalinter - - gometalinter.exe --install + - appveyor DownloadFile https://github.com/alecthomas/gometalinter/releases/download/v2.0.12/gometalinter-2.0.12-windows-amd64.zip + - 7z x gometalinter-2.0.12-windows-amd64.zip -y -oC:\ > NUL - gometalinter.exe --config .gometalinter.json ./... - - go get -v -d -t -tags "functional integration admin" ./... - go build ./cmd/wclayer - go build ./cmd/runhcs - - go test -c ./pkg/go-runhcs/ -tags integration - go build ./cmd/tar2ext4 - go test -v ./... -tags admin - - go test -c ./functional/ -tags functional + - go test -c ./test/functional/ -tags functional + - go test -c ./test/runhcs/ -tags integration artifacts: - path: 'wclayer.exe' - path: 'runhcs.exe' - - path: 'go-runhcs.test.exe' - path: 'tar2ext4.exe' - - path: 'functional.test.exe' \ No newline at end of file + - path: 'functional.test.exe' + - path: 'runhcs.test.exe' \ No newline at end of file diff --git a/vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/NOTICE b/vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/NOTICE deleted file mode 100644 index 5f9d59f13c..0000000000 --- a/vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/NOTICE +++ /dev/null @@ -1,22 +0,0 @@ -go-runhcs is a fork of go-runc - -The following is runc's legal notice. - ---- - -runc - -Copyright 2012-2015 Docker, Inc. - -This product includes software developed at Docker, Inc. (http://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 http://www.bis.doc.gov - -See also http://www.apache.org/dev/crypto.html and/or seek legal counsel. \ No newline at end of file diff --git a/vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs.go b/vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs.go deleted file mode 100644 index df580248ef..0000000000 --- a/vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs.go +++ /dev/null @@ -1,125 +0,0 @@ -package runhcs - -import ( - "bytes" - "context" - "fmt" - "os" - "os/exec" - "sync" - - "github.com/containerd/go-runc" -) - -// Format is the type of log formatting options available. -type Format string - -const ( - none Format = "" - // Text is the default text log ouput. - Text Format = "text" - // JSON is the JSON formatted log output. - JSON Format = "json" - - command = "runhcs" -) - -var bytesBufferPool = sync.Pool{ - New: func() interface{} { - return bytes.NewBuffer(nil) - }, -} - -func getBuf() *bytes.Buffer { - return bytesBufferPool.Get().(*bytes.Buffer) -} - -func putBuf(b *bytes.Buffer) { - b.Reset() - bytesBufferPool.Put(b) -} - -// Runhcs is the client to the runhcs cli -type Runhcs struct { - // Debug enables debug output for logging. - Debug bool - // Log sets the log file path where internal debug information is written. - Log string - // LogFormat sets the format used by logs. - LogFormat Format - // Owner sets the compute system owner property. - Owner string - // Root is the registry key root for storage of runhcs container state. - Root string -} - -func (r *Runhcs) args() []string { - var out []string - if r.Debug { - out = append(out, "--debug") - } - if r.Log != "" { - // TODO: JTERRY75 - Should we do abs here? - out = append(out, "--log", r.Log) - } - if r.LogFormat != none { - out = append(out, "--log-format", string(r.LogFormat)) - } - if r.Owner != "" { - out = append(out, "--owner", r.Owner) - } - if r.Root != "" { - out = append(out, "--root", r.Root) - } - return out -} - -func (r *Runhcs) command(context context.Context, args ...string) *exec.Cmd { - cmd := exec.CommandContext(context, command, append(r.args(), args...)...) - cmd.Env = os.Environ() - return cmd -} - -// runOrError will run the provided command. If an error is -// encountered and neither Stdout or Stderr was set the error and the -// stderr of the command will be returned in the format of : -// -func (r *Runhcs) runOrError(cmd *exec.Cmd) error { - if cmd.Stdout != nil || cmd.Stderr != nil { - ec, err := runc.Monitor.Start(cmd) - if err != nil { - return err - } - status, err := runc.Monitor.Wait(cmd, ec) - if err == nil && status != 0 { - err = fmt.Errorf("%s did not terminate sucessfully", cmd.Args[0]) - } - return err - } - data, err := cmdOutput(cmd, true) - if err != nil { - return fmt.Errorf("%s: %s", err, data) - } - return nil -} - -func cmdOutput(cmd *exec.Cmd, combined bool) ([]byte, error) { - b := getBuf() - defer putBuf(b) - - cmd.Stdout = b - if combined { - cmd.Stderr = b - } - ec, err := runc.Monitor.Start(cmd) - if err != nil { - return nil, err - } - - status, err := runc.Monitor.Wait(cmd, ec) - if err == nil && status != 0 { - err = fmt.Errorf("%s did not terminate sucessfully", cmd.Args[0]) - } - - return b.Bytes(), err -} diff --git a/vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_create-scratch.go b/vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_create-scratch.go deleted file mode 100644 index 3b53b39908..0000000000 --- a/vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_create-scratch.go +++ /dev/null @@ -1,10 +0,0 @@ -package runhcs - -import ( - "context" -) - -// CreateScratch creates a scratch vhdx at 'destpath' that is ext4 formatted. -func (r *Runhcs) CreateScratch(context context.Context, destpath string) error { - return r.runOrError(r.command(context, "create-scratch", "--destpath", destpath)) -} diff --git a/vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_create-scratch_test.go b/vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_create-scratch_test.go deleted file mode 100644 index 4ce8c3d020..0000000000 --- a/vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_create-scratch_test.go +++ /dev/null @@ -1,65 +0,0 @@ -// +build integration - -package runhcs - -import ( - "context" - "io/ioutil" - "os" - "path/filepath" - "testing" -) - -func Test_CreateScratch_EmptyDestpath_Fail(t *testing.T) { - rhcs := Runhcs{ - Debug: true, - } - - ctx := context.TODO() - err := rhcs.CreateScratch(ctx, "") - if err == nil { - t.Fatal("Should have failed 'CreateScratch' command.") - } -} - -func Test_CreateScratch_DirDestpath_Failure(t *testing.T) { - rhcs := Runhcs{ - Debug: true, - } - - td, err := ioutil.TempDir("", "CreateScratch") - if err != nil { - t.Fatal(err) - } - defer os.Remove(td) - - ctx := context.TODO() - err = rhcs.CreateScratch(ctx, td) - if err == nil { - t.Fatal("Should have failed 'CreateScratch' command with dir destpath") - } -} - -func Test_CreateScratch_ValidDestpath_Success(t *testing.T) { - rhcs := Runhcs{ - Debug: true, - } - - td, err := ioutil.TempDir("", "CreateScratch") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(td) - - scratchPath := filepath.Join(td, "scratch.vhdx") - - ctx := context.TODO() - err = rhcs.CreateScratch(ctx, scratchPath) - if err != nil { - t.Fatalf("Failed 'CreateScratch' command with: %v", err) - } - _, err = os.Stat(scratchPath) - if err != nil { - t.Fatalf("Failed to stat scratch path with: %v", err) - } -} diff --git a/vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_create.go b/vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_create.go deleted file mode 100644 index 601eab8b22..0000000000 --- a/vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_create.go +++ /dev/null @@ -1,91 +0,0 @@ -package runhcs - -import ( - "context" - "fmt" - "path/filepath" - - runc "github.com/containerd/go-runc" -) - -// CreateOpts is set of options that can be used with the Create command. -type CreateOpts struct { - runc.IO - // PidFile is the path to the file to write the process id to. - PidFile string - // ShimLog is the path to the log file for the launched shim process. - ShimLog string - // VMLog is the path to the log file for the launched VM shim process. - VMLog string - // VMConsole is the path to the pipe for the VM's console (e.g. \\.\pipe\debugpipe) - VMConsole string -} - -func (opt *CreateOpts) args() ([]string, error) { - var out []string - if opt.PidFile != "" { - abs, err := filepath.Abs(opt.PidFile) - if err != nil { - return nil, err - } - out = append(out, "--pid-file", abs) - } - if opt.ShimLog != "" { - abs, err := filepath.Abs(opt.ShimLog) - if err != nil { - return nil, err - } - out = append(out, "--shim-log", abs) - } - if opt.VMLog != "" { - abs, err := filepath.Abs(opt.VMLog) - if err != nil { - return nil, err - } - out = append(out, "--vm-log", abs) - } - if opt.VMConsole != "" { - out = append(out, "--vm-console", opt.VMConsole) - } - return out, nil -} - -// Create creates a new container and returns its pid if it was created -// successfully. -func (r *Runhcs) Create(context context.Context, id, bundle string, opts *CreateOpts) error { - args := []string{"create", "--bundle", bundle} - if opts != nil { - oargs, err := opts.args() - if err != nil { - return err - } - args = append(args, oargs...) - } - cmd := r.command(context, append(args, id)...) - if opts != nil && opts.IO != nil { - opts.Set(cmd) - } - if cmd.Stdout == nil && cmd.Stderr == nil { - data, err := cmdOutput(cmd, true) - if err != nil { - return fmt.Errorf("%s: %s", err, data) - } - return nil - } - ec, err := runc.Monitor.Start(cmd) - if err != nil { - return err - } - if opts != nil && opts.IO != nil { - if c, ok := opts.IO.(runc.StartCloser); ok { - if err := c.CloseAfterStart(); err != nil { - return err - } - } - } - status, err := runc.Monitor.Wait(cmd, ec) - if err == nil && status != 0 { - err = fmt.Errorf("%s did not terminate sucessfully", cmd.Args[0]) - } - return nil -} diff --git a/vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_delete.go b/vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_delete.go deleted file mode 100644 index 08b82bbd9a..0000000000 --- a/vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_delete.go +++ /dev/null @@ -1,33 +0,0 @@ -package runhcs - -import ( - "context" -) - -// DeleteOpts is set of options that can be used with the Delete command. -type DeleteOpts struct { - // Force forcibly deletes the container if it is still running (uses SIGKILL). - Force bool -} - -func (opt *DeleteOpts) args() ([]string, error) { - var out []string - if opt.Force { - out = append(out, "--force") - } - return out, nil -} - -// Delete any resources held by the container often used with detached -// containers. -func (r *Runhcs) Delete(context context.Context, id string, opts *DeleteOpts) error { - args := []string{"delete"} - if opts != nil { - oargs, err := opts.args() - if err != nil { - return err - } - args = append(args, oargs...) - } - return r.runOrError(r.command(context, append(args, id)...)) -} diff --git a/vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_exec.go b/vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_exec.go deleted file mode 100644 index d2f69a3f2b..0000000000 --- a/vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_exec.go +++ /dev/null @@ -1,82 +0,0 @@ -package runhcs - -import ( - "context" - "fmt" - "path/filepath" - - "github.com/containerd/go-runc" -) - -// ExecOpts is set of options that can be used with the Exec command. -type ExecOpts struct { - runc.IO - // Detach from the container's process. - Detach bool - // PidFile is the path to the file to write the process id to. - PidFile string - // ShimLog is the path to the log file for the launched shim process. - ShimLog string -} - -func (opt *ExecOpts) args() ([]string, error) { - var out []string - if opt.Detach { - out = append(out, "--detach") - } - if opt.PidFile != "" { - abs, err := filepath.Abs(opt.PidFile) - if err != nil { - return nil, err - } - out = append(out, "--pid-file", abs) - } - if opt.ShimLog != "" { - abs, err := filepath.Abs(opt.ShimLog) - if err != nil { - return nil, err - } - out = append(out, "--shim-log", abs) - } - return out, nil -} - -// Exec executes an additional process inside the container based on the -// oci.Process spec found at processFile. -func (r *Runhcs) Exec(context context.Context, id, processFile string, opts *ExecOpts) error { - args := []string{"exec", "--process", processFile} - if opts != nil { - oargs, err := opts.args() - if err != nil { - return err - } - args = append(args, oargs...) - } - cmd := r.command(context, append(args, id)...) - if opts != nil && opts.IO != nil { - opts.Set(cmd) - } - if cmd.Stdout == nil && cmd.Stderr == nil { - data, err := cmdOutput(cmd, true) - if err != nil { - return fmt.Errorf("%s: %s", err, data) - } - return nil - } - ec, err := runc.Monitor.Start(cmd) - if err != nil { - return err - } - if opts != nil && opts.IO != nil { - if c, ok := opts.IO.(runc.StartCloser); ok { - if err := c.CloseAfterStart(); err != nil { - return err - } - } - } - status, err := runc.Monitor.Wait(cmd, ec) - if err == nil && status != 0 { - err = fmt.Errorf("%s did not terminate sucessfully", cmd.Args[0]) - } - return err -} diff --git a/vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_kill.go b/vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_kill.go deleted file mode 100644 index 021e5b16fe..0000000000 --- a/vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_kill.go +++ /dev/null @@ -1,11 +0,0 @@ -package runhcs - -import ( - "context" -) - -// Kill sends the specified signal (default: SIGTERM) to the container's init -// process. -func (r *Runhcs) Kill(context context.Context, id, signal string) error { - return r.runOrError(r.command(context, "kill", id, signal)) -} diff --git a/vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_list.go b/vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_list.go deleted file mode 100644 index 3b9208017f..0000000000 --- a/vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_list.go +++ /dev/null @@ -1,28 +0,0 @@ -package runhcs - -import ( - "context" - "encoding/json" - - irunhcs "github.com/Microsoft/hcsshim/internal/runhcs" -) - -// ContainerState is the representation of the containers state at the moment of -// query. -type ContainerState = irunhcs.ContainerState - -// List containers started by runhcs. -// -// Note: This is specific to the Runhcs.Root namespace provided in the global -// settings. -func (r *Runhcs) List(context context.Context) ([]*ContainerState, error) { - data, err := cmdOutput(r.command(context, "list", "--format=json"), false) - if err != nil { - return nil, err - } - var out []*ContainerState - if err := json.Unmarshal(data, &out); err != nil { - return nil, err - } - return out, nil -} diff --git a/vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_list_test.go b/vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_list_test.go deleted file mode 100644 index c393f40c54..0000000000 --- a/vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_list_test.go +++ /dev/null @@ -1,23 +0,0 @@ -// +build integration - -package runhcs - -import ( - "context" - "testing" -) - -func Test_List_NoContainers(t *testing.T) { - rhcs := Runhcs{ - Debug: true, - } - - ctx := context.TODO() - cs, err := rhcs.List(ctx) - if err != nil { - t.Fatalf("Failed 'List' command with: %v", err) - } - if len(cs) != 0 { - t.Fatalf("Length of ContainerState array expected: 0, actual: %d", len(cs)) - } -} diff --git a/vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_pause.go b/vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_pause.go deleted file mode 100644 index 56392fa43e..0000000000 --- a/vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_pause.go +++ /dev/null @@ -1,10 +0,0 @@ -package runhcs - -import ( - "context" -) - -// Pause suspends all processes inside the container. -func (r *Runhcs) Pause(context context.Context, id string) error { - return r.runOrError(r.command(context, "pause", id)) -} diff --git a/vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_ps.go b/vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_ps.go deleted file mode 100644 index 4dc9f144fe..0000000000 --- a/vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_ps.go +++ /dev/null @@ -1,20 +0,0 @@ -package runhcs - -import ( - "context" - "encoding/json" - "fmt" -) - -// Ps displays the processes running inside a container. -func (r *Runhcs) Ps(context context.Context, id string) ([]int, error) { - data, err := cmdOutput(r.command(context, "ps", "--format=json", id), true) - if err != nil { - return nil, fmt.Errorf("%s: %s", err, data) - } - var out []int - if err := json.Unmarshal(data, &out); err != nil { - return nil, err - } - return out, nil -} diff --git a/vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_resize-tty.go b/vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_resize-tty.go deleted file mode 100644 index b9f90491d3..0000000000 --- a/vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_resize-tty.go +++ /dev/null @@ -1,33 +0,0 @@ -package runhcs - -import ( - "context" - "strconv" -) - -// ResizeTTYOpts is set of options that can be used with the ResizeTTY command. -type ResizeTTYOpts struct { - // Pid is the process pid (defaults to init pid). - Pid *int -} - -func (opt *ResizeTTYOpts) args() ([]string, error) { - var out []string - if opt.Pid != nil { - out = append(out, "--pid", strconv.Itoa(*opt.Pid)) - } - return out, nil -} - -// ResizeTTY updates the terminal size for a container process. -func (r *Runhcs) ResizeTTY(context context.Context, id string, width, height uint16, opts *ResizeTTYOpts) error { - args := []string{"resize-tty"} - if opts != nil { - oargs, err := opts.args() - if err != nil { - return err - } - args = append(args, oargs...) - } - return r.runOrError(r.command(context, append(args, id, strconv.FormatUint(uint64(width), 10), strconv.FormatUint(uint64(height), 10))...)) -} diff --git a/vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_resume.go b/vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_resume.go deleted file mode 100644 index 1fdeb87d9b..0000000000 --- a/vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_resume.go +++ /dev/null @@ -1,10 +0,0 @@ -package runhcs - -import ( - "context" -) - -// Resume resumes all processes that have been previously paused. -func (r *Runhcs) Resume(context context.Context, id string) error { - return r.runOrError(r.command(context, "resume", id)) -} diff --git a/vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_start.go b/vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_start.go deleted file mode 100644 index ad3df746a8..0000000000 --- a/vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_start.go +++ /dev/null @@ -1,10 +0,0 @@ -package runhcs - -import ( - "context" -) - -// Start will start an already created container. -func (r *Runhcs) Start(context context.Context, id string) error { - return r.runOrError(r.command(context, "start", id)) -} diff --git a/vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_state.go b/vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_state.go deleted file mode 100644 index b22bb079cc..0000000000 --- a/vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_state.go +++ /dev/null @@ -1,20 +0,0 @@ -package runhcs - -import ( - "context" - "encoding/json" - "fmt" -) - -// State outputs the state of a container. -func (r *Runhcs) State(context context.Context, id string) (*ContainerState, error) { - data, err := cmdOutput(r.command(context, "state", id), true) - if err != nil { - return nil, fmt.Errorf("%s: %s", err, data) - } - var out ContainerState - if err := json.Unmarshal(data, &out); err != nil { - return nil, err - } - return &out, nil -} diff --git a/vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_test.go b/vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_test.go deleted file mode 100644 index 34d3bd0006..0000000000 --- a/vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/runhcs_test.go +++ /dev/null @@ -1,103 +0,0 @@ -// +build runhcs_test - -package runhcs - -import ( - "bytes" - "context" - "io" - "os" - "path/filepath" - "sync" - "testing" - - runc "github.com/containerd/go-runc" -) - -func TestRunhcs_E2E(t *testing.T) { - rhcs := Runhcs{ - Debug: true, - } - - // TODO: JTERRY75 use this from assets dynamically - //dir, err := ioutil.TempDir("", "runhcs-bundle") - //if err != nil { - // t.Fatalf("failed to create tempdir with error: %v", err) - //} - //defer os.Remove(dir) - br := os.Getenv("RUNHCS_TEST_BUNDLE_ROOT") - if br == "" { - t.Fatal("You must set %RUNHCS_TEST_BUNDLE_ROOT% to the folder containing the test bundles") - return - } - // TODO: JTERRY75 create this spec dynamically once we can do the layer - // extraction in some way so we dont need hard coded bundle/config.json's - dir := filepath.Join(br, "runhcs-tee-test") - - ctx := context.TODO() - id := "runhcs-e2e-id" - - pio, err := runc.NewPipeIO() - if err != nil { - t.Fatalf("failed to create new pipe io with error: %v", err) - } - defer pio.Close() - - // Write our expected output - expected := "Hello go-runhcs-container!" - inbuff := bytes.NewBufferString(expected) - outbuff := &bytes.Buffer{} - errbuff := &bytes.Buffer{} - wg := sync.WaitGroup{} - wg.Add(2) - go func() { - _, err := io.Copy(pio.Stdin(), inbuff) - if err != nil { - t.Errorf("failed to copy string to stdin pipe.") - } - pio.Stdin().Close() - }() - go func() { - _, err := io.Copy(outbuff, pio.Stdout()) - if err != nil { - t.Errorf("failed to copy string from stdout pipe") - } - wg.Done() - }() - go func() { - _, err := io.Copy(errbuff, pio.Stderr()) - if err != nil { - t.Errorf("failed to copy string from stderr pipe") - } - wg.Done() - }() - - copts := &CreateOpts{ - IO: pio, - PidFile: filepath.Join(dir, "pid-file.txt"), - ShimLog: filepath.Join(dir, "shim-log.txt"), - VMLog: filepath.Join(dir, "vm-log.txt"), - } - if err := rhcs.Create(ctx, id, dir, copts); err != nil { - t.Fatalf("failed to create container with error: %v", err) - } - defer func() { - if err := rhcs.Delete(ctx, id, &DeleteOpts{Force: true}); err != nil { - t.Fatalf("failed to delete container with error: %v", err) - } - }() - - if err := rhcs.Start(ctx, id); err != nil { - t.Fatalf("failed to start container with error: %v", err) - } - wg.Wait() - - outstring := outbuff.String() - if outstring != expected { - t.Fatalf("stdout string '%s' != expected '%s'", outstring, expected) - } - errstring := errbuff.String() - if errstring != expected { - t.Fatalf("stderr string '%s' != expected '%s'", errstring, expected) - } -} diff --git a/vendor/github.com/Microsoft/hcsshim/cmd/runhcs/container.go b/vendor/github.com/Microsoft/hcsshim/cmd/runhcs/container.go index c68745b095..2a9ccd573b 100644 --- a/vendor/github.com/Microsoft/hcsshim/cmd/runhcs/container.go +++ b/vendor/github.com/Microsoft/hcsshim/cmd/runhcs/container.go @@ -225,16 +225,14 @@ func parseSandboxAnnotations(a map[string]string) (string, bool) { } // parseAnnotationsBool searches `a` for `key` and if found verifies that the -// value is `true` or `false` in any case. If `key` is not found returns `nil`. -func parseAnnotationsBool(a map[string]string, key string) *bool { +// value is `true` or `false` in any case. If `key` is not found returns `def`. +func parseAnnotationsBool(a map[string]string, key string, def bool) bool { if v, ok := a[key]; ok { - yes := true - no := false switch strings.ToLower(v) { case "true": - return &yes + return true case "false": - return &no + return false default: logrus.WithFields(logrus.Fields{ logfields.OCIAnnotation: key, @@ -243,37 +241,67 @@ func parseAnnotationsBool(a map[string]string, key string) *bool { }).Warning("annotation could not be parsed") } } - return nil + return def +} + +// parseAnnotationsCPU searches `s.Annotations` for the CPU annotation. If +// not found searches `s` for the Windows CPU section. If neither are found +// returns `def`. +func parseAnnotationsCPU(s *specs.Spec, annotation string, def int32) int32 { + if m := parseAnnotationsUint64(s.Annotations, annotation, 0); m != 0 { + return int32(m) + } + if s.Windows != nil && + s.Windows.Resources != nil && + s.Windows.Resources.CPU != nil && + s.Windows.Resources.CPU.Count != nil && + *s.Windows.Resources.CPU.Count > 0 { + return int32(*s.Windows.Resources.CPU.Count) + } + return def +} + +// parseAnnotationsMemory searches `s.Annotations` for the memory annotation. If +// not found searches `s` for the Windows memory section. If neither are found +// returns `def`. +func parseAnnotationsMemory(s *specs.Spec, annotation string, def int32) int32 { + if m := parseAnnotationsUint64(s.Annotations, annotation, 0); m != 0 { + return int32(m) + } + if s.Windows != nil && + s.Windows.Resources != nil && + s.Windows.Resources.Memory != nil && + s.Windows.Resources.Memory.Limit != nil && + *s.Windows.Resources.Memory.Limit > 0 { + return int32(*s.Windows.Resources.Memory.Limit) + } + return def } // parseAnnotationsPreferredRootFSType searches `a` for `key` and verifies that the -// value is in the set of allowed values. If `key` is not found returns `nil`. -// Otherwise returns the index at which it was found in allowed values. -func parseAnnotationsPreferredRootFSType(a map[string]string, key string) *uvm.PreferredRootFSType { +// value is in the set of allowed values. If `key` is not found returns `def`. +func parseAnnotationsPreferredRootFSType(a map[string]string, key string, def uvm.PreferredRootFSType) uvm.PreferredRootFSType { if v, ok := a[key]; ok { - // Following array must match enumeration uvm.PreferredRootFSType indexes - possibles := []string{"initrd", "vhd"} - for index, possible := range possibles { - if possible == v { - prfstype := uvm.PreferredRootFSType(index) - return &prfstype - } + switch v { + case "initrd": + return uvm.PreferredRootFSTypeInitRd + case "vhd": + return uvm.PreferredRootFSTypeVHD + default: + logrus.Warningf("annotation: '%s', with value: '%s' must be 'initrd' or 'vhd'", key, v) } - logrus.Warningf("annotation: '%s', with value: '%s' must be one of %+v", key, v, possibles) - return nil - } - return nil + return def } // parseAnnotationsUint32 searches `a` for `key` and if found verifies that the -// value is a 32 bit unsigned integer. If `key` is not found returns `nil`. -func parseAnnotationsUint32(a map[string]string, key string) *uint32 { +// value is a 32 bit unsigned integer. If `key` is not found returns `def`. +func parseAnnotationsUint32(a map[string]string, key string, def uint32) uint32 { if v, ok := a[key]; ok { countu, err := strconv.ParseUint(v, 10, 32) if err == nil { v := uint32(countu) - return &v + return v } logrus.WithFields(logrus.Fields{ logfields.OCIAnnotation: key, @@ -282,16 +310,16 @@ func parseAnnotationsUint32(a map[string]string, key string) *uint32 { logrus.ErrorKey: err, }).Warning("annotation could not be parsed") } - return nil + return def } // parseAnnotationsUint64 searches `a` for `key` and if found verifies that the -// value is a 64 bit unsigned integer. If `key` is not found returns `nil`. -func parseAnnotationsUint64(a map[string]string, key string) *uint64 { +// value is a 64 bit unsigned integer. If `key` is not found returns `def`. +func parseAnnotationsUint64(a map[string]string, key string, def uint64) uint64 { if v, ok := a[key]; ok { countu, err := strconv.ParseUint(v, 10, 64) if err == nil { - return &countu + return countu } logrus.WithFields(logrus.Fields{ logfields.OCIAnnotation: key, @@ -300,7 +328,7 @@ func parseAnnotationsUint64(a map[string]string, key string) *uint64 { logrus.ErrorKey: err, }).Warning("annotation could not be parsed") } - return nil + return def } // startVMShim starts a vm-shim command with the specified `opts`. `opts` can be `uvm.OptionsWCOW` or `uvm.OptionsLCOW` @@ -468,7 +496,7 @@ func createContainer(cfg *containerConfig) (_ *container, err error) { var opts interface{} const ( - annotationAllowOverCommit = "io.microsoft.virtualmachine.computetopology.memory.allowovercommit" + annotationAllowOvercommit = "io.microsoft.virtualmachine.computetopology.memory.allowovercommit" annotationEnableDeferredCommit = "io.microsoft.virtualmachine.computetopology.memory.enabledeferredcommit" annotationMemorySizeInMB = "io.microsoft.virtualmachine.computetopology.memory.sizeinmb" annotationProcessorCount = "io.microsoft.virtualmachine.computetopology.processor.count" @@ -477,41 +505,30 @@ func createContainer(cfg *containerConfig) (_ *container, err error) { annotationPreferredRootFSType = "io.microsoft.virtualmachine.lcow.preferredrootfstype" ) - bothOpts := &uvm.Options{ - ID: vmID(c.ID), - Owner: cfg.Owner, - AllowOvercommit: parseAnnotationsBool(cfg.Spec.Annotations, annotationAllowOverCommit), - EnableDeferredCommit: parseAnnotationsBool(cfg.Spec.Annotations, annotationEnableDeferredCommit), - } - - // If the Resources section of the config specified mem/cpu set it now. - if cfg.Spec.Windows != nil && cfg.Spec.Windows.Resources != nil { - if cfg.Spec.Windows.Resources.Memory != nil && cfg.Spec.Windows.Resources.Memory.Limit != nil { - bothOpts.MemorySizeInMB = int32(*cfg.Spec.Windows.Resources.Memory.Limit / 1024 / 1024) - } - if cfg.Spec.Windows.Resources.CPU != nil && cfg.Spec.Windows.Resources.CPU.Count != nil { - bothOpts.ProcessorCount = int32(*cfg.Spec.Windows.Resources.CPU.Count) - } - } - // Allow overrides of any mem/cpu annotations - memSize := parseAnnotationsUint64(cfg.Spec.Annotations, annotationMemorySizeInMB) - if memSize != nil { - bothOpts.MemorySizeInMB = int32(*memSize) - } - cpuCount := parseAnnotationsUint64(cfg.Spec.Annotations, annotationProcessorCount) - if cpuCount != nil { - bothOpts.ProcessorCount = int32(*cpuCount) - } - if cfg.Spec.Linux != nil { - opts = &uvm.OptionsLCOW{ - Options: bothOpts, - ConsolePipe: cfg.VMConsolePipe, - VPMemDeviceCount: parseAnnotationsUint32(cfg.Spec.Annotations, annotationVPMemCount), - VPMemSizeBytes: parseAnnotationsUint64(cfg.Spec.Annotations, annotationVPMemSize), - PreferredRootFSType: parseAnnotationsPreferredRootFSType(cfg.Spec.Annotations, annotationPreferredRootFSType), + lopts := uvm.NewDefaultOptionsLCOW(vmID(c.ID), cfg.Owner) + lopts.MemorySizeInMB = parseAnnotationsMemory(cfg.Spec, annotationMemorySizeInMB, lopts.MemorySizeInMB) + lopts.AllowOvercommit = parseAnnotationsBool(cfg.Spec.Annotations, annotationAllowOvercommit, lopts.AllowOvercommit) + lopts.EnableDeferredCommit = parseAnnotationsBool(cfg.Spec.Annotations, annotationEnableDeferredCommit, lopts.EnableDeferredCommit) + lopts.ProcessorCount = parseAnnotationsCPU(cfg.Spec, annotationProcessorCount, lopts.ProcessorCount) + lopts.ConsolePipe = cfg.VMConsolePipe + lopts.VPMemDeviceCount = parseAnnotationsUint32(cfg.Spec.Annotations, annotationVPMemCount, lopts.VPMemDeviceCount) + lopts.VPMemSizeBytes = parseAnnotationsUint64(cfg.Spec.Annotations, annotationVPMemSize, lopts.VPMemSizeBytes) + lopts.PreferredRootFSType = parseAnnotationsPreferredRootFSType(cfg.Spec.Annotations, annotationPreferredRootFSType, lopts.PreferredRootFSType) + switch lopts.PreferredRootFSType { + case uvm.PreferredRootFSTypeInitRd: + lopts.RootFSFile = uvm.InitrdFile + case uvm.PreferredRootFSTypeVHD: + lopts.RootFSFile = uvm.VhdFile } + opts = lopts } else { + wopts := uvm.NewDefaultOptionsWCOW(vmID(c.ID), cfg.Owner) + wopts.MemorySizeInMB = parseAnnotationsMemory(cfg.Spec, annotationMemorySizeInMB, wopts.MemorySizeInMB) + wopts.AllowOvercommit = parseAnnotationsBool(cfg.Spec.Annotations, annotationAllowOvercommit, wopts.AllowOvercommit) + wopts.EnableDeferredCommit = parseAnnotationsBool(cfg.Spec.Annotations, annotationEnableDeferredCommit, wopts.EnableDeferredCommit) + wopts.ProcessorCount = parseAnnotationsCPU(cfg.Spec, annotationProcessorCount, wopts.ProcessorCount) + // In order for the UVM sandbox.vhdx not to collide with the actual // nested Argon sandbox.vhdx we append the \vm folder to the last entry // in the list. @@ -526,10 +543,8 @@ func createContainer(cfg *containerConfig) (_ *container, err error) { } layers[layersLen-1] = vmPath - opts = &uvm.OptionsWCOW{ - Options: bothOpts, - LayerFolders: layers, - } + wopts.LayerFolders = layers + opts = wopts } shim, err := c.startVMShim(cfg.VMLogFile, opts) diff --git a/vendor/github.com/Microsoft/hcsshim/cmd/runhcs/create-scratch.go b/vendor/github.com/Microsoft/hcsshim/cmd/runhcs/create-scratch.go index 544b5dc26a..826ef43e46 100644 --- a/vendor/github.com/Microsoft/hcsshim/cmd/runhcs/create-scratch.go +++ b/vendor/github.com/Microsoft/hcsshim/cmd/runhcs/create-scratch.go @@ -36,7 +36,7 @@ var createScratchCommand = cli.Command{ Options: gcsclient.Options{ KirdPath: filepath.Join(os.Getenv("ProgramFiles"), "Linux Containers"), KernelFile: "kernel", - InitrdFile: "initrd.img", + InitrdFile: uvm.InitrdFile, }, Name: "createscratch-uvm", UvmTimeoutSeconds: 5 * 60, // 5 Min @@ -51,13 +51,8 @@ var createScratchCommand = cli.Command{ return errors.Wrapf(err, "failed to create ext4vhdx for '%s'", cfg.Name) } } else { - opts := uvm.OptionsLCOW{ - Options: &uvm.Options{ - ID: "createscratch-uvm", - Owner: context.GlobalString("owner"), - }, - } - convertUVM, err := uvm.CreateLCOW(&opts) + opts := uvm.NewDefaultOptionsLCOW("createscratch-uvm", context.GlobalString("owner")) + convertUVM, err := uvm.CreateLCOW(opts) if err != nil { return errors.Wrapf(err, "failed to create '%s'", opts.ID) } diff --git a/vendor/github.com/Microsoft/hcsshim/cmd/runhcs/kill.go b/vendor/github.com/Microsoft/hcsshim/cmd/runhcs/kill.go index b82128255a..2b713e010f 100644 --- a/vendor/github.com/Microsoft/hcsshim/cmd/runhcs/kill.go +++ b/vendor/github.com/Microsoft/hcsshim/cmd/runhcs/kill.go @@ -116,6 +116,9 @@ func validateSigstr(sigstr string, signalsSupported bool, isLcow bool) (int, err sigstr = strings.ToUpper(sigstr) if !signalsSupported { + // If signals arent supported we just validate that its a known signal. + // We already return 0 since we only supported a platform Kill() at that + // time. if isLcow { switch sigstr { case "15": @@ -123,19 +126,43 @@ func validateSigstr(sigstr string, signalsSupported bool, isLcow bool) (int, err case "TERM": fallthrough case "SIGTERM": - return 0xf, nil + return 0, nil default: return 0, errInvalidSignal } } switch sigstr { + // Docker sends a UNIX term in the supported Windows Signal map. + case "15": + fallthrough + case "TERM": + fallthrough case "0": fallthrough case "CTRLC": - return 0x0, nil + return 0, nil + case "9": + fallthrough + case "KILL": + return 0, nil default: return 0, errInvalidSignal } + } else { + if !isLcow { + // Docker sends the UNIX signal name or value. Convert them to the + // correct Windows signals. + switch sigstr { + case "15": + fallthrough + case "TERM": + return 0x0, nil // Convert to CTRLC + case "9": + fallthrough + case "KILL": + return 0x6, nil // Convert to CTRLSHUTDOWN + } + } } var sigmap map[string]int diff --git a/vendor/github.com/Microsoft/hcsshim/cmd/runhcs/kill_test.go b/vendor/github.com/Microsoft/hcsshim/cmd/runhcs/kill_test.go index ab0b3dcbbc..4cef065e5c 100644 --- a/vendor/github.com/Microsoft/hcsshim/cmd/runhcs/kill_test.go +++ b/vendor/github.com/Microsoft/hcsshim/cmd/runhcs/kill_test.go @@ -24,35 +24,39 @@ func runValidateSigstrTest(sigstr string, signalsSupported, isLcow bool, } } -func TestValidateSigstrEmpty(t *testing.T) { +func Test_ValidateSigstr_Empty(t *testing.T) { runValidateSigstrTest("", false, false, 0, false, t) runValidateSigstrTest("", false, true, 0xf, false, t) runValidateSigstrTest("", true, false, 0, false, t) runValidateSigstrTest("", true, true, 0xf, false, t) } -func TestValidateSigstrDefaultLCOW(t *testing.T) { - runValidateSigstrTest("15", false, true, 0xf, false, t) - runValidateSigstrTest("TERM", false, true, 0xf, false, t) - runValidateSigstrTest("SIGTERM", false, true, 0xf, false, t) +func Test_ValidateSigstr_LCOW_NoSignalSupport_Default(t *testing.T) { + runValidateSigstrTest("15", false, true, 0, false, t) + runValidateSigstrTest("TERM", false, true, 0, false, t) + runValidateSigstrTest("SIGTERM", false, true, 0, false, t) } -func TestValidateSigstrDefaultLCOWInvalid(t *testing.T) { +func Test_ValidateSigstr_LCOW_NoSignalSupport_Default_Invalid(t *testing.T) { runValidateSigstrTest("2", false, true, 0, true, t) runValidateSigstrTest("test", false, true, 0, true, t) } -func TestValidateSigstrDefaultWCOW(t *testing.T) { - runValidateSigstrTest("0", false, false, 0x0, false, t) - runValidateSigstrTest("CTRLC", false, false, 0x0, false, t) +func Test_ValidateSigstr_WCOW_NoSignalSupport_Default(t *testing.T) { + runValidateSigstrTest("15", false, false, 0, false, t) + runValidateSigstrTest("TERM", false, false, 0, false, t) + runValidateSigstrTest("0", false, false, 0, false, t) + runValidateSigstrTest("CTRLC", false, false, 0, false, t) + runValidateSigstrTest("9", false, false, 0, false, t) + runValidateSigstrTest("KILL", false, false, 0, false, t) } -func TestValidateSigstrDefaultWCOWInvalid(t *testing.T) { - runValidateSigstrTest("15", false, false, 0, true, t) +func Test_ValidateSigstr_WCOW_NoSignalSupport_Default_Invalid(t *testing.T) { + runValidateSigstrTest("2", false, false, 0, true, t) runValidateSigstrTest("test", false, false, 0, true, t) } -func TestValidateSignalStringLCOW(t *testing.T) { +func Test_ValidateSigstr_LCOW_SignalSupport_SignalNames(t *testing.T) { for k, v := range signalMapLcow { runValidateSigstrTest(k, true, true, v, false, t) // run it again with a case not in the map @@ -64,7 +68,7 @@ func TestValidateSignalStringLCOW(t *testing.T) { } } -func TestValidateSignalStringWCOW(t *testing.T) { +func Test_ValidateSigstr_WCOW_SignalSupport_SignalNames(t *testing.T) { for k, v := range signalMapWindows { runValidateSigstrTest(k, true, false, v, false, t) // run it again with a case not in the map @@ -76,16 +80,32 @@ func TestValidateSignalStringWCOW(t *testing.T) { } } -func TestValidateSignalValueLCOW(t *testing.T) { +func Test_ValidateSigstr_LCOW_SignalSupport_SignalValues(t *testing.T) { for _, v := range signalMapLcow { str := strconv.Itoa(v) runValidateSigstrTest(str, true, true, v, false, t) } } -func TestValidateSignalValueWCOW(t *testing.T) { +func Test_ValidateSigstr_WCOW_SignalSupport_SignalValues(t *testing.T) { for _, v := range signalMapWindows { str := strconv.Itoa(v) runValidateSigstrTest(str, true, false, v, false, t) } } + +func Test_ValidateSigstr_WCOW_SignalSupport_Docker_SignalNames(t *testing.T) { + // Docker KILL -> CTRLSHUTDOWN when signals are supported + runValidateSigstrTest("KILL", true, false, 0x6, false, t) + + // Docker TERM -> CTRLSHUTDOWN when signals are supported + runValidateSigstrTest("TERM", true, false, 0x0, false, t) +} + +func Test_ValidateSigstr_WCOW_SignalSupport_Docker_SignalValues(t *testing.T) { + // Docker KILL -> CTRLSHUTDOWN when signals are supported + runValidateSigstrTest("9", true, false, 0x6, false, t) + + // Docker TERM -> CTRLSHUTDOWN when signals are supported + runValidateSigstrTest("15", true, false, 0x0, false, t) +} diff --git a/vendor/github.com/Microsoft/hcsshim/cmd/runhcs/main.go b/vendor/github.com/Microsoft/hcsshim/cmd/runhcs/main.go index cc165e4028..e13dbc097b 100644 --- a/vendor/github.com/Microsoft/hcsshim/cmd/runhcs/main.go +++ b/vendor/github.com/Microsoft/hcsshim/cmd/runhcs/main.go @@ -7,6 +7,7 @@ import ( "strings" "github.com/Microsoft/go-winio" + "github.com/Microsoft/go-winio/pkg/etwlogrus" "github.com/Microsoft/hcsshim/internal/regstate" "github.com/Microsoft/hcsshim/internal/runhcs" "github.com/opencontainers/runtime-spec/specs-go" @@ -50,6 +51,14 @@ Where "" is your name for the instance of the container that you a ) func main() { + // Provider ID: 0b52781f-b24d-5685-ddf6-69830ed40ec3 + // Hook isn't closed explicitly, as it will exist until process exit. + if hook, err := etwlogrus.NewHook("Microsoft.Virtualization.RunHCS"); err == nil { + logrus.AddHook(hook) + } else { + logrus.Error(err) + } + app := cli.NewApp() app.Name = "runhcs" app.Usage = usage @@ -148,7 +157,6 @@ func main() { fatalWriter.Writer = cli.ErrWriter cli.ErrWriter = &fatalWriter if err := app.Run(os.Args); err != nil { - logrus.Error(err) fmt.Fprintln(cli.ErrWriter, err) os.Exit(1) } diff --git a/vendor/github.com/Microsoft/hcsshim/cmd/runhcs/tar2vhd.go b/vendor/github.com/Microsoft/hcsshim/cmd/runhcs/tar2vhd.go deleted file mode 100644 index fa524bd46a..0000000000 --- a/vendor/github.com/Microsoft/hcsshim/cmd/runhcs/tar2vhd.go +++ /dev/null @@ -1,120 +0,0 @@ -package main - -import ( - "io" - "os" - "path/filepath" - - "github.com/Microsoft/hcsshim/internal/appargs" - "github.com/Microsoft/hcsshim/internal/lcow" - "github.com/Microsoft/hcsshim/internal/osversion" - "github.com/Microsoft/hcsshim/internal/uvm" - "github.com/Microsoft/hcsshim/internal/wclayer" - gcsclient "github.com/Microsoft/opengcs/client" - "github.com/pkg/errors" - "github.com/sirupsen/logrus" - "github.com/urfave/cli" -) - -var tarToVhdCommand = cli.Command{ - Name: "tar2vhd", - Usage: "converts a tar over stdin to a vhd at 'destpath'", - Description: "The tar2vhd command converts the tar at ('sourcepath'|stdin) to a vhd at 'destpath'", - Flags: []cli.Flag{ - cli.StringFlag{ - Name: "sourcepath", - Usage: "Optional: describes the path to the tar on disk", - }, - cli.StringFlag{ - Name: "scratchpath", - Usage: "Required: describes the path to the scratch.vhdx file to use for the transformation", - }, - cli.StringFlag{ - Name: "destpath", - Usage: "Required: describes the destination vhd path to write the contents of the tar to on disk", - }, - }, - Before: appargs.Validate(), - Action: func(context *cli.Context) error { - var rdr io.Reader - if src := context.String("sourcepath"); src != "" { - // Source is via file path not stdin - f, err := os.OpenFile(src, os.O_RDONLY, 0) - if err != nil { - return errors.Wrapf(err, "failed to open 'sourcepath': '%s'", src) - } - defer f.Close() - rdr = f - } else { - rdr = os.Stdin - } - - scratch := context.String("scratchpath") - if scratch == "" { - return errors.New("'scratchpath' is required") - } - - dest := context.String("destpath") - if dest == "" { - return errors.New("'destpath' is required") - } - - // If we only have v1 lcow support do it the old way. - if osversion.Get().Build < osversion.RS5 { - cfg := gcsclient.Config{ - Options: gcsclient.Options{ - KirdPath: filepath.Join(os.Getenv("ProgramFiles"), "Linux Containers"), - KernelFile: "kernel", - InitrdFile: "initrd.img", - }, - Name: "tar2vhd-uvm", - UvmTimeoutSeconds: 5 * 60, // 5 Min - } - - if err := cfg.StartUtilityVM(); err != nil { - return errors.Wrapf(err, "failed to start '%s'", cfg.Name) - } - defer cfg.Uvm.Terminate() - - if err := cfg.HotAddVhd(scratch, "/tmp/scratch", false, true); err != nil { - return errors.Wrapf(err, "failed to mount scratch path: '%s' to '%s'", scratch, cfg.Name) - } - - n, err := cfg.TarToVhd(dest, rdr) - if err != nil { - return errors.Wrapf(err, "failed to convert tar2vhd for '%s'", cfg.Name) - } - - logrus.Debugf("wrote %v bytes to %s", n, dest) - } else { - opts := uvm.UVMOptions{ - ID: "tar2vhd-uvm", - OperatingSystem: "linux", - } - convertUVM, err := uvm.Create(&opts) - if err != nil { - return errors.Wrapf(err, "failed to create '%s'", opts.ID) - } - if err := convertUVM.Start(); err != nil { - return errors.Wrapf(err, "failed to start '%s'", opts.ID) - } - defer convertUVM.Terminate() - - if err := wclayer.GrantVmAccess(opts.ID, scratch); err != nil { - return errors.Wrapf(err, "failed to grant access to scratch path: '%s' to '%s'", scratch, opts.ID) - } - if _, _, err := convertUVM.AddSCSI(scratch, "/tmp/scratch"); err != nil { - return errors.Wrapf(err, "failed to mount scratch path: '%s' to '%s'", scratch, opts.ID) - } - - n, err := lcow.TarToVhd(convertUVM, dest, rdr) - if err != nil { - return errors.Wrapf(err, "failed to convert tar2vhd for '%s'", opts.ID) - } - - logrus.Debugf("wrote %v bytes to %s", n, dest) - } - - return nil - }, -} diff --git a/vendor/github.com/Microsoft/hcsshim/functional/manifest.go b/vendor/github.com/Microsoft/hcsshim/functional/manifest.go deleted file mode 100644 index dbb62226bd..0000000000 --- a/vendor/github.com/Microsoft/hcsshim/functional/manifest.go +++ /dev/null @@ -1,3 +0,0 @@ -package functional - -import _ "github.com/Microsoft/hcsshim/functional/manifest" diff --git a/vendor/github.com/Microsoft/hcsshim/hcn/hcn.go b/vendor/github.com/Microsoft/hcsshim/hcn/hcn.go index 808742a353..8bae5fc0ee 100644 --- a/vendor/github.com/Microsoft/hcsshim/hcn/hcn.go +++ b/vendor/github.com/Microsoft/hcsshim/hcn/hcn.go @@ -134,6 +134,33 @@ func V2SchemaVersion() SchemaVersion { } } +// RemoteSubnetSupported returns an error if the HCN version does not support Remote Subnet policies. +func RemoteSubnetSupported() error { + supported := GetSupportedFeatures() + if supported.RemoteSubnet { + return nil + } + return platformDoesNotSupportError("Remote Subnet") +} + +// HostRouteSupported returns an error if the HCN version does not support Host Route policies. +func HostRouteSupported() error { + supported := GetSupportedFeatures() + if supported.HostRoute { + return nil + } + return platformDoesNotSupportError("Host Route") +} + +// DSRSupported returns an error if the HCN version does not support Direct Server Return. +func DSRSupported() error { + supported := GetSupportedFeatures() + if supported.DSR { + return nil + } + return platformDoesNotSupportError("Direct Server Return (DSR)") +} + // RequestType are the different operations performed to settings. // Used to update the settings of Endpoint/Namespace objects. type RequestType string diff --git a/vendor/github.com/Microsoft/hcsshim/hcn/hcnendpoint.go b/vendor/github.com/Microsoft/hcsshim/hcn/hcnendpoint.go index 0c6c81a64a..d58335e5c6 100644 --- a/vendor/github.com/Microsoft/hcsshim/hcn/hcnendpoint.go +++ b/vendor/github.com/Microsoft/hcsshim/hcn/hcnendpoint.go @@ -313,13 +313,13 @@ func (endpoint *HostComputeEndpoint) Create() (*HostComputeEndpoint, error) { } // Delete Endpoint. -func (endpoint *HostComputeEndpoint) Delete() (*HostComputeEndpoint, error) { +func (endpoint *HostComputeEndpoint) Delete() error { logrus.Debugf("hcn::HostComputeEndpoint::Delete id=%s", endpoint.Id) if err := deleteEndpoint(endpoint.Id); err != nil { - return nil, err + return err } - return nil, nil + return nil } // ModifyEndpointSettings updates the Port/Policy of an Endpoint. diff --git a/vendor/github.com/Microsoft/hcsshim/hcn/hcnendpoint_test.go b/vendor/github.com/Microsoft/hcsshim/hcn/hcnendpoint_test.go index e20dba659a..748b8448eb 100644 --- a/vendor/github.com/Microsoft/hcsshim/hcn/hcnendpoint_test.go +++ b/vendor/github.com/Microsoft/hcsshim/hcn/hcnendpoint_test.go @@ -23,11 +23,11 @@ func TestCreateDeleteEndpoint(t *testing.T) { } fmt.Printf("Endpoint JSON:\n%s \n", jsonString) - _, err = Endpoint.Delete() + err = Endpoint.Delete() if err != nil { t.Fatal(err) } - _, err = network.Delete() + err = network.Delete() if err != nil { t.Fatal(err) } @@ -51,11 +51,11 @@ func TestGetEndpointById(t *testing.T) { t.Fatal("No Endpoint found") } - _, err = foundEndpoint.Delete() + err = foundEndpoint.Delete() if err != nil { t.Fatal(err) } - _, err = network.Delete() + err = network.Delete() if err != nil { t.Fatal(err) } @@ -79,11 +79,11 @@ func TestGetEndpointByName(t *testing.T) { t.Fatal("No Endpoint found") } - _, err = foundEndpoint.Delete() + err = foundEndpoint.Delete() if err != nil { t.Fatal(err) } - _, err = network.Delete() + err = network.Delete() if err != nil { t.Fatal(err) } @@ -107,11 +107,11 @@ func TestListEndpoints(t *testing.T) { t.Fatal("No Endpoint found") } - _, err = Endpoint.Delete() + err = Endpoint.Delete() if err != nil { t.Fatal(err) } - _, err = network.Delete() + err = network.Delete() if err != nil { t.Fatal(err) } @@ -135,11 +135,11 @@ func TestListEndpointsOfNetwork(t *testing.T) { t.Fatal("No Endpoint found") } - _, err = Endpoint.Delete() + err = Endpoint.Delete() if err != nil { t.Fatal(err) } - _, err = network.Delete() + err = network.Delete() if err != nil { t.Fatal(err) } @@ -168,15 +168,15 @@ func TestEndpointNamespaceAttachDetach(t *testing.T) { t.Fatal(err) } - _, err = namespace.Delete() + err = namespace.Delete() if err != nil { t.Fatal(err) } - _, err = endpoint.Delete() + err = endpoint.Delete() if err != nil { t.Fatal(err) } - _, err = network.Delete() + err = network.Delete() if err != nil { t.Fatal(err) } @@ -199,11 +199,11 @@ func TestCreateEndpointWithNamespace(t *testing.T) { t.Fatal("No Namespace detected.") } - _, err = Endpoint.Delete() + err = Endpoint.Delete() if err != nil { t.Fatal(err) } - _, err = network.Delete() + err = network.Delete() if err != nil { t.Fatal(err) } @@ -240,11 +240,11 @@ func TestApplyPolicyOnEndpoint(t *testing.T) { t.Fatal("No Endpoint Policies found") } - _, err = Endpoint.Delete() + err = Endpoint.Delete() if err != nil { t.Fatal(err) } - _, err = network.Delete() + err = network.Delete() if err != nil { t.Fatal(err) } @@ -287,11 +287,11 @@ func TestModifyEndpointSettings(t *testing.T) { t.Fatal("No Endpoint Policies found") } - _, err = endpoint.Delete() + err = endpoint.Delete() if err != nil { t.Fatal(err) } - _, err = network.Delete() + err = network.Delete() if err != nil { t.Fatal(err) } diff --git a/vendor/github.com/Microsoft/hcsshim/hcn/hcnglobals.go b/vendor/github.com/Microsoft/hcsshim/hcn/hcnglobals.go index b0fce0ba4f..29d13deac9 100644 --- a/vendor/github.com/Microsoft/hcsshim/hcn/hcnglobals.go +++ b/vendor/github.com/Microsoft/hcsshim/hcn/hcnglobals.go @@ -25,6 +25,12 @@ var ( HNSVersion1803 = Version{Major: 7, Minor: 2} // V2ApiSupport allows the use of V2 Api calls and V2 Schema. V2ApiSupport = Version{Major: 9, Minor: 1} + // Remote Subnet allows for Remote Subnet policies on Overlay networks + RemoteSubnetVersion = Version{Major: 9, Minor: 2} + // A Host Route policy allows for local container to local host communication Overlay networks + HostRouteVersion = Version{Major: 9, Minor: 2} + // HNS 10.2 allows for Direct Server Return for loadbalancing + DSRVersion = Version{Major: 10, Minor: 2} ) // GetGlobals returns the global properties of the HCN Service. diff --git a/vendor/github.com/Microsoft/hcsshim/hcn/hcnloadbalancer.go b/vendor/github.com/Microsoft/hcsshim/hcn/hcnloadbalancer.go index 40cc3f1e88..cff68e1350 100644 --- a/vendor/github.com/Microsoft/hcsshim/hcn/hcnloadbalancer.go +++ b/vendor/github.com/Microsoft/hcsshim/hcn/hcnloadbalancer.go @@ -10,10 +10,10 @@ import ( // LoadBalancerPortMapping is associated with HostComputeLoadBalancer type LoadBalancerPortMapping struct { - Protocol uint32 `json:",omitempty"` // EX: TCP = 6, UDP = 17 - InternalPort uint16 `json:",omitempty"` - ExternalPort uint16 `json:",omitempty"` - Flags uint32 `json:",omitempty"` // 0: None, 1: EnableILB, 2: LocalRoutedVip + Protocol uint32 `json:",omitempty"` // EX: TCP = 6, UDP = 17 + InternalPort uint16 `json:",omitempty"` + ExternalPort uint16 `json:",omitempty"` + Flags LoadBalancerPortMappingFlags `json:",omitempty"` } // HostComputeLoadBalancer represents software load balancer. @@ -24,9 +24,35 @@ type HostComputeLoadBalancer struct { FrontendVIPs []string `json:",omitempty"` PortMappings []LoadBalancerPortMapping `json:",omitempty"` SchemaVersion SchemaVersion `json:",omitempty"` - Flags uint32 `json:",omitempty"` // 0: None, 1: EnableDirectServerReturn + Flags LoadBalancerFlags `json:",omitempty"` // 0: None, 1: EnableDirectServerReturn } +//LoadBalancerFlags modify settings for a loadbalancer. +type LoadBalancerFlags uint32 + +var ( + // LoadBalancerFlagsNone is the default. + LoadBalancerFlagsNone LoadBalancerFlags = 0 + // LoadBalancerFlagsDSR enables Direct Server Return (DSR) + LoadBalancerFlagsDSR LoadBalancerFlags = 1 +) + +// LoadBalancerPortMappingFlags are special settings on a loadbalancer. +type LoadBalancerPortMappingFlags uint32 + +var ( + // LoadBalancerPortMappingFlagsNone is the default. + LoadBalancerPortMappingFlagsNone LoadBalancerPortMappingFlags + // LoadBalancerPortMappingFlagsILB enables internal loadbalancing. + LoadBalancerPortMappingFlagsILB LoadBalancerPortMappingFlags = 1 + // LoadBalancerPortMappingFlagsLocalRoutedVIP enables VIP access from the host. + LoadBalancerPortMappingFlagsLocalRoutedVIP LoadBalancerPortMappingFlags = 2 + // LoadBalancerPortMappingFlagsUseMux enables DSR for NodePort access of VIP. + LoadBalancerPortMappingFlagsUseMux LoadBalancerPortMappingFlags = 4 + // LoadBalancerPortMappingFlagsPreserveDIP delivers packets with destination IP as the VIP. + LoadBalancerPortMappingFlagsPreserveDIP LoadBalancerPortMappingFlags = 8 +) + func getLoadBalancer(loadBalancerGuid guid.GUID, query string) (*HostComputeLoadBalancer, error) { // Open loadBalancer. var ( @@ -234,20 +260,20 @@ func (loadBalancer *HostComputeLoadBalancer) Create() (*HostComputeLoadBalancer, } // Delete LoadBalancer. -func (loadBalancer *HostComputeLoadBalancer) Delete() (*HostComputeLoadBalancer, error) { +func (loadBalancer *HostComputeLoadBalancer) Delete() error { logrus.Debugf("hcn::HostComputeLoadBalancer::Delete id=%s", loadBalancer.Id) if err := deleteLoadBalancer(loadBalancer.Id); err != nil { - return nil, err + return err } - return nil, nil + return nil } // AddEndpoint add an endpoint to a LoadBalancer func (loadBalancer *HostComputeLoadBalancer) AddEndpoint(endpoint *HostComputeEndpoint) (*HostComputeLoadBalancer, error) { logrus.Debugf("hcn::HostComputeLoadBalancer::AddEndpoint loadBalancer=%s endpoint=%s", loadBalancer.Id, endpoint.Id) - _, err := loadBalancer.Delete() + err := loadBalancer.Delete() if err != nil { return nil, err } @@ -262,7 +288,7 @@ func (loadBalancer *HostComputeLoadBalancer) AddEndpoint(endpoint *HostComputeEn func (loadBalancer *HostComputeLoadBalancer) RemoveEndpoint(endpoint *HostComputeEndpoint) (*HostComputeLoadBalancer, error) { logrus.Debugf("hcn::HostComputeLoadBalancer::RemoveEndpoint loadBalancer=%s endpoint=%s", loadBalancer.Id, endpoint.Id) - _, err := loadBalancer.Delete() + err := loadBalancer.Delete() if err != nil { return nil, err } @@ -280,20 +306,8 @@ func (loadBalancer *HostComputeLoadBalancer) RemoveEndpoint(endpoint *HostComput } // AddLoadBalancer for the specified endpoints -func AddLoadBalancer(endpoints []HostComputeEndpoint, isILB bool, isDSR bool, sourceVIP string, frontendVIPs []string, protocol uint16, internalPort uint16, externalPort uint16) (*HostComputeLoadBalancer, error) { - logrus.Debugf("hcn::HostComputeLoadBalancer::AddLoadBalancer endpointId=%v, isILB=%v, sourceVIP=%s, frontendVIPs=%v, protocol=%v, internalPort=%v, externalPort=%v", endpoints, isILB, sourceVIP, frontendVIPs, protocol, internalPort, externalPort) - - var portMappingFlags uint32 - portMappingFlags = 0 - if isILB { - portMappingFlags = 1 - } - - var lbFlags uint32 - lbFlags = 0 - if isDSR { - lbFlags = 1 // EnableDirectServerReturn - } +func AddLoadBalancer(endpoints []HostComputeEndpoint, flags LoadBalancerFlags, portMappingFlags LoadBalancerPortMappingFlags, sourceVIP string, frontendVIPs []string, protocol uint16, internalPort uint16, externalPort uint16) (*HostComputeLoadBalancer, error) { + logrus.Debugf("hcn::HostComputeLoadBalancer::AddLoadBalancer endpointId=%v, LoadBalancerFlags=%v, LoadBalancerPortMappingFlags=%v, sourceVIP=%s, frontendVIPs=%v, protocol=%v, internalPort=%v, externalPort=%v", endpoints, flags, portMappingFlags, sourceVIP, frontendVIPs, protocol, internalPort, externalPort) loadBalancer := &HostComputeLoadBalancer{ SourceVIP: sourceVIP, @@ -310,7 +324,7 @@ func AddLoadBalancer(endpoints []HostComputeEndpoint, isILB bool, isDSR bool, so Major: 2, Minor: 0, }, - Flags: lbFlags, + Flags: flags, } for _, endpoint := range endpoints { diff --git a/vendor/github.com/Microsoft/hcsshim/hcn/hcnloadbalancer_test.go b/vendor/github.com/Microsoft/hcsshim/hcn/hcnloadbalancer_test.go index e06b337a50..785e265916 100644 --- a/vendor/github.com/Microsoft/hcsshim/hcn/hcnloadbalancer_test.go +++ b/vendor/github.com/Microsoft/hcsshim/hcn/hcnloadbalancer_test.go @@ -27,15 +27,15 @@ func TestCreateDeleteLoadBalancer(t *testing.T) { } fmt.Printf("LoadBalancer JSON:\n%s \n", jsonString) - _, err = loadBalancer.Delete() + err = loadBalancer.Delete() if err != nil { t.Fatal(err) } - _, err = endpoint.Delete() + err = endpoint.Delete() if err != nil { t.Fatal(err) } - _, err = network.Delete() + err = network.Delete() if err != nil { t.Fatal(err) } @@ -61,15 +61,15 @@ func TestGetLoadBalancerById(t *testing.T) { if foundLB == nil { t.Fatalf("No loadBalancer found") } - _, err = loadBalancer.Delete() + err = loadBalancer.Delete() if err != nil { t.Fatal(err) } - _, err = endpoint.Delete() + err = endpoint.Delete() if err != nil { t.Fatal(err) } - _, err = network.Delete() + err = network.Delete() if err != nil { t.Fatal(err) } @@ -116,19 +116,19 @@ func TestLoadBalancerAddRemoveEndpoint(t *testing.T) { t.Fatalf("Endpoint not removed from loadBalancer") } - _, err = loadBalancer.Delete() + err = loadBalancer.Delete() if err != nil { t.Fatal(err) } - _, err = secondEndpoint.Delete() + err = secondEndpoint.Delete() if err != nil { t.Fatal(err) } - _, err = endpoint.Delete() + err = endpoint.Delete() if err != nil { t.Fatal(err) } - _, err = network.Delete() + err = network.Delete() if err != nil { t.Fatal(err) } @@ -144,7 +144,7 @@ func TestAddLoadBalancer(t *testing.T) { t.Fatal(err) } - loadBalancer, err := AddLoadBalancer([]HostComputeEndpoint{*endpoint}, false, false, "10.0.0.1", []string{"1.1.1.2", "1.1.1.3"}, 6, 8080, 80) + loadBalancer, err := AddLoadBalancer([]HostComputeEndpoint{*endpoint}, LoadBalancerFlagsNone, LoadBalancerPortMappingFlagsNone, "10.0.0.1", []string{"1.1.1.2", "1.1.1.3"}, 6, 8080, 80) if err != nil { t.Fatal(err) } @@ -156,15 +156,15 @@ func TestAddLoadBalancer(t *testing.T) { t.Fatal(fmt.Errorf("No loadBalancer found")) } - _, err = loadBalancer.Delete() + err = loadBalancer.Delete() if err != nil { t.Fatal(err) } - _, err = endpoint.Delete() + err = endpoint.Delete() if err != nil { t.Fatal(err) } - _, err = network.Delete() + err = network.Delete() if err != nil { t.Fatal(err) } @@ -180,7 +180,8 @@ func TestAddDSRLoadBalancer(t *testing.T) { t.Fatal(err) } - loadBalancer, err := AddLoadBalancer([]HostComputeEndpoint{*endpoint}, false, true, "10.0.0.1", []string{"1.1.1.2", "1.1.1.3"}, 6, 8080, 80) + portMappings := LoadBalancerPortMappingFlagsPreserveDIP | LoadBalancerPortMappingFlagsUseMux + loadBalancer, err := AddLoadBalancer([]HostComputeEndpoint{*endpoint}, LoadBalancerFlagsDSR, portMappings, "10.0.0.1", []string{"1.1.1.2", "1.1.1.3"}, 6, 8080, 80) if err != nil { t.Fatal(err) } @@ -191,16 +192,27 @@ func TestAddDSRLoadBalancer(t *testing.T) { if foundLB == nil { t.Fatal(fmt.Errorf("No loadBalancer found")) } + if foundLB.Flags != 1 { + t.Fatal(fmt.Errorf("IsDSR is not set")) + } + + foundFlags := foundLB.PortMappings[0].Flags + if foundFlags&LoadBalancerPortMappingFlagsUseMux == 0 { + t.Fatal(fmt.Errorf("UseMux is not set")) + } + if foundFlags&LoadBalancerPortMappingFlagsPreserveDIP == 0 { + t.Fatal(fmt.Errorf("PreserveDIP is not set")) + } - _, err = loadBalancer.Delete() + err = loadBalancer.Delete() if err != nil { t.Fatal(err) } - _, err = endpoint.Delete() + err = endpoint.Delete() if err != nil { t.Fatal(err) } - _, err = network.Delete() + err = network.Delete() if err != nil { t.Fatal(err) } @@ -216,7 +228,7 @@ func TestAddILBLoadBalancer(t *testing.T) { t.Fatal(err) } - loadBalancer, err := AddLoadBalancer([]HostComputeEndpoint{*endpoint}, true, false, "10.0.0.1", []string{"1.1.1.2", "1.1.1.3"}, 6, 8080, 80) + loadBalancer, err := AddLoadBalancer([]HostComputeEndpoint{*endpoint}, LoadBalancerFlagsNone, LoadBalancerPortMappingFlagsILB, "10.0.0.1", []string{"1.1.1.2", "1.1.1.3"}, 6, 8080, 80) if err != nil { t.Fatal(err) } @@ -228,15 +240,20 @@ func TestAddILBLoadBalancer(t *testing.T) { t.Fatal(fmt.Errorf("No loadBalancer found")) } - _, err = loadBalancer.Delete() + foundFlags := foundLB.PortMappings[0].Flags + if foundFlags&LoadBalancerPortMappingFlagsILB == 0 { + t.Fatal(fmt.Errorf("Loadbalancer is not ILB")) + } + + err = loadBalancer.Delete() if err != nil { t.Fatal(err) } - _, err = endpoint.Delete() + err = endpoint.Delete() if err != nil { t.Fatal(err) } - _, err = network.Delete() + err = network.Delete() if err != nil { t.Fatal(err) } diff --git a/vendor/github.com/Microsoft/hcsshim/hcn/hcnnamespace.go b/vendor/github.com/Microsoft/hcsshim/hcn/hcnnamespace.go index 6a255cddc0..6dbef4f254 100644 --- a/vendor/github.com/Microsoft/hcsshim/hcn/hcnnamespace.go +++ b/vendor/github.com/Microsoft/hcsshim/hcn/hcnnamespace.go @@ -308,13 +308,13 @@ func (namespace *HostComputeNamespace) Create() (*HostComputeNamespace, error) { } // Delete Namespace. -func (namespace *HostComputeNamespace) Delete() (*HostComputeNamespace, error) { +func (namespace *HostComputeNamespace) Delete() error { logrus.Debugf("hcn::HostComputeNamespace::Delete id=%s", namespace.Id) if err := deleteNamespace(namespace.Id); err != nil { - return nil, err + return err } - return nil, nil + return nil } // Sync Namespace endpoints with the appropriate sandbox container holding the diff --git a/vendor/github.com/Microsoft/hcsshim/hcn/hcnnamespace_test.go b/vendor/github.com/Microsoft/hcsshim/hcn/hcnnamespace_test.go index 9aa6fab9e5..91e3b20b7c 100644 --- a/vendor/github.com/Microsoft/hcsshim/hcn/hcnnamespace_test.go +++ b/vendor/github.com/Microsoft/hcsshim/hcn/hcnnamespace_test.go @@ -30,7 +30,7 @@ func TestCreateDeleteNamespace(t *testing.T) { } fmt.Printf("Namespace JSON:\n%s \n", jsonString) - _, err = namespace.Delete() + err = namespace.Delete() if err != nil { t.Fatal(err) } @@ -50,7 +50,7 @@ func TestCreateDeleteNamespaceGuest(t *testing.T) { t.Fatal(err) } - _, err = hnsNamespace.Delete() + err = hnsNamespace.Delete() if err != nil { t.Fatal(err) } @@ -70,7 +70,7 @@ func TestGetNamespaceById(t *testing.T) { t.Fatal("No namespace found") } - _, err = namespace.Delete() + err = namespace.Delete() if err != nil { t.Fatal(err) } @@ -90,7 +90,7 @@ func TestListNamespaces(t *testing.T) { t.Fatal("No Namespaces found") } - _, err = namespace.Delete() + err = namespace.Delete() if err != nil { t.Fatal(err) } @@ -126,15 +126,15 @@ func TestGetNamespaceEndpointIds(t *testing.T) { t.Fatal(err) } - _, err = namespace.Delete() + err = namespace.Delete() if err != nil { t.Fatal(err) } - _, err = endpoint.Delete() + err = endpoint.Delete() if err != nil { t.Fatal(err) } - _, err = network.Delete() + err = network.Delete() if err != nil { t.Fatal(err) } @@ -154,7 +154,7 @@ func TestGetNamespaceContainers(t *testing.T) { t.Fatal("Found containers when none should exist") } - _, err = namespace.Delete() + err = namespace.Delete() if err != nil { t.Fatal(err) } @@ -190,15 +190,15 @@ func TestAddRemoveNamespaceEndpoint(t *testing.T) { t.Fatal(err) } - _, err = namespace.Delete() + err = namespace.Delete() if err != nil { t.Fatal(err) } - _, err = endpoint.Delete() + err = endpoint.Delete() if err != nil { t.Fatal(err) } - _, err = network.Delete() + err = network.Delete() if err != nil { t.Fatal(err) } @@ -245,15 +245,15 @@ func TestModifyNamespaceSettings(t *testing.T) { t.Fatal(err) } - _, err = namespace.Delete() + err = namespace.Delete() if err != nil { t.Fatal(err) } - _, err = endpoint.Delete() + err = endpoint.Delete() if err != nil { t.Fatal(err) } - _, err = network.Delete() + err = network.Delete() if err != nil { t.Fatal(err) } @@ -282,7 +282,7 @@ func TestSyncNamespaceHostDefault(t *testing.T) { t.Fatal(err) } - _, err = hnsNamespace.Delete() + err = hnsNamespace.Delete() if err != nil { t.Fatal(err) } @@ -309,7 +309,7 @@ func TestSyncNamespaceHost(t *testing.T) { t.Fatal(err) } - _, err = hnsNamespace.Delete() + err = hnsNamespace.Delete() if err != nil { t.Fatal(err) } @@ -336,7 +336,7 @@ func TestSyncNamespaceGuestNoReg(t *testing.T) { t.Fatal(err) } - _, err = hnsNamespace.Delete() + err = hnsNamespace.Delete() if err != nil { t.Fatal(err) } @@ -363,7 +363,7 @@ func TestSyncNamespaceGuestDefaultNoReg(t *testing.T) { t.Fatal(err) } - _, err = hnsNamespace.Delete() + err = hnsNamespace.Delete() if err != nil { t.Fatal(err) } @@ -404,7 +404,7 @@ func TestSyncNamespaceGuest(t *testing.T) { if err != nil { t.Fatal(err) } - _, err = hnsNamespace.Delete() + err = hnsNamespace.Delete() if err != nil { t.Fatal(err) } @@ -444,7 +444,7 @@ func TestSyncNamespaceGuestDefault(t *testing.T) { if err != nil { t.Fatal(err) } - _, err = hnsNamespace.Delete() + err = hnsNamespace.Delete() if err != nil { t.Fatal(err) } diff --git a/vendor/github.com/Microsoft/hcsshim/hcn/hcnnetwork.go b/vendor/github.com/Microsoft/hcsshim/hcn/hcnnetwork.go index 45c876e246..b5f1db8b22 100644 --- a/vendor/github.com/Microsoft/hcsshim/hcn/hcnnetwork.go +++ b/vendor/github.com/Microsoft/hcsshim/hcn/hcnnetwork.go @@ -42,7 +42,7 @@ type MacPool struct { // Dns (Domain Name System is associated with a network. type Dns struct { - Suffix string `json:",omitempty"` + Domain string `json:",omitempty"` Search []string `json:",omitempty"` ServerList []string `json:",omitempty"` Options []string `json:",omitempty"` @@ -62,6 +62,15 @@ const ( Overlay NetworkType = "Overlay" ) +// NetworkFlags are various network flags. +type NetworkFlags uint32 + +// NetworkFlags const +const ( + None NetworkFlags = 0 + EnableNonPersistent NetworkFlags = 8 +) + // HostComputeNetwork represents a network type HostComputeNetwork struct { Id string `json:"ID,omitempty"` @@ -71,7 +80,7 @@ type HostComputeNetwork struct { MacPool MacPool `json:",omitempty"` Dns Dns `json:",omitempty"` Ipams []Ipam `json:",omitempty"` - Flags uint32 `json:",omitempty"` // 0: None + Flags NetworkFlags `json:",omitempty"` // 0: None SchemaVersion SchemaVersion `json:",omitempty"` } @@ -326,13 +335,13 @@ func (network *HostComputeNetwork) Create() (*HostComputeNetwork, error) { } // Delete Network. -func (network *HostComputeNetwork) Delete() (*HostComputeNetwork, error) { +func (network *HostComputeNetwork) Delete() error { logrus.Debugf("hcn::HostComputeNetwork::Delete id=%s", network.Id) if err := deleteNetwork(network.Id); err != nil { - return nil, err + return err } - return nil, nil + return nil } // ModifyNetworkSettings updates the Policy for a network. diff --git a/vendor/github.com/Microsoft/hcsshim/hcn/hcnnetwork_test.go b/vendor/github.com/Microsoft/hcsshim/hcn/hcnnetwork_test.go index a773bb6938..eaac255547 100644 --- a/vendor/github.com/Microsoft/hcsshim/hcn/hcnnetwork_test.go +++ b/vendor/github.com/Microsoft/hcsshim/hcn/hcnnetwork_test.go @@ -18,7 +18,7 @@ func TestCreateDeleteNetwork(t *testing.T) { t.Fatal(err) } fmt.Printf("Network JSON:\n%s \n", jsonString) - _, err = network.Delete() + err = network.Delete() if err != nil { t.Fatal(err) } @@ -36,7 +36,7 @@ func TestGetNetworkByName(t *testing.T) { if network == nil { t.Fatal("No Network found") } - _, err = network.Delete() + err = network.Delete() if err != nil { t.Fatal(err) } @@ -54,7 +54,7 @@ func TestGetNetworkById(t *testing.T) { if network == nil { t.Fatal("No Network found") } - _, err = network.Delete() + err = network.Delete() if err != nil { t.Fatal(err) } @@ -67,20 +67,34 @@ func TestListNetwork(t *testing.T) { } } -func TestAddRemoveRemoteSubnetRoutePolicy(t *testing.T) { - +func testNetworkPolicy(t *testing.T, policiesToTest *PolicyNetworkRequest) { network, err := CreateTestOverlayNetwork() if err != nil { t.Fatal(err) } - remoteSubnetRoutePolicy, err := HcnCreateTestRemoteSubnetRoute() + network.AddPolicy(*policiesToTest) + + //Reload the network object from HNS. + network, err = GetNetworkByID(network.Id) if err != nil { t.Fatal(err) } - //Add Policy - network.AddPolicy(*remoteSubnetRoutePolicy) + for _, policyToTest := range policiesToTest.Policies { + foundPolicy := false + for _, policy := range network.Policies { + if policy.Type == policyToTest.Type { + foundPolicy = true + break + } + } + if !foundPolicy { + t.Fatalf("Could not find %s policy on network.", policyToTest.Type) + } + } + + network.RemovePolicy(*policiesToTest) //Reload the network object from HNS. network, err = GetNetworkByID(network.Id) @@ -88,19 +102,51 @@ func TestAddRemoveRemoteSubnetRoutePolicy(t *testing.T) { t.Fatal(err) } - foundPolicy := false - for _, policy := range network.Policies { - if policy.Type == RemoteSubnetRoute { - foundPolicy = true - break + for _, policyToTest := range policiesToTest.Policies { + foundPolicy := false + for _, policy := range network.Policies { + if policy.Type == policyToTest.Type { + foundPolicy = true + break + } } + if foundPolicy { + t.Fatalf("Found %s policy on network when it should have been deleted.", policyToTest.Type) + } + } + + err = network.Delete() + if err != nil { + t.Fatal(err) + } +} + +func TestAddRemoveRemoteSubnetRoutePolicy(t *testing.T) { + + remoteSubnetRoutePolicy, err := HcnCreateTestRemoteSubnetRoute() + if err != nil { + t.Fatal(err) } - if !foundPolicy { - t.Fatalf("Could not find remote subnet route policy on network.") + + testNetworkPolicy(t, remoteSubnetRoutePolicy) +} + +func TestAddRemoveHostRoutePolicy(t *testing.T) { + + hostRoutePolicy, err := HcnCreateTestHostRoute() + if err != nil { + t.Fatal(err) } - //Remove Policy. - network.RemovePolicy(*remoteSubnetRoutePolicy) + testNetworkPolicy(t, hostRoutePolicy) +} + +func TestNetworkFlags(t *testing.T) { + + network, err := CreateTestOverlayNetwork() + if err != nil { + t.Fatal(err) + } //Reload the network object from HNS. network, err = GetNetworkByID(network.Id) @@ -108,18 +154,11 @@ func TestAddRemoveRemoteSubnetRoutePolicy(t *testing.T) { t.Fatal(err) } - foundPolicy = false - for _, policy := range network.Policies { - if policy.Type == RemoteSubnetRoute { - foundPolicy = true - break - } - } - if foundPolicy { - t.Fatalf("Found remote subnet route policy on network when it should have been deleted.") + if network.Flags != EnableNonPersistent { + t.Errorf("EnableNonPersistent flag (%d) is not set on network", EnableNonPersistent) } - _, err = network.Delete() + err = network.Delete() if err != nil { t.Fatal(err) } diff --git a/vendor/github.com/Microsoft/hcsshim/hcn/hcnpolicy.go b/vendor/github.com/Microsoft/hcsshim/hcn/hcnpolicy.go index 70442e191b..6b12d73c60 100644 --- a/vendor/github.com/Microsoft/hcsshim/hcn/hcnpolicy.go +++ b/vendor/github.com/Microsoft/hcsshim/hcn/hcnpolicy.go @@ -40,6 +40,7 @@ const ( InterfaceConstraint NetworkPolicyType = "InterfaceConstraint" ProviderAddress NetworkPolicyType = "ProviderAddress" RemoteSubnetRoute NetworkPolicyType = "RemoteSubnetRoute" + HostRoute NetworkPolicyType = "HostRoute" ) // NetworkPolicy is a collection of Policy settings for a Network. diff --git a/vendor/github.com/Microsoft/hcsshim/hcn/hcnsupport.go b/vendor/github.com/Microsoft/hcsshim/hcn/hcnsupport.go index 3eccd15ac2..9b5df20301 100644 --- a/vendor/github.com/Microsoft/hcsshim/hcn/hcnsupport.go +++ b/vendor/github.com/Microsoft/hcsshim/hcn/hcnsupport.go @@ -6,8 +6,11 @@ import ( // SupportedFeatures are the features provided by the Service. type SupportedFeatures struct { - Acl AclFeatures `json:"ACL"` - Api ApiSupport `json:"API"` + Acl AclFeatures `json:"ACL"` + Api ApiSupport `json:"API"` + RemoteSubnet bool `json:"RemoteSubnet"` + HostRoute bool `json:"HostRoute"` + DSR bool `json:"DSR"` } // AclFeatures are the supported ACL possibilities. @@ -47,6 +50,10 @@ func GetSupportedFeatures() SupportedFeatures { V1: true, // HNSCall is still available. } + features.RemoteSubnet = isFeatureSupported(globals.Version, RemoteSubnetVersion) + features.HostRoute = isFeatureSupported(globals.Version, HostRouteVersion) + features.DSR = isFeatureSupported(globals.Version, DSRVersion) + return features } diff --git a/vendor/github.com/Microsoft/hcsshim/hcn/hcnsupport_test.go b/vendor/github.com/Microsoft/hcsshim/hcn/hcnsupport_test.go index ee8f929abb..b4a0211580 100644 --- a/vendor/github.com/Microsoft/hcsshim/hcn/hcnsupport_test.go +++ b/vendor/github.com/Microsoft/hcsshim/hcn/hcnsupport_test.go @@ -18,8 +18,45 @@ func TestSupportedFeatures(t *testing.T) { } func TestV2ApiSupport(t *testing.T) { + supportedFeatures := GetSupportedFeatures() err := V2ApiSupported() - if err != nil { + if supportedFeatures.Api.V2 && err != nil { + t.Fatal(err) + } + if !supportedFeatures.Api.V2 && err == nil { + t.Fatal(err) + } +} + +func TestRemoteSubnetSupport(t *testing.T) { + supportedFeatures := GetSupportedFeatures() + err := RemoteSubnetSupported() + if supportedFeatures.RemoteSubnet && err != nil { + t.Fatal(err) + } + if !supportedFeatures.RemoteSubnet && err == nil { + t.Fatal(err) + } +} + +func TestHostRouteSupport(t *testing.T) { + supportedFeatures := GetSupportedFeatures() + err := HostRouteSupported() + if supportedFeatures.HostRoute && err != nil { + t.Fatal(err) + } + if !supportedFeatures.HostRoute && err == nil { + t.Fatal(err) + } +} + +func TestDSRSupport(t *testing.T) { + supportedFeatures := GetSupportedFeatures() + err := DSRSupported() + if supportedFeatures.DSR && err != nil { + t.Fatal(err) + } + if !supportedFeatures.DSR && err == nil { t.Fatal(err) } } diff --git a/vendor/github.com/Microsoft/hcsshim/hcn/hcnutils_test.go b/vendor/github.com/Microsoft/hcsshim/hcn/hcnutils_test.go index 0fbe566ce2..afc40cf45d 100644 --- a/vendor/github.com/Microsoft/hcsshim/hcn/hcnutils_test.go +++ b/vendor/github.com/Microsoft/hcsshim/hcn/hcnutils_test.go @@ -13,7 +13,7 @@ func cleanup(networkName string) { return } if testNetwork != nil { - _, err := testNetwork.Delete() + err := testNetwork.Delete() if err != nil { return } @@ -87,6 +87,7 @@ func CreateTestOverlayNetwork() (*HostComputeNetwork, error) { }, }, }, + Flags: EnableNonPersistent, SchemaVersion: SchemaVersion{ Major: 2, Minor: 0, @@ -251,3 +252,16 @@ func HcnCreateTestRemoteSubnetRoute() (*PolicyNetworkRequest, error) { return &networkRequest, nil } + +func HcnCreateTestHostRoute() (*PolicyNetworkRequest, error) { + hostRoutePolicy := NetworkPolicy{ + Type: HostRoute, + Settings: []byte("{}"), + } + + networkRequest := PolicyNetworkRequest{ + Policies: []NetworkPolicy{hostRoutePolicy}, + } + + return &networkRequest, nil +} diff --git a/vendor/github.com/Microsoft/hcsshim/hcn/hcnv1schema_test.go b/vendor/github.com/Microsoft/hcsshim/hcn/hcnv1schema_test.go index a45d5cb1fd..fd300ed030 100644 --- a/vendor/github.com/Microsoft/hcsshim/hcn/hcnv1schema_test.go +++ b/vendor/github.com/Microsoft/hcsshim/hcn/hcnv1schema_test.go @@ -41,7 +41,7 @@ func TestV1Network(t *testing.T) { t.Fail() } - _, err = network.Delete() + err = network.Delete() if err != nil { t.Fatal(err) t.Fail() @@ -97,13 +97,13 @@ func TestV1Endpoint(t *testing.T) { t.Fail() } - _, err = endpoint.Delete() + err = endpoint.Delete() if err != nil { t.Fatal(err) t.Fail() } - _, err = network.Delete() + err = network.Delete() if err != nil { t.Fatal(err) t.Fail() diff --git a/vendor/github.com/Microsoft/hcsshim/internal/cmd/createuvm/createuvm.go b/vendor/github.com/Microsoft/hcsshim/internal/cmd/createuvm/createuvm.go deleted file mode 100644 index 9bee7e34dc..0000000000 --- a/vendor/github.com/Microsoft/hcsshim/internal/cmd/createuvm/createuvm.go +++ /dev/null @@ -1,37 +0,0 @@ -package main - -// createuvm does what it says on the tin. Simple test utility for looking -// at startup timing. - -import ( - "bufio" - "fmt" - "os" - - "github.com/Microsoft/hcsshim/internal/uvm" -) - -func main() { - - fmt.Println("Creating...") - lcowUVM, err := uvm.Create(&uvm.UVMOptions{OperatingSystem: "linux", ID: "uvm"}) - if err != nil { - fmt.Fprintf(os.Stderr, "Failed to create utility VM: %s", err) - os.Exit(-1) - } - - fmt.Print("Created. Press 'Enter' to start...") - bufio.NewReader(os.Stdin).ReadBytes('\n') - - fmt.Println("Starting...") - if err := lcowUVM.Start(); err != nil { - fmt.Fprintf(os.Stderr, "Failed to start utility VM: %s", err) - os.Exit(-1) - } - - fmt.Print("Started. Use `hcsdiag console -uvm uvm`. Press 'Enter' to terminate...") - bufio.NewReader(os.Stdin).ReadBytes('\n') - - lcowUVM.Terminate() - os.Exit(0) -} diff --git a/vendor/github.com/Microsoft/hcsshim/internal/cmd/rootfs2vhd/rootfs2vhd.go b/vendor/github.com/Microsoft/hcsshim/internal/cmd/rootfs2vhd/rootfs2vhd.go deleted file mode 100644 index d79446f470..0000000000 --- a/vendor/github.com/Microsoft/hcsshim/internal/cmd/rootfs2vhd/rootfs2vhd.go +++ /dev/null @@ -1,210 +0,0 @@ -package main - -// rootfs2vhd is a simple utility to convert rootfs.tar.gz generated by -// the Microsoft/opengcs repos build.ps1 script to rootfs.vhd which LCOW -// can use for the root filesystem added on VPMem (as opposed to an initrd). -// -// It's not pretty, but enough to get the job done. It does require -// the Hyper-V RSAT to be installed for shelling out to New-VHD. - -import ( - "bufio" - "bytes" - "fmt" - "os" - "os/exec" - "path/filepath" - "strings" - "time" - - "github.com/Microsoft/hcsshim/internal/lcow" - "github.com/Microsoft/hcsshim/internal/uvm" - "github.com/Microsoft/hcsshim/internal/wclayer" - specs "github.com/opencontainers/runtime-spec/specs-go" - "github.com/sirupsen/logrus" - "github.com/urfave/cli" -) - -var ( - debug = false - pause = false -) - -func main() { - - app := cli.NewApp() - cwd, _ := filepath.Abs("./") - - app.Flags = []cli.Flag{ - cli.StringFlag{ - Name: "i", - Usage: "Full path to .tar.gz of the root file system to be converted", - Value: cwd + `\rootfs.tar.gz`, - }, - cli.StringFlag{ - Name: "o", - Usage: "Full path to output filename", - Value: cwd + `\rootfs.vhd`, - }, - cli.IntFlag{ - Name: "s", - Usage: "Size in MB of the new VHD", - Value: 19, - }, - cli.BoolFlag{ - Name: "D", - Usage: "Debug mode", - }, - cli.BoolFlag{ - Name: "P", - Usage: "Pause when complete but before tearing down the utility VM", - }, - } - app.Action = func(c *cli.Context) { - rootfs2vhd(c) - } - fmt.Printf("\nrootfs2vhd: Converts an LCOW root filesystem tar.gz to a VHD\n\n") - if err := app.Run(os.Args); err != nil { - os.Exit(-1) - } -} - -func rootfs2vhd(c *cli.Context) { - sourceRootFS := c.String("i") - destFile := c.String("o") - debug = c.Bool("D") - pause = c.Bool("P") - - if debug { - logrus.SetLevel(logrus.DebugLevel) - logrus.SetFormatter(&logrus.TextFormatter{FullTimestamp: true}) - } - - if _, err := os.Stat(sourceRootFS); err != nil { - fmt.Fprintf(os.Stderr, "%s not found\n", sourceRootFS) - os.Exit(-1) - } - - if _, err := os.Stat(destFile); err == nil { - fmt.Fprintf(os.Stderr, "%s exists. Not overwriting\n", destFile) - os.Exit(-1) - } - - // TODO The right thing to do here is modify go-winio to be able to create this type of disk. - fmt.Printf("- Creating %s...\n", destFile) - if _, err := exec.Command(`powershell`, `-command`, fmt.Sprintf(`New-VHD %s -SizeBytes %dMB -fixed`, destFile, c.Int("s"))).Output(); err != nil { - fmt.Fprintf(os.Stderr, string(err.(*exec.ExitError).Stderr)) - os.Exit(-1) - } - - fmt.Println("- Creating an LCOW utility VM...") - lcowUVM, err := uvm.Create(&uvm.UVMOptions{OperatingSystem: "linux", ID: "rootfs2vhd"}) - if err != nil { - fmt.Fprintf(os.Stderr, "Failed to create utility VM: %s", err) - os.Exit(-1) - } - - fmt.Println("- Starting it....") - if err := lcowUVM.Start(); err != nil { - fmt.Fprintf(os.Stderr, "Failed to start utility VM: %s", err) - os.Exit(-1) - } - - fmt.Printf("- Adding %s as read-only...\n", filepath.Dir(sourceRootFS)) - if err := lcowUVM.AddPlan9(filepath.Dir(sourceRootFS), `/fssource`, true); err != nil { - fmt.Fprintf(os.Stderr, "failed to add %s: %s", filepath.Dir(sourceRootFS), err) - lcowUVM.Terminate() - lcowUVM.Wait() - os.Exit(-1) - } - - fmt.Printf("- Granting access to %s...\n", destFile) - if err := wclayer.GrantVmAccess(lcowUVM.ID(), destFile); err != nil { - fmt.Fprintf(os.Stderr, "Failed to grant access: %s", err) - lcowUVM.Terminate() - lcowUVM.Wait() - os.Exit(-1) - } - - fmt.Println("- Hot-adding SCSI disk...") - controller, lun, err := lcowUVM.AddSCSI(destFile, "") // No destination as not formatted - if err != nil { - fmt.Fprintf(os.Stderr, "Failed to add SCSI: %s", err) - lcowUVM.Terminate() - lcowUVM.Wait() - os.Exit(-1) - } - fmt.Printf("- Added at SCSI %d:%d\n", controller, lun) - - uvmCommand(lcowUVM, []string{"test", "-d", fmt.Sprintf("/sys/bus/scsi/devices/%d:0:0:%d", controller, lun)}) - device := fmt.Sprintf(`/dev/%s`, strings.TrimSpace(uvmCommand(lcowUVM, []string{"ls", fmt.Sprintf("/sys/bus/scsi/devices/%d:0:0:%d/block", controller, lun)}))) - fmt.Printf("- Located at %s\n", device) - - fmt.Printf("- Formatting ext4...\n") - uvmCommand(lcowUVM, []string{"mkfs.ext4", "-q", "-E", "lazy_itable_init=1", "-O", `^has_journal,sparse_super2,uninit_bg,^resize_inode`, device}) - - fmt.Printf("- Extracting %s...\n", filepath.Base(sourceRootFS)) - uvmCommand(lcowUVM, []string{"mkdir", "/target"}) - uvmCommand(lcowUVM, []string{"mount", device, "/target"}) - uvmCommand(lcowUVM, []string{"rm", "-rf", "/target/lost+found"}) - uvmCommand(lcowUVM, []string{"sh", "-c", fmt.Sprintf(`"cd /target; gzip -dc /fssource/%s | tar x"`, filepath.Base(sourceRootFS))}) - fmt.Println("- Extract complete!") - fmt.Printf("\n%s\n", uvmCommand(lcowUVM, []string{"df", "/target"})) - possiblePause() - uvmCommand(lcowUVM, []string{"umount", device}) - - fmt.Println("- Removing SCSI disk...") - if err := lcowUVM.RemoveSCSI(destFile); err != nil { - fmt.Fprintf(os.Stderr, "Failed to remove SCSI: %s", err) - lcowUVM.Terminate() - lcowUVM.Wait() - os.Exit(-1) - } - - lcowUVM.Terminate() - - fmt.Printf("\nSuccess\n") - os.Exit(0) -} - -func uvmCommand(lcowUVM *uvm.UtilityVM, args []string) string { - timeout := 30 * time.Second - var outB, errB bytes.Buffer - p, _, err := lcow.CreateProcess(&lcow.ProcessOptions{ - HCSSystem: lcowUVM.ComputeSystem(), - CreateInUtilityVm: true, - CopyTimeout: timeout, - Process: &specs.Process{Args: args}, - Stdout: &outB, - Stderr: &errB, - }) - if err != nil { - fmt.Fprintf(os.Stderr, "%+v failed:\n%s\n%s)", args, err, errB.String()) - possiblePause() - lcowUVM.Terminate() - os.Exit(-1) - } - defer p.Close() - p.WaitTimeout(timeout) - ec, err := p.ExitCode() - if err != nil { - fmt.Fprintf(os.Stderr, "%+v failed to get exit code:\n%s\n%s)", args, err, errB.String()) - possiblePause() - lcowUVM.Terminate() - os.Exit(-1) - } - if ec != 0 { - fmt.Fprintf(os.Stderr, "%+v had non-zero exit code:\n%s)", args, errB.String()) - possiblePause() - lcowUVM.Terminate() - os.Exit(-1) - } - return outB.String() -} - -func possiblePause() { - if pause { - fmt.Print("Press 'Enter' to continue...") - bufio.NewReader(os.Stdin).ReadBytes('\n') - } -} diff --git a/vendor/github.com/Microsoft/hcsshim/internal/guestrequest/types.go b/vendor/github.com/Microsoft/hcsshim/internal/guestrequest/types.go index 9f926c6be7..5d3d0dfef1 100644 --- a/vendor/github.com/Microsoft/hcsshim/internal/guestrequest/types.go +++ b/vendor/github.com/Microsoft/hcsshim/internal/guestrequest/types.go @@ -1,6 +1,8 @@ package guestrequest -import "github.com/Microsoft/hcsshim/internal/schema2" +import ( + "github.com/Microsoft/hcsshim/internal/schema2" +) // Arguably, many of these (at least CombinedLayers) should have been generated // by swagger. @@ -47,6 +49,19 @@ type LCOWMappedVPMemDevice struct { MountPath string `json:"MountPath,omitempty"` // /tmp/pN } +type LCOWNetworkAdapter struct { + NamespaceID string `json:",omitempty"` + ID string `json:",omitempty"` + MacAddress string `json:",omitempty"` + IPAddress string `json:",omitempty"` + PrefixLength uint8 `json:",omitempty"` + GatewayAddress string `json:",omitempty"` + DNSSuffix string `json:",omitempty"` + DNSServerList string `json:",omitempty"` + EnableLowMetric bool `json:",omitempty"` + EncapOverhead uint16 `json:",omitempty"` +} + type ResourceType string const ( diff --git a/vendor/github.com/Microsoft/hcsshim/internal/hcs/process.go b/vendor/github.com/Microsoft/hcsshim/internal/hcs/process.go index 67b9ecb57b..4c35c732cc 100644 --- a/vendor/github.com/Microsoft/hcsshim/internal/hcs/process.go +++ b/vendor/github.com/Microsoft/hcsshim/internal/hcs/process.go @@ -130,10 +130,9 @@ func (process *Process) Signal(options guestrequest.SignalProcessOptions) (err e optionsStr := string(optionsb) var resultp *uint16 - completed := false - go syscallWatcher(process.logctx, &completed) - err = hcsSignalProcess(process.handle, optionsStr, &resultp) - completed = true + syscallWatcher(process.logctx, func() { + err = hcsSignalProcess(process.handle, optionsStr, &resultp) + }) events := processHcsResult(resultp) if err != nil { return makeProcessError(process, operation, err, events) @@ -156,10 +155,9 @@ func (process *Process) Kill() (err error) { } var resultp *uint16 - completed := false - go syscallWatcher(process.logctx, &completed) - err = hcsTerminateProcess(process.handle, &resultp) - completed = true + syscallWatcher(process.logctx, func() { + err = hcsTerminateProcess(process.handle, &resultp) + }) events := processHcsResult(resultp) if err != nil { return makeProcessError(process, operation, err, events) @@ -251,10 +249,9 @@ func (process *Process) Properties() (_ *ProcessStatus, err error) { resultp *uint16 propertiesp *uint16 ) - completed := false - go syscallWatcher(process.logctx, &completed) - err = hcsGetProcessProperties(process.handle, &propertiesp, &resultp) - completed = true + syscallWatcher(process.logctx, func() { + err = hcsGetProcessProperties(process.handle, &propertiesp, &resultp) + }) events := processHcsResult(resultp) if err != nil { return nil, makeProcessError(process, operation, err, events) diff --git a/vendor/github.com/Microsoft/hcsshim/internal/hcs/system.go b/vendor/github.com/Microsoft/hcsshim/internal/hcs/system.go index 09d6f3d66c..50f768b729 100644 --- a/vendor/github.com/Microsoft/hcsshim/internal/hcs/system.go +++ b/vendor/github.com/Microsoft/hcsshim/internal/hcs/system.go @@ -97,13 +97,13 @@ func CreateComputeSystem(id string, hcsDocumentInterface interface{}) (_ *System Debug("HCS ComputeSystem Document") var ( - resultp *uint16 - identity syscall.Handle + resultp *uint16 + identity syscall.Handle + createError error ) - completed := false - go syscallWatcher(computeSystem.logctx, &completed) - createError := hcsCreateComputeSystem(id, hcsDocument, identity, &computeSystem.handle, &resultp) - completed = true + syscallWatcher(computeSystem.logctx, func() { + createError = hcsCreateComputeSystem(id, hcsDocument, identity, &computeSystem.handle, &resultp) + }) if createError == nil || IsPending(createError) { if err = computeSystem.registerCallback(); err != nil { @@ -133,7 +133,13 @@ func OpenComputeSystem(id string) (_ *System, err error) { computeSystem := newSystem(id) computeSystem.logOperationBegin(operation) - defer func() { computeSystem.logOperationEnd(err) }() + defer func() { + if IsNotExist(err) { + computeSystem.logOperationEnd(nil) + } else { + computeSystem.logOperationEnd(err) + } + }() var ( handle hcsSystem @@ -193,10 +199,10 @@ func GetComputeSystems(q schema1.ComputeSystemQuery) (_ []schema1.ContainerPrope resultp *uint16 computeSystemsp *uint16 ) - completed := false - go syscallWatcher(fields, &completed) - err = hcsEnumerateComputeSystems(query, &computeSystemsp, &resultp) - completed = true + + syscallWatcher(fields, func() { + err = hcsEnumerateComputeSystems(query, &computeSystemsp, &resultp) + }) events := processHcsResult(resultp) if err != nil { return nil, &HcsError{Op: operation, Err: err, Events: events} @@ -254,10 +260,9 @@ func (computeSystem *System) Start() (err error) { } var resultp *uint16 - completed := false - go syscallWatcher(computeSystem.logctx, &completed) - err = hcsStartComputeSystem(computeSystem.handle, "", &resultp) - completed = true + syscallWatcher(computeSystem.logctx, func() { + err = hcsStartComputeSystem(computeSystem.handle, "", &resultp) + }) events, err := processAsyncHcsResult(err, resultp, computeSystem.callbackNumber, hcsNotificationSystemStartCompleted, &timeout.SystemStart) if err != nil { return makeSystemError(computeSystem, "Start", "", err, events) @@ -279,17 +284,22 @@ func (computeSystem *System) Shutdown() (err error) { operation := "hcsshim::ComputeSystem::Shutdown" computeSystem.logOperationBegin(operation) - defer func() { computeSystem.logOperationEnd(err) }() + defer func() { + if IsAlreadyStopped(err) { + computeSystem.logOperationEnd(nil) + } else { + computeSystem.logOperationEnd(err) + } + }() if computeSystem.handle == 0 { return makeSystemError(computeSystem, "Shutdown", "", ErrAlreadyClosed, nil) } var resultp *uint16 - completed := false - go syscallWatcher(computeSystem.logctx, &completed) - err = hcsShutdownComputeSystem(computeSystem.handle, "", &resultp) - completed = true + syscallWatcher(computeSystem.logctx, func() { + err = hcsShutdownComputeSystem(computeSystem.handle, "", &resultp) + }) events := processHcsResult(resultp) if err != nil { return makeSystemError(computeSystem, "Shutdown", "", err, events) @@ -306,17 +316,22 @@ func (computeSystem *System) Terminate() (err error) { operation := "hcsshim::ComputeSystem::Terminate" computeSystem.logOperationBegin(operation) - defer func() { computeSystem.logOperationEnd(err) }() + defer func() { + if IsPending(err) { + computeSystem.logOperationEnd(nil) + } else { + computeSystem.logOperationEnd(err) + } + }() if computeSystem.handle == 0 { return makeSystemError(computeSystem, "Terminate", "", ErrAlreadyClosed, nil) } var resultp *uint16 - completed := false - go syscallWatcher(computeSystem.logctx, &completed) - err = hcsTerminateComputeSystem(computeSystem.handle, "", &resultp) - completed = true + syscallWatcher(computeSystem.logctx, func() { + err = hcsTerminateComputeSystem(computeSystem.handle, "", &resultp) + }) events := processHcsResult(resultp) if err != nil && err != ErrVmcomputeAlreadyStopped { return makeSystemError(computeSystem, "Terminate", "", err, events) @@ -387,10 +402,9 @@ func (computeSystem *System) Properties(types ...schema1.PropertyType) (_ *schem Debug("HCS ComputeSystem Properties Query") var resultp, propertiesp *uint16 - completed := false - go syscallWatcher(computeSystem.logctx, &completed) - err = hcsGetComputeSystemProperties(computeSystem.handle, string(queryj), &propertiesp, &resultp) - completed = true + syscallWatcher(computeSystem.logctx, func() { + err = hcsGetComputeSystemProperties(computeSystem.handle, string(queryj), &propertiesp, &resultp) + }) events := processHcsResult(resultp) if err != nil { return nil, makeSystemError(computeSystem, "Properties", "", err, events) @@ -422,10 +436,9 @@ func (computeSystem *System) Pause() (err error) { } var resultp *uint16 - completed := false - go syscallWatcher(computeSystem.logctx, &completed) - err = hcsPauseComputeSystem(computeSystem.handle, "", &resultp) - completed = true + syscallWatcher(computeSystem.logctx, func() { + err = hcsPauseComputeSystem(computeSystem.handle, "", &resultp) + }) events, err := processAsyncHcsResult(err, resultp, computeSystem.callbackNumber, hcsNotificationSystemPauseCompleted, &timeout.SystemPause) if err != nil { return makeSystemError(computeSystem, "Pause", "", err, events) @@ -448,10 +461,9 @@ func (computeSystem *System) Resume() (err error) { } var resultp *uint16 - completed := false - go syscallWatcher(computeSystem.logctx, &completed) - err = hcsResumeComputeSystem(computeSystem.handle, "", &resultp) - completed = true + syscallWatcher(computeSystem.logctx, func() { + err = hcsResumeComputeSystem(computeSystem.handle, "", &resultp) + }) events, err := processAsyncHcsResult(err, resultp, computeSystem.callbackNumber, hcsNotificationSystemResumeCompleted, &timeout.SystemResume) if err != nil { return makeSystemError(computeSystem, "Resume", "", err, events) @@ -490,10 +502,9 @@ func (computeSystem *System) CreateProcess(c interface{}) (_ *Process, err error WithField(logfields.JSON, configuration). Debug("HCS ComputeSystem Process Document") - completed := false - go syscallWatcher(computeSystem.logctx, &completed) - err = hcsCreateProcess(computeSystem.handle, configuration, &processInfo, &processHandle, &resultp) - completed = true + syscallWatcher(computeSystem.logctx, func() { + err = hcsCreateProcess(computeSystem.handle, configuration, &processInfo, &processHandle, &resultp) + }) events := processHcsResult(resultp) if err != nil { return nil, makeSystemError(computeSystem, "CreateProcess", configuration, err, events) @@ -539,10 +550,9 @@ func (computeSystem *System) OpenProcess(pid int) (_ *Process, err error) { return nil, makeSystemError(computeSystem, "OpenProcess", "", ErrAlreadyClosed, nil) } - completed := false - go syscallWatcher(computeSystem.logctx, &completed) - err = hcsOpenProcess(computeSystem.handle, uint32(pid), &processHandle, &resultp) - completed = true + syscallWatcher(computeSystem.logctx, func() { + err = hcsOpenProcess(computeSystem.handle, uint32(pid), &processHandle, &resultp) + }) events := processHcsResult(resultp) if err != nil { return nil, makeSystemError(computeSystem, "OpenProcess", "", err, events) @@ -574,10 +584,9 @@ func (computeSystem *System) Close() (err error) { return makeSystemError(computeSystem, "Close", "", err, nil) } - completed := false - go syscallWatcher(computeSystem.logctx, &completed) - err = hcsCloseComputeSystem(computeSystem.handle) - completed = true + syscallWatcher(computeSystem.logctx, func() { + err = hcsCloseComputeSystem(computeSystem.handle) + }) if err != nil { return makeSystemError(computeSystem, "Close", "", err, nil) } @@ -669,10 +678,9 @@ func (computeSystem *System) Modify(config interface{}) (err error) { Debug("HCS ComputeSystem Modify Document") var resultp *uint16 - completed := false - go syscallWatcher(computeSystem.logctx, &completed) - err = hcsModifyComputeSystem(computeSystem.handle, requestString, &resultp) - completed = true + syscallWatcher(computeSystem.logctx, func() { + err = hcsModifyComputeSystem(computeSystem.handle, requestString, &resultp) + }) events := processHcsResult(resultp) if err != nil { return makeSystemError(computeSystem, "Modify", requestString, err, events) diff --git a/vendor/github.com/Microsoft/hcsshim/internal/hcs/watcher.go b/vendor/github.com/Microsoft/hcsshim/internal/hcs/watcher.go index e09dd1334f..f85ed31874 100644 --- a/vendor/github.com/Microsoft/hcsshim/internal/hcs/watcher.go +++ b/vendor/github.com/Microsoft/hcsshim/internal/hcs/watcher.go @@ -1,7 +1,7 @@ package hcs import ( - "time" + "context" "github.com/Microsoft/hcsshim/internal/logfields" "github.com/Microsoft/hcsshim/internal/timeout" @@ -17,17 +17,25 @@ import ( // // Usage is: // -// completed := false -// go syscallWatcher(context, &completed) -// -// completed = true +// syscallWatcher(logContext, func() { +// err = (args...) +// }) // -func syscallWatcher(context logrus.Fields, syscallCompleted *bool) { - time.Sleep(timeout.SyscallWatcher) - if *syscallCompleted { - return + +func syscallWatcher(logContext logrus.Fields, syscallLambda func()) { + ctx, cancel := context.WithTimeout(context.Background(), timeout.SyscallWatcher) + defer cancel() + go watchFunc(ctx, logContext) + syscallLambda() +} + +func watchFunc(ctx context.Context, logContext logrus.Fields) { + select { + case <-ctx.Done(): + if ctx.Err() != context.Canceled { + logrus.WithFields(logContext). + WithField(logfields.Timeout, timeout.SyscallWatcher). + Warning("Syscall did not complete within operation timeout. This may indicate a platform issue. If it appears to be making no forward progress, obtain the stacks and see if there is a syscall stuck in the platform API for a significant length of time.") + } } - logrus.WithFields(context). - WithField(logfields.Timeout, timeout.SyscallWatcher). - Warning("Syscall did not complete within operation timeout. This may indicate a platform issue. If it appears to be making no forward progress, obtain the stacks and see if there is a syscall stuck in the platform API for a significant length of time.") } diff --git a/vendor/github.com/Microsoft/hcsshim/internal/hcsoci/hcsdoc_lcow.go b/vendor/github.com/Microsoft/hcsshim/internal/hcsoci/hcsdoc_lcow.go index 1dac6d8c94..71b1d03720 100644 --- a/vendor/github.com/Microsoft/hcsshim/internal/hcsoci/hcsdoc_lcow.go +++ b/vendor/github.com/Microsoft/hcsshim/internal/hcsoci/hcsdoc_lcow.go @@ -33,8 +33,18 @@ func createLCOWSpec(coi *createOptionsInternal) (*specs.Spec, error) { } */ - // Linux containers don't care about Windows aspects of the spec + // Linux containers don't care about Windows aspects of the spec except the + // network namespace spec.Windows = nil + if coi.Spec.Windows != nil && + coi.Spec.Windows.Network != nil && + coi.Spec.Windows.Network.NetworkNamespace != "" { + spec.Windows = &specs.Windows{ + Network: &specs.WindowsNetwork{ + NetworkNamespace: coi.Spec.Windows.Network.NetworkNamespace, + }, + } + } // Hooks are not supported (they should be run in the host) spec.Hooks = nil diff --git a/vendor/github.com/Microsoft/hcsshim/internal/hns/hnsendpoint.go b/vendor/github.com/Microsoft/hcsshim/internal/hns/hnsendpoint.go index ce636458c0..59ec7004c3 100644 --- a/vendor/github.com/Microsoft/hcsshim/internal/hns/hnsendpoint.go +++ b/vendor/github.com/Microsoft/hcsshim/internal/hns/hnsendpoint.go @@ -23,7 +23,9 @@ type HNSEndpoint struct { DisableICC bool `json:",omitempty"` PrefixLength uint8 `json:",omitempty"` IsRemoteEndpoint bool `json:",omitempty"` + EnableLowMetric bool `json:",omitempty"` Namespace *Namespace `json:",omitempty"` + EncapOverhead uint16 `json:",omitempty"` } //SystemType represents the type of the system on which actions are done diff --git a/vendor/github.com/Microsoft/hcsshim/internal/osversion/osversion.go b/vendor/github.com/Microsoft/hcsshim/internal/osversion/osversion.go deleted file mode 100644 index 916950c023..0000000000 --- a/vendor/github.com/Microsoft/hcsshim/internal/osversion/osversion.go +++ /dev/null @@ -1,51 +0,0 @@ -package osversion - -import ( - "fmt" - - "golang.org/x/sys/windows" -) - -// OSVersion is a wrapper for Windows version information -// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724439(v=vs.85).aspx -type OSVersion struct { - Version uint32 - MajorVersion uint8 - MinorVersion uint8 - Build uint16 -} - -// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724833(v=vs.85).aspx -type osVersionInfoEx struct { - OSVersionInfoSize uint32 - MajorVersion uint32 - MinorVersion uint32 - BuildNumber uint32 - PlatformID uint32 - CSDVersion [128]uint16 - ServicePackMajor uint16 - ServicePackMinor uint16 - SuiteMask uint16 - ProductType byte - Reserve byte -} - -// Get gets the operating system version on Windows. -// The calling application must be manifested to get the correct version information. -func Get() OSVersion { - var err error - osv := OSVersion{} - osv.Version, err = windows.GetVersion() - if err != nil { - // GetVersion never fails. - panic(err) - } - osv.MajorVersion = uint8(osv.Version & 0xFF) - osv.MinorVersion = uint8(osv.Version >> 8 & 0xFF) - osv.Build = uint16(osv.Version >> 16) - return osv -} - -func (osv OSVersion) ToString() string { - return fmt.Sprintf("%d.%d.%d", osv.MajorVersion, osv.MinorVersion, osv.Build) -} diff --git a/vendor/github.com/Microsoft/hcsshim/internal/osversion/windowsbuilds.go b/vendor/github.com/Microsoft/hcsshim/internal/osversion/windowsbuilds.go deleted file mode 100644 index 181fc2bb22..0000000000 --- a/vendor/github.com/Microsoft/hcsshim/internal/osversion/windowsbuilds.go +++ /dev/null @@ -1,11 +0,0 @@ -package osversion - -const ( - - // RS2 was a client-only release in case you're asking why it's not in the list. - RS1 = 14393 - RS3 = 16299 - RS4 = 17134 - RS5 = 17743 // TODO Bump to final RS5 build - -) diff --git a/vendor/github.com/Microsoft/hcsshim/internal/schema2/plan9_share.go b/vendor/github.com/Microsoft/hcsshim/internal/schema2/plan9_share.go index b2bc58b83c..eb171817a6 100644 --- a/vendor/github.com/Microsoft/hcsshim/internal/schema2/plan9_share.go +++ b/vendor/github.com/Microsoft/hcsshim/internal/schema2/plan9_share.go @@ -20,6 +20,13 @@ type Plan9Share struct { Port int32 `json:"Port,omitempty"` + // Flags are marked private. Until they are exported correctly + // + // ReadOnly 0x00000001 + // LinuxMetadata 0x00000004 + // CaseSensitive 0x00000008 + Flags int32 `json:"Flags,omitempty"` + ReadOnly bool `json:"ReadOnly,omitempty"` UseShareRootIdentity bool `json:"UseShareRootIdentity,omitempty"` diff --git a/vendor/github.com/Microsoft/hcsshim/internal/schema2/virtual_machine.go b/vendor/github.com/Microsoft/hcsshim/internal/schema2/virtual_machine.go index 11f39eea7b..2d22b1bcb0 100644 --- a/vendor/github.com/Microsoft/hcsshim/internal/schema2/virtual_machine.go +++ b/vendor/github.com/Microsoft/hcsshim/internal/schema2/virtual_machine.go @@ -11,6 +11,9 @@ package hcsschema type VirtualMachine struct { + // StopOnReset is private in the schema. If regenerated need to put back. + StopOnReset bool `json:"StopOnReset,omitempty"` + Chipset *Chipset `json:"Chipset,omitempty"` ComputeTopology *Topology `json:"ComputeTopology,omitempty"` diff --git a/vendor/github.com/Microsoft/hcsshim/internal/schemaversion/schemaversion_test.go b/vendor/github.com/Microsoft/hcsshim/internal/schemaversion/schemaversion_test.go index 63c2ceb027..3f0f027a8c 100644 --- a/vendor/github.com/Microsoft/hcsshim/internal/schemaversion/schemaversion_test.go +++ b/vendor/github.com/Microsoft/hcsshim/internal/schemaversion/schemaversion_test.go @@ -4,9 +4,9 @@ import ( "io/ioutil" "testing" - _ "github.com/Microsoft/hcsshim/functional/manifest" "github.com/Microsoft/hcsshim/internal/schema2" "github.com/Microsoft/hcsshim/osversion" + _ "github.com/Microsoft/hcsshim/test/functional/manifest" "github.com/sirupsen/logrus" ) diff --git a/vendor/github.com/Microsoft/hcsshim/internal/uvm/create.go b/vendor/github.com/Microsoft/hcsshim/internal/uvm/create.go index dc7cb249c0..0daaef9b96 100644 --- a/vendor/github.com/Microsoft/hcsshim/internal/uvm/create.go +++ b/vendor/github.com/Microsoft/hcsshim/internal/uvm/create.go @@ -16,11 +16,11 @@ type Options struct { // Memory for UVM. Defaults to true. For physical backed memory, set to // false. - AllowOvercommit *bool + AllowOvercommit bool // Memory for UVM. Defaults to false. For virtual memory with deferred // commit, set to true. - EnableDeferredCommit *bool + EnableDeferredCommit bool // ProcessorCount sets the number of vCPU's. If `0` will default to platform // default. @@ -54,19 +54,9 @@ func (uvm *UtilityVM) Close() error { return err } -func normalizeMemory(m int32) int32 { - if m == 0 { - return 1024 // 1GB By Default. +func defaultProcessorCount() int32 { + if runtime.NumCPU() == 1 { + return 1 } - return m -} - -func normalizeProcessors(p int32) int32 { - if p == 0 { - if runtime.NumCPU() == 1 { - return 1 - } - return 2 - } - return p + return 2 } diff --git a/vendor/github.com/Microsoft/hcsshim/internal/uvm/create_lcow.go b/vendor/github.com/Microsoft/hcsshim/internal/uvm/create_lcow.go index 3869c1e972..b9c261e8b9 100644 --- a/vendor/github.com/Microsoft/hcsshim/internal/uvm/create_lcow.go +++ b/vendor/github.com/Microsoft/hcsshim/internal/uvm/create_lcow.go @@ -31,37 +31,99 @@ const ( type OutputHandler func(io.Reader) const ( - initrdFile = "initrd.img" - vhdFile = "rootfs.vhd" + // InitrdFile is the default file name for an initrd.img used to boot LCOW. + InitrdFile = "initrd.img" + // VhdFile is the default file name for a rootfs.vhd used to boot LCOW. + VhdFile = "rootfs.vhd" + // KernelFile is the default file name for a kernel used to boot LCOW. + KernelFile = "kernel" + // UncompressedKernelFile is the default file name for an uncompressed + // kernel used to boot LCOW with KernelDirect. + UncompressedKernelFile = "vmlinux" ) // OptionsLCOW are the set of options passed to CreateLCOW() to create a utility vm. type OptionsLCOW struct { *Options - BootFilesPath string // Folder in which kernel and root file system reside. Defaults to \Program Files\Linux Containers - KernelFile string // Filename under BootFilesPath for the kernel. Defaults to `kernel` - KernelDirect bool // Skip UEFI and boot directly to `kernel` - RootFSFile string // Filename under BootFilesPath for the UVMs root file system. Defaults are `initrd.img` or `rootfs.vhd` based on `PreferredRootFSType`. - KernelBootOptions string // Additional boot options for the kernel - EnableGraphicsConsole bool // If true, enable a graphics console for the utility VM - ConsolePipe string // The named pipe path to use for the serial console. eg \\.\pipe\vmpipe - SCSIControllerCount *uint32 // The number of SCSI controllers. Defaults to 1 if omitted. Currently we only support 0 or 1. - UseGuestConnection *bool // Whether the HCS should connect to the UVM's GCS. Defaults to true - ExecCommandLine string // The command line to exec from init. Defaults to GCS - ForwardStdout *bool // Whether stdout will be forwarded from the executed program. Defaults to false - ForwardStderr *bool // Whether stderr will be forwarded from the executed program. Defaults to true - OutputHandler *OutputHandler // Controls how output received over HVSocket from the UVM is handled. Defaults to parsing output as logrus messages - - // Number of VPMem devices. Limit at 128. If booting UVM from VHD, device 0 is taken. LCOW Only. io.microsoft.virtualmachine.devices.virtualpmem.maximumcount - VPMemDeviceCount *uint32 - - // Size of the VPMem devices. LCOW Only. Defaults to 4GB. io.microsoft.virtualmachine.devices.virtualpmem.maximumsizebytes - VPMemSizeBytes *uint64 - - // Controls searching for the RootFSFile. Defaults to initrd (0). Can be set to VHD (1). io.microsoft.virtualmachine.lcow.preferredrootfstype - // Note this uses an arbitrary annotation strict which has no direct mapping to the HCS schema. - PreferredRootFSType *PreferredRootFSType + BootFilesPath string // Folder in which kernel and root file system reside. Defaults to \Program Files\Linux Containers + KernelFile string // Filename under `BootFilesPath` for the kernel. Defaults to `kernel` + KernelDirect bool // Skip UEFI and boot directly to `kernel` + RootFSFile string // Filename under `BootFilesPath` for the UVMs root file system. Defaults to `InitrdFile` + KernelBootOptions string // Additional boot options for the kernel + EnableGraphicsConsole bool // If true, enable a graphics console for the utility VM + ConsolePipe string // The named pipe path to use for the serial console. eg \\.\pipe\vmpipe + SCSIControllerCount uint32 // The number of SCSI controllers. Defaults to 1. Currently we only support 0 or 1. + UseGuestConnection bool // Whether the HCS should connect to the UVM's GCS. Defaults to true + ExecCommandLine string // The command line to exec from init. Defaults to GCS + ForwardStdout bool // Whether stdout will be forwarded from the executed program. Defaults to false + ForwardStderr bool // Whether stderr will be forwarded from the executed program. Defaults to true + OutputHandler OutputHandler `json:"-"` // Controls how output received over HVSocket from the UVM is handled. Defaults to parsing output as logrus messages + VPMemDeviceCount uint32 // Number of VPMem devices. Defaults to `DefaultVPMEMCount`. Limit at 128. If booting UVM from VHD, device 0 is taken. + VPMemSizeBytes uint64 // Size of the VPMem devices. Defaults to `DefaultVPMemSizeBytes`. + PreferredRootFSType PreferredRootFSType // If `KernelFile` is `InitrdFile` use `PreferredRootFSTypeInitRd`. If `KernelFile` is `VhdFile` use `PreferredRootFSTypeVHD` +} + +// NewDefaultOptionsLCOW creates the default options for a bootable version of +// LCOW. +// +// `id` the ID of the compute system. If not passed will generate a new GUID. +// +// `owner` the owner of the compute system. If not passed will use the +// executable files name. +func NewDefaultOptionsLCOW(id, owner string) *OptionsLCOW { + // Use KernelDirect boot by default on all builds that support it. + kernelDirectSupported := osversion.Get().Build >= 18286 + opts := &OptionsLCOW{ + Options: &Options{ + ID: id, + Owner: owner, + MemorySizeInMB: 1024, + AllowOvercommit: true, + EnableDeferredCommit: false, + ProcessorCount: defaultProcessorCount(), + }, + BootFilesPath: filepath.Join(os.Getenv("ProgramFiles"), "Linux Containers"), + KernelFile: KernelFile, + KernelDirect: kernelDirectSupported, + RootFSFile: InitrdFile, + KernelBootOptions: "", + EnableGraphicsConsole: false, + ConsolePipe: "", + SCSIControllerCount: 1, + UseGuestConnection: true, + ExecCommandLine: fmt.Sprintf("/bin/gcs -log-format json -loglevel %s", logrus.StandardLogger().Level.String()), + ForwardStdout: false, + ForwardStderr: true, + OutputHandler: parseLogrus, + VPMemDeviceCount: DefaultVPMEMCount, + VPMemSizeBytes: DefaultVPMemSizeBytes, + PreferredRootFSType: PreferredRootFSTypeInitRd, + } + + if opts.ID == "" { + opts.ID = guid.New().String() + } + if opts.Owner == "" { + opts.Owner = filepath.Base(os.Args[0]) + } + + if _, err := os.Stat(filepath.Join(opts.BootFilesPath, VhdFile)); err == nil { + // We have a rootfs.vhd in the boot files path. Use it over an initrd.img + opts.RootFSFile = VhdFile + opts.PreferredRootFSType = PreferredRootFSTypeVHD + } + + if kernelDirectSupported { + // KernelDirect supports uncompressed kernel if the kernel is present. + // Default to uncompressed if on box. NOTE: If `kernel` is already + // uncompressed and simply named 'kernel' it will still be used + // uncompressed automatically. + if _, err := os.Stat(filepath.Join(opts.BootFilesPath, UncompressedKernelFile)); err == nil { + opts.KernelFile = UncompressedKernelFile + } + } + return opts } const linuxLogVsockPort = 109 @@ -70,91 +132,41 @@ const linuxLogVsockPort = 109 func CreateLCOW(opts *OptionsLCOW) (_ *UtilityVM, err error) { logrus.Debugf("uvm::CreateLCOW %+v", opts) - if opts.Options == nil { - opts.Options = &Options{} + // We dont serialize OutputHandler so if it is missing we need to put it back to the default. + if opts.OutputHandler == nil { + opts.OutputHandler = parseLogrus } uvm := &UtilityVM{ id: opts.ID, owner: opts.Owner, operatingSystem: "linux", - scsiControllerCount: 1, - vpmemMaxCount: DefaultVPMEMCount, - vpmemMaxSizeBytes: DefaultVPMemSizeBytes, + scsiControllerCount: opts.SCSIControllerCount, + vpmemMaxCount: opts.VPMemDeviceCount, + vpmemMaxSizeBytes: opts.VPMemSizeBytes, } - // Defaults if omitted by caller. - // TODO: Change this. Don't auto generate ID if omitted. Avoids the chicken-and-egg problem - if uvm.id == "" { - uvm.id = guid.New().String() + kernelFullPath := filepath.Join(opts.BootFilesPath, opts.KernelFile) + if _, err := os.Stat(kernelFullPath); os.IsNotExist(err) { + return nil, fmt.Errorf("kernel: '%s' not found", kernelFullPath) } - if uvm.owner == "" { - uvm.owner = filepath.Base(os.Args[0]) - } - if opts.UseGuestConnection == nil { - val := true - opts.UseGuestConnection = &val + rootfsFullPath := filepath.Join(opts.BootFilesPath, opts.RootFSFile) + if _, err := os.Stat(rootfsFullPath); os.IsNotExist(err) { + return nil, fmt.Errorf("boot file: '%s' not found", rootfsFullPath) } - if opts.BootFilesPath == "" { - opts.BootFilesPath = filepath.Join(os.Getenv("ProgramFiles"), "Linux Containers") - } - if opts.KernelFile == "" { - opts.KernelFile = "kernel" + if opts.SCSIControllerCount > 1 { + return nil, fmt.Errorf("SCSI controller count must be 0 or 1") // Future extension here for up to 4 } - if _, err := os.Stat(filepath.Join(opts.BootFilesPath, opts.KernelFile)); os.IsNotExist(err) { - return nil, fmt.Errorf("kernel '%s' not found", filepath.Join(opts.BootFilesPath, opts.KernelFile)) - } - if opts.PreferredRootFSType == nil { - v := PreferredRootFSTypeInitRd - opts.PreferredRootFSType = &v - } - if opts.RootFSFile == "" { - switch *opts.PreferredRootFSType { - case PreferredRootFSTypeInitRd: - opts.RootFSFile = initrdFile - case PreferredRootFSTypeVHD: - opts.RootFSFile = "rootfs.vhd" - } - } - if opts.ForwardStdout == nil { - val := false - opts.ForwardStdout = &val - } - if opts.ForwardStderr == nil { - val := true - opts.ForwardStderr = &val - } - if opts.OutputHandler == nil { - val := OutputHandler(parseLogrus) - opts.OutputHandler = &val - } - - if _, err := os.Stat(filepath.Join(opts.BootFilesPath, opts.RootFSFile)); os.IsNotExist(err) { - return nil, fmt.Errorf("%s not found under %s", opts.RootFSFile, opts.BootFilesPath) - } - - if opts.SCSIControllerCount != nil { - if *opts.SCSIControllerCount > 1 { - return nil, fmt.Errorf("SCSI controller count must be 0 or 1") // Future extension here for up to 4 - } - uvm.scsiControllerCount = *opts.SCSIControllerCount - } - if opts.VPMemDeviceCount != nil { - if *opts.VPMemDeviceCount > MaxVPMEMCount { - return nil, fmt.Errorf("vpmem device count cannot be greater than %d", MaxVPMEMCount) - } - uvm.vpmemMaxCount = *opts.VPMemDeviceCount + if opts.VPMemDeviceCount > MaxVPMEMCount { + return nil, fmt.Errorf("vpmem device count cannot be greater than %d", MaxVPMEMCount) } if uvm.vpmemMaxCount > 0 { - if opts.VPMemSizeBytes != nil { - if *opts.VPMemSizeBytes%4096 != 0 { - return nil, fmt.Errorf("opts.VPMemSizeBytes must be a multiple of 4096") - } - uvm.vpmemMaxSizeBytes = *opts.VPMemSizeBytes + if opts.VPMemSizeBytes%4096 != 0 { + return nil, fmt.Errorf("opts.VPMemSizeBytes must be a multiple of 4096") } } else { - if *opts.PreferredRootFSType == PreferredRootFSTypeVHD { + if opts.PreferredRootFSType == PreferredRootFSTypeVHD { return nil, fmt.Errorf("PreferredRootFSTypeVHD requires at least one VPMem device") } } @@ -167,17 +179,16 @@ func CreateLCOW(opts *OptionsLCOW) (_ *UtilityVM, err error) { SchemaVersion: schemaversion.SchemaV21(), ShouldTerminateOnLastHandleClosed: true, VirtualMachine: &hcsschema.VirtualMachine{ - Chipset: &hcsschema.Chipset{}, + StopOnReset: true, + Chipset: &hcsschema.Chipset{}, ComputeTopology: &hcsschema.Topology{ Memory: &hcsschema.Memory2{ - SizeInMB: normalizeMemory(opts.MemorySizeInMB), - // AllowOvercommit `true` by default if not passed. - AllowOvercommit: opts.AllowOvercommit == nil || *opts.AllowOvercommit, - // EnableDeferredCommit `false` by default if not passed. - EnableDeferredCommit: opts.EnableDeferredCommit != nil && *opts.EnableDeferredCommit, + SizeInMB: opts.MemorySizeInMB, + AllowOvercommit: opts.AllowOvercommit, + EnableDeferredCommit: opts.EnableDeferredCommit, }, Processor: &hcsschema.Processor2{ - Count: normalizeProcessors(opts.ProcessorCount), + Count: opts.ProcessorCount, }, }, Devices: &hcsschema.Devices{ @@ -192,30 +203,13 @@ func CreateLCOW(opts *OptionsLCOW) (_ *UtilityVM, err error) { }, } - if *opts.UseGuestConnection { + if opts.UseGuestConnection { doc.VirtualMachine.GuestConnection = &hcsschema.GuestConnection{ UseVsock: true, UseConnectedSuspend: true, } } - if !opts.KernelDirect { - doc.VirtualMachine.Devices.VirtualSmb = &hcsschema.VirtualSmb{ - Shares: []hcsschema.VirtualSmbShare{ - { - Name: "os", - Path: opts.BootFilesPath, - Options: &hcsschema.VirtualSmbShareOptions{ - ReadOnly: true, - TakeBackupPrivilege: true, - CacheIo: true, - ShareRead: true, - }, - }, - }, - } - } - if uvm.scsiControllerCount > 0 { // TODO: JTERRY75 - this should enumerate scsicount and add an entry per value. doc.VirtualMachine.Devices.Scsi = map[string]hcsschema.Scsi{ @@ -232,7 +226,7 @@ func CreateLCOW(opts *OptionsLCOW) (_ *UtilityVM, err error) { } var kernelArgs string - switch *opts.PreferredRootFSType { + switch opts.PreferredRootFSType { case PreferredRootFSTypeInitRd: if !opts.KernelDirect { kernelArgs = "initrd=/" + opts.RootFSFile @@ -246,13 +240,13 @@ func CreateLCOW(opts *OptionsLCOW) (_ *UtilityVM, err error) { } doc.VirtualMachine.Devices.VirtualPMem.Devices = map[string]hcsschema.VirtualPMemDevice{ "0": { - HostPath: filepath.Join(opts.BootFilesPath, opts.RootFSFile), + HostPath: rootfsFullPath, ReadOnly: true, ImageFormat: imageFormat, }, } - if err := wclayer.GrantVmAccess(uvm.id, filepath.Join(opts.BootFilesPath, opts.RootFSFile)); err != nil { - return nil, fmt.Errorf("failed to grantvmaccess to %s: %s", filepath.Join(opts.BootFilesPath, opts.RootFSFile), err) + if err := wclayer.GrantVmAccess(uvm.id, rootfsFullPath); err != nil { + return nil, fmt.Errorf("failed to grantvmaccess to %s: %s", rootfsFullPath, err) } // Add to our internal structure uvm.vpmemDevices[0] = vpmemInfo{ @@ -296,21 +290,15 @@ func CreateLCOW(opts *OptionsLCOW) (_ *UtilityVM, err error) { // created below in order to forward guest logs to logrus. initArgs := "/bin/vsockexec" - if *opts.ForwardStdout { + if opts.ForwardStdout { initArgs += fmt.Sprintf(" -o %d", linuxLogVsockPort) } - if *opts.ForwardStderr { + if opts.ForwardStderr { initArgs += fmt.Sprintf(" -e %d", linuxLogVsockPort) } - initArgs += " " - if opts.ExecCommandLine != "" { - initArgs += opts.ExecCommandLine - } else { - // Default to running GCS when another command isn't specified. - initArgs += fmt.Sprintf("/bin/gcs -log-format json -loglevel %s", logrus.StandardLogger().Level.String()) - } + initArgs += " " + opts.ExecCommandLine if vmDebugging { // Launch a shell on the console. @@ -322,18 +310,19 @@ func CreateLCOW(opts *OptionsLCOW) (_ *UtilityVM, err error) { if !opts.KernelDirect { doc.VirtualMachine.Chipset.Uefi = &hcsschema.Uefi{ BootThis: &hcsschema.UefiBootEntry{ - DevicePath: `\` + opts.KernelFile, - DeviceType: "VmbFs", - OptionalData: kernelArgs, + DevicePath: `\` + opts.KernelFile, + DeviceType: "VmbFs", + VmbFsRootPath: opts.BootFilesPath, + OptionalData: kernelArgs, }, } } else { doc.VirtualMachine.Chipset.LinuxKernelDirect = &hcsschema.LinuxKernelDirect{ - KernelFilePath: filepath.Join(opts.BootFilesPath, opts.KernelFile), + KernelFilePath: kernelFullPath, KernelCmdLine: kernelArgs, } - if *opts.PreferredRootFSType == PreferredRootFSTypeInitRd { - doc.VirtualMachine.Chipset.LinuxKernelDirect.InitRdPath = filepath.Join(opts.BootFilesPath, opts.RootFSFile) + if opts.PreferredRootFSType == PreferredRootFSTypeInitRd { + doc.VirtualMachine.Chipset.LinuxKernelDirect.InitRdPath = rootfsFullPath } } @@ -357,8 +346,8 @@ func CreateLCOW(opts *OptionsLCOW) (_ *UtilityVM, err error) { // Create a socket that the executed program can send to. This is usually // used by GCS to send log data. - if *opts.ForwardStdout || *opts.ForwardStderr { - uvm.outputHandler = *opts.OutputHandler + if opts.ForwardStdout || opts.ForwardStderr { + uvm.outputHandler = opts.OutputHandler uvm.outputProcessingDone = make(chan struct{}) uvm.outputListener, err = uvm.listenVsock(linuxLogVsockPort) if err != nil { diff --git a/vendor/github.com/Microsoft/hcsshim/internal/uvm/create_test.go b/vendor/github.com/Microsoft/hcsshim/internal/uvm/create_test.go index 14402bdcb2..9e494dd0e6 100644 --- a/vendor/github.com/Microsoft/hcsshim/internal/uvm/create_test.go +++ b/vendor/github.com/Microsoft/hcsshim/internal/uvm/create_test.go @@ -7,17 +7,17 @@ import ( // Unit tests for negative testing of input to uvm.Create() func TestCreateBadBootFilesPath(t *testing.T) { - opts := &OptionsLCOW{ - BootFilesPath: `c:\does\not\exist\I\hope`, - } + opts := NewDefaultOptionsLCOW(t.Name(), "") + opts.BootFilesPath = `c:\does\not\exist\I\hope` + _, err := CreateLCOW(opts) - if err == nil || (err != nil && err.Error() != `kernel 'c:\does\not\exist\I\hope\kernel' not found`) { + if err == nil || err.Error() != `kernel: 'c:\does\not\exist\I\hope\kernel' not found` { t.Fatal(err) } } func TestCreateWCOWBadLayerFolders(t *testing.T) { - opts := &OptionsWCOW{} + opts := NewDefaultOptionsWCOW(t.Name(), "") _, err := CreateWCOW(opts) if err == nil || (err != nil && err.Error() != `at least 2 LayerFolders must be supplied`) { t.Fatal(err) diff --git a/vendor/github.com/Microsoft/hcsshim/internal/uvm/create_wcow.go b/vendor/github.com/Microsoft/hcsshim/internal/uvm/create_wcow.go index 4b75c7051c..9d5e61c97a 100644 --- a/vendor/github.com/Microsoft/hcsshim/internal/uvm/create_wcow.go +++ b/vendor/github.com/Microsoft/hcsshim/internal/uvm/create_wcow.go @@ -22,6 +22,35 @@ type OptionsWCOW struct { LayerFolders []string // Set of folders for base layers and scratch. Ordered from top most read-only through base read-only layer, followed by scratch } +// NewDefaultOptionsWCOW creates the default options for a bootable version of +// WCOW. The caller `MUST` set the `LayerFolders` path on the returned value. +// +// `id` the ID of the compute system. If not passed will generate a new GUID. +// +// `owner` the owner of the compute system. If not passed will use the +// executable files name. +func NewDefaultOptionsWCOW(id, owner string) *OptionsWCOW { + opts := &OptionsWCOW{ + Options: &Options{ + ID: id, + Owner: owner, + MemorySizeInMB: 1024, + AllowOvercommit: true, + EnableDeferredCommit: false, + ProcessorCount: defaultProcessorCount(), + }, + } + + if opts.ID == "" { + opts.ID = guid.New().String() + } + if opts.Owner == "" { + opts.Owner = filepath.Base(os.Args[0]) + } + + return opts +} + // CreateWCOW creates an HCS compute system representing a utility VM. // // WCOW Notes: @@ -42,15 +71,6 @@ func CreateWCOW(opts *OptionsWCOW) (_ *UtilityVM, err error) { vsmbShares: make(map[string]*vsmbShare), } - // Defaults if omitted by caller. - // TODO: Change this. Don't auto generate ID if omitted. Avoids the chicken-and-egg problem - if uvm.id == "" { - uvm.id = guid.New().String() - } - if uvm.owner == "" { - uvm.owner = filepath.Base(os.Args[0]) - } - if len(opts.LayerFolders) < 2 { return nil, fmt.Errorf("at least 2 LayerFolders must be supplied") } @@ -89,6 +109,7 @@ func CreateWCOW(opts *OptionsWCOW) (_ *UtilityVM, err error) { SchemaVersion: schemaversion.SchemaV21(), ShouldTerminateOnLastHandleClosed: true, VirtualMachine: &hcsschema.VirtualMachine{ + StopOnReset: true, Chipset: &hcsschema.Chipset{ Uefi: &hcsschema.Uefi{ BootThis: &hcsschema.UefiBootEntry{ @@ -99,16 +120,14 @@ func CreateWCOW(opts *OptionsWCOW) (_ *UtilityVM, err error) { }, ComputeTopology: &hcsschema.Topology{ Memory: &hcsschema.Memory2{ - SizeInMB: normalizeMemory(opts.MemorySizeInMB), - // AllowOvercommit `true` by default if not passed. - AllowOvercommit: opts.AllowOvercommit == nil || *opts.AllowOvercommit, - // EnableHotHint is not compatible with physical. Only virtual, and only Windows. - EnableHotHint: opts.AllowOvercommit == nil || *opts.AllowOvercommit, - // EnableDeferredCommit `false` by default if not passed. - EnableDeferredCommit: opts.EnableDeferredCommit != nil && *opts.EnableDeferredCommit, + SizeInMB: opts.MemorySizeInMB, + AllowOvercommit: opts.AllowOvercommit, + // EnableHotHint is not compatible with physical. + EnableHotHint: opts.AllowOvercommit, + EnableDeferredCommit: opts.EnableDeferredCommit, }, Processor: &hcsschema.Processor2{ - Count: normalizeProcessors(opts.ProcessorCount), + Count: defaultProcessorCount(), }, }, GuestConnection: &hcsschema.GuestConnection{}, diff --git a/vendor/github.com/Microsoft/hcsshim/internal/uvm/network.go b/vendor/github.com/Microsoft/hcsshim/internal/uvm/network.go index 6fdde43cc3..3e54e48234 100644 --- a/vendor/github.com/Microsoft/hcsshim/internal/uvm/network.go +++ b/vendor/github.com/Microsoft/hcsshim/internal/uvm/network.go @@ -24,7 +24,8 @@ func (uvm *UtilityVM) AddNetNS(id string, endpoints []*hns.HNSEndpoint) (err err ns = &namespaceInfo{} if uvm.isNetworkNamespaceSupported() { - // Add a Guest Network namespace. Remove windows check when LCOW supports it + // Add a Guest Network namespace. On LCOW we add the adapters + // dynamically. if uvm.operatingSystem == "windows" { hcnNamespace, err := hcn.GetNamespaceByID(id) if err != nil { @@ -182,13 +183,26 @@ func (uvm *UtilityVM) addNIC(id guid.GUID, endpoint *hns.HNSEndpoint) error { requesttype.Add, nil), } - // Uncomment this once we have GuestRequest support for Linux - //} else { - // request.GuestRequest = guestrequest.GuestRequest{ - // ResourceType: guestrequest.ResourceTypeNetwork, - // RequestType: requesttype.Add, - // Settings: endpoint, - // } + } else { + // Verify this version of LCOW supports Network HotAdd + if uvm.isNetworkNamespaceSupported() { + request.GuestRequest = guestrequest.GuestRequest{ + ResourceType: guestrequest.ResourceTypeNetwork, + RequestType: requesttype.Add, + Settings: &guestrequest.LCOWNetworkAdapter{ + NamespaceID: endpoint.Namespace.ID, + ID: id.String(), + MacAddress: endpoint.MacAddress, + IPAddress: endpoint.IPAddress.String(), + PrefixLength: endpoint.PrefixLength, + GatewayAddress: endpoint.GatewayAddress, + DNSSuffix: endpoint.DNSSuffix, + DNSServerList: endpoint.DNSServerList, + EnableLowMetric: endpoint.EnableLowMetric, + EncapOverhead: endpoint.EncapOverhead, + }, + } + } } if err := uvm.Modify(&request); err != nil { @@ -217,10 +231,16 @@ func (uvm *UtilityVM) removeNIC(id guid.GUID, endpoint *hns.HNSEndpoint) error { nil), } } else { - request.GuestRequest = guestrequest.GuestRequest{ - ResourceType: guestrequest.ResourceTypeNetwork, - RequestType: requesttype.Remove, - Settings: endpoint, + // Verify this version of LCOW supports Network HotRemove + if uvm.isNetworkNamespaceSupported() { + request.GuestRequest = guestrequest.GuestRequest{ + ResourceType: guestrequest.ResourceTypeNetwork, + RequestType: requesttype.Remove, + Settings: &guestrequest.LCOWNetworkAdapter{ + NamespaceID: endpoint.Namespace.ID, + ID: endpoint.Id, + }, + } } } diff --git a/vendor/github.com/Microsoft/hcsshim/internal/uvm/plan9.go b/vendor/github.com/Microsoft/hcsshim/internal/uvm/plan9.go index c2e3a7e9ad..7b64e2a461 100644 --- a/vendor/github.com/Microsoft/hcsshim/internal/uvm/plan9.go +++ b/vendor/github.com/Microsoft/hcsshim/internal/uvm/plan9.go @@ -27,6 +27,22 @@ func (uvm *UtilityVM) AddPlan9(hostPath string, uvmPath string, readOnly bool) e return fmt.Errorf("uvmPath must be passed to AddPlan9") } + // TODO: JTERRY75 - These are marked private in the schema. For now use them + // but when there are public variants we need to switch to them. + const ( + shareFlagsReadOnly int32 = 0x00000001 + shareFlagsLinuxMetadata int32 = 0x00000004 + shareFlagsCaseSensitive int32 = 0x00000008 + ) + + // TODO: JTERRY75 - `shareFlagsCaseSensitive` only works if the Windows + // `hostPath` supports case sensitivity. We need to detect this case before + // forwarding this flag in all cases. + flags := shareFlagsLinuxMetadata // | shareFlagsCaseSensitive + if readOnly { + flags |= shareFlagsReadOnly + } + uvm.m.Lock() defer uvm.m.Unlock() if uvm.plan9Shares == nil { @@ -38,9 +54,10 @@ func (uvm *UtilityVM) AddPlan9(hostPath string, uvmPath string, readOnly bool) e modification := &hcsschema.ModifySettingRequest{ RequestType: requesttype.Add, Settings: hcsschema.Plan9Share{ - Name: fmt.Sprintf("%d", uvm.plan9Counter), - Path: hostPath, - Port: int32(uvm.plan9Counter), // TODO: Temporary. Will all use a single port (9999) + Name: fmt.Sprintf("%d", uvm.plan9Counter), + Path: hostPath, + Port: int32(uvm.plan9Counter), // TODO: Temporary. Will all use a single port (9999) + Flags: flags, }, ResourcePath: fmt.Sprintf("VirtualMachine/Devices/Plan9/Shares"), GuestRequest: guestrequest.GuestRequest{ diff --git a/vendor/github.com/Microsoft/hcsshim/internal/uvm/start.go b/vendor/github.com/Microsoft/hcsshim/internal/uvm/start.go index 612242f768..93549308f3 100644 --- a/vendor/github.com/Microsoft/hcsshim/internal/uvm/start.go +++ b/vendor/github.com/Microsoft/hcsshim/internal/uvm/start.go @@ -1,6 +1,7 @@ package uvm import ( + "context" "encoding/json" "io" "io/ioutil" @@ -12,6 +13,8 @@ import ( const _ERROR_CONNECTION_ABORTED syscall.Errno = 1236 +var _ = (OutputHandler)(parseLogrus) + func parseLogrus(r io.Reader) { j := json.NewDecoder(r) logger := logrus.StandardLogger() @@ -52,24 +55,43 @@ func parseLogrus(r io.Reader) { } } -func processOutput(l net.Listener, doneChan chan struct{}, handler OutputHandler) { +type acceptResult struct { + c net.Conn + err error +} + +func processOutput(ctx context.Context, l net.Listener, doneChan chan struct{}, handler OutputHandler) { defer close(doneChan) - c, err := l.Accept() - l.Close() - if err != nil { - logrus.Error("accepting log socket: ", err) + ch := make(chan acceptResult) + go func() { + c, err := l.Accept() + ch <- acceptResult{c, err} + }() + + select { + case <-ctx.Done(): + l.Close() return - } - defer c.Close() + case ar := <-ch: + c, err := ar.c, ar.err + l.Close() + if err != nil { + logrus.Error("accepting log socket: ", err) + return + } + defer c.Close() - handler(c) + handler(c) + } } // Start synchronously starts the utility VM. func (uvm *UtilityVM) Start() error { if uvm.outputListener != nil { - go processOutput(uvm.outputListener, uvm.outputProcessingDone, uvm.outputHandler) + ctx, cancel := context.WithCancel(context.Background()) + go processOutput(ctx, uvm.outputListener, uvm.outputProcessingDone, uvm.outputHandler) + uvm.outputProcessingCancel = cancel uvm.outputListener = nil } return uvm.hcsSystem.Start() diff --git a/vendor/github.com/Microsoft/hcsshim/internal/uvm/types.go b/vendor/github.com/Microsoft/hcsshim/internal/uvm/types.go index d629be20a8..2ee167888b 100644 --- a/vendor/github.com/Microsoft/hcsshim/internal/uvm/types.go +++ b/vendor/github.com/Microsoft/hcsshim/internal/uvm/types.go @@ -3,6 +3,7 @@ package uvm // This package describes the external interface for utility VMs. import ( + "context" "net" "sync" @@ -97,7 +98,8 @@ type UtilityVM struct { namespaces map[string]*namespaceInfo - outputListener net.Listener - outputProcessingDone chan struct{} - outputHandler OutputHandler + outputListener net.Listener + outputProcessingDone chan struct{} + outputHandler OutputHandler + outputProcessingCancel context.CancelFunc } diff --git a/vendor/github.com/Microsoft/hcsshim/internal/uvm/wait.go b/vendor/github.com/Microsoft/hcsshim/internal/uvm/wait.go index e9d3477cb4..aee387a8c0 100644 --- a/vendor/github.com/Microsoft/hcsshim/internal/uvm/wait.go +++ b/vendor/github.com/Microsoft/hcsshim/internal/uvm/wait.go @@ -16,12 +16,31 @@ func (uvm *UtilityVM) waitForOutput() { // Waits synchronously waits for a utility VM to terminate. func (uvm *UtilityVM) Wait() error { err := uvm.hcsSystem.Wait() + + // outputProcessingCancel will only cancel waiting for the vsockexec + // connection, it won't stop output processing once the connection is + // established. + if uvm.outputProcessingCancel != nil { + uvm.outputProcessingCancel() + } uvm.waitForOutput() + return err } +// WaitExpectedError synchronously waits for a utility VM to terminate. If the +// UVM terminates successfully, or if the given error is encountered internally +// during the wait, this function returns nil. func (uvm *UtilityVM) WaitExpectedError(expected error) error { err := uvm.hcsSystem.WaitExpectedError(expected) + + // outputProcessingCancel will only cancel waiting for the vsockexec + // connection, it won't stop output processing once the connection is + // established. + if uvm.outputProcessingCancel != nil { + uvm.outputProcessingCancel() + } uvm.waitForOutput() + return err } diff --git a/vendor/github.com/Microsoft/hcsshim/pkg/go-runhcs/runhcs.go b/vendor/github.com/Microsoft/hcsshim/pkg/go-runhcs/runhcs.go index 5d5205abdb..64491a70cc 100644 --- a/vendor/github.com/Microsoft/hcsshim/pkg/go-runhcs/runhcs.go +++ b/vendor/github.com/Microsoft/hcsshim/pkg/go-runhcs/runhcs.go @@ -35,9 +35,22 @@ func getCommandPath() string { if pathi == nil { path, err := exec.LookPath(command) if err != nil { - // Failed to look up command just use it directly and let the - // Windows loader find it. - path = command + // LookPath only finds current directory matches based on the + // callers current directory but the caller is not likely in the + // same directory as the containerd executables. Instead match the + // calling binaries path (a containerd shim usually) and see if they + // are side by side. If so execute the runhcs.exe found there. + if self, serr := os.Executable(); serr == nil { + testPath := filepath.Join(filepath.Dir(self), command) + if _, serr := os.Stat(testPath); serr == nil { + path = testPath + } + } + if path == "" { + // Failed to look up command just use it directly and let the + // Windows loader find it. + path = command + } runhcsPath.Store(path) return path } diff --git a/vendor/github.com/Microsoft/hcsshim/pkg/go-runhcs/runhcs_integration_test.go b/vendor/github.com/Microsoft/hcsshim/pkg/go-runhcs/runhcs_integration_test.go deleted file mode 100644 index 12922e089a..0000000000 --- a/vendor/github.com/Microsoft/hcsshim/pkg/go-runhcs/runhcs_integration_test.go +++ /dev/null @@ -1,7 +0,0 @@ -// +build integration - -package runhcs - -import ( - _ "github.com/Microsoft/hcsshim/functional/manifest" -) diff --git a/vendor/github.com/Microsoft/hcsshim/functional/assets/defaultlinuxspec.json b/vendor/github.com/Microsoft/hcsshim/test/functional/assets/defaultlinuxspec.json similarity index 100% rename from vendor/github.com/Microsoft/hcsshim/functional/assets/defaultlinuxspec.json rename to vendor/github.com/Microsoft/hcsshim/test/functional/assets/defaultlinuxspec.json diff --git a/vendor/github.com/Microsoft/hcsshim/functional/assets/defaultwindowsspec.json b/vendor/github.com/Microsoft/hcsshim/test/functional/assets/defaultwindowsspec.json similarity index 100% rename from vendor/github.com/Microsoft/hcsshim/functional/assets/defaultwindowsspec.json rename to vendor/github.com/Microsoft/hcsshim/test/functional/assets/defaultwindowsspec.json diff --git a/vendor/github.com/Microsoft/hcsshim/functional/assets/samples/config.justin.lcow.working.json b/vendor/github.com/Microsoft/hcsshim/test/functional/assets/samples/config.justin.lcow.working.json similarity index 100% rename from vendor/github.com/Microsoft/hcsshim/functional/assets/samples/config.justin.lcow.working.json rename to vendor/github.com/Microsoft/hcsshim/test/functional/assets/samples/config.justin.lcow.working.json diff --git a/vendor/github.com/Microsoft/hcsshim/functional/assets/samples/from-docker-linux/privileged.json b/vendor/github.com/Microsoft/hcsshim/test/functional/assets/samples/from-docker-linux/privileged.json similarity index 100% rename from vendor/github.com/Microsoft/hcsshim/functional/assets/samples/from-docker-linux/privileged.json rename to vendor/github.com/Microsoft/hcsshim/test/functional/assets/samples/from-docker-linux/privileged.json diff --git a/vendor/github.com/Microsoft/hcsshim/functional/assets/samples/from-docker-linux/sh.json b/vendor/github.com/Microsoft/hcsshim/test/functional/assets/samples/from-docker-linux/sh.json similarity index 100% rename from vendor/github.com/Microsoft/hcsshim/functional/assets/samples/from-docker-linux/sh.json rename to vendor/github.com/Microsoft/hcsshim/test/functional/assets/samples/from-docker-linux/sh.json diff --git a/vendor/github.com/Microsoft/hcsshim/functional/lcow_test.go b/vendor/github.com/Microsoft/hcsshim/test/functional/lcow_test.go similarity index 88% rename from vendor/github.com/Microsoft/hcsshim/functional/lcow_test.go rename to vendor/github.com/Microsoft/hcsshim/test/functional/lcow_test.go index 5e75a996dd..6ca4d72909 100644 --- a/vendor/github.com/Microsoft/hcsshim/functional/lcow_test.go +++ b/vendor/github.com/Microsoft/hcsshim/test/functional/lcow_test.go @@ -4,6 +4,7 @@ package functional import ( "bytes" + "fmt" "os" "os/exec" "path/filepath" @@ -11,44 +12,35 @@ import ( "testing" "time" - "github.com/Microsoft/hcsshim/functional/utilities" "github.com/Microsoft/hcsshim/internal/hcs" "github.com/Microsoft/hcsshim/internal/hcsoci" "github.com/Microsoft/hcsshim/internal/lcow" "github.com/Microsoft/hcsshim/internal/uvm" "github.com/Microsoft/hcsshim/osversion" + "github.com/Microsoft/hcsshim/test/functional/utilities" ) // TestLCOWUVMNoSCSINoVPMemInitrd starts an LCOW utility VM without a SCSI controller and // no VPMem device. Uses initrd. func TestLCOWUVMNoSCSINoVPMemInitrd(t *testing.T) { - var scsiCount uint32 = 0 - var vpmemCount uint32 = 0 - opts := &uvm.OptionsLCOW{ - Options: &uvm.Options{ - ID: "uvm", - }, - VPMemDeviceCount: &vpmemCount, - SCSIControllerCount: &scsiCount, - } - testLCOWUVMNoSCSISingleVPMem(t, opts, `Command line: initrd=/initrd.img`) + opts := uvm.NewDefaultOptionsLCOW(t.Name(), "") + opts.SCSIControllerCount = 0 + opts.VPMemDeviceCount = 0 + opts.PreferredRootFSType = uvm.PreferredRootFSTypeInitRd + opts.RootFSFile = uvm.InitrdFile + + testLCOWUVMNoSCSISingleVPMem(t, opts, fmt.Sprintf("Command line: initrd=/%s", opts.RootFSFile)) } // TestLCOWUVMNoSCSISingleVPMemVHD starts an LCOW utility VM without a SCSI controller and // only a single VPMem device. Uses VPMEM VHD func TestLCOWUVMNoSCSISingleVPMemVHD(t *testing.T) { - var scsiCount uint32 = 0 - var vpmemCount uint32 = 1 - var prfst uvm.PreferredRootFSType = uvm.PreferredRootFSTypeVHD - opts := &uvm.OptionsLCOW{ - Options: &uvm.Options{ - ID: "uvm", - }, - VPMemDeviceCount: &vpmemCount, - SCSIControllerCount: &scsiCount, - PreferredRootFSType: &prfst, - //ConsolePipe: `\\.\pipe\vmpipe`, - } + opts := uvm.NewDefaultOptionsLCOW(t.Name(), "") + opts.SCSIControllerCount = 0 + opts.VPMemDeviceCount = 1 + opts.PreferredRootFSType = uvm.PreferredRootFSTypeVHD + opts.RootFSFile = uvm.VhdFile + testLCOWUVMNoSCSISingleVPMem(t, opts, `Command line: root=/dev/pmem0 init=/init`) } @@ -100,16 +92,18 @@ func TestLCOWUVMStart_KernelDirect_InitRd(t *testing.T) { } func testLCOWTimeUVMStart(t *testing.T, kernelDirect bool, rfsType uvm.PreferredRootFSType) { - var vpmemCount uint32 = 32 for i := 0; i < 3; i++ { - opts := &uvm.OptionsLCOW{ - Options: &uvm.Options{ - ID: t.Name(), - }, - VPMemDeviceCount: &vpmemCount, - PreferredRootFSType: &rfsType, - KernelDirect: kernelDirect, + opts := uvm.NewDefaultOptionsLCOW(t.Name(), "") + opts.KernelDirect = kernelDirect + opts.VPMemDeviceCount = 32 + opts.PreferredRootFSType = rfsType + switch opts.PreferredRootFSType { + case uvm.PreferredRootFSTypeInitRd: + opts.RootFSFile = uvm.InitrdFile + case uvm.PreferredRootFSTypeVHD: + opts.RootFSFile = uvm.VhdFile } + lcowUVM := testutilities.CreateLCOWUVMFromOpts(t, opts) lcowUVM.Close() } diff --git a/vendor/github.com/Microsoft/hcsshim/functional/manifest/manifest.go b/vendor/github.com/Microsoft/hcsshim/test/functional/manifest/manifest.go similarity index 100% rename from vendor/github.com/Microsoft/hcsshim/functional/manifest/manifest.go rename to vendor/github.com/Microsoft/hcsshim/test/functional/manifest/manifest.go diff --git a/vendor/github.com/Microsoft/hcsshim/functional/manifest/rsrc_amd64.syso b/vendor/github.com/Microsoft/hcsshim/test/functional/manifest/rsrc_amd64.syso similarity index 100% rename from vendor/github.com/Microsoft/hcsshim/functional/manifest/rsrc_amd64.syso rename to vendor/github.com/Microsoft/hcsshim/test/functional/manifest/rsrc_amd64.syso diff --git a/vendor/github.com/Microsoft/hcsshim/test/functional/manifest_test.go b/vendor/github.com/Microsoft/hcsshim/test/functional/manifest_test.go new file mode 100644 index 0000000000..d7be25b1d2 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/test/functional/manifest_test.go @@ -0,0 +1,3 @@ +package functional + +import _ "github.com/Microsoft/hcsshim/test/functional/manifest" diff --git a/vendor/github.com/Microsoft/hcsshim/functional/test.go b/vendor/github.com/Microsoft/hcsshim/test/functional/test.go similarity index 100% rename from vendor/github.com/Microsoft/hcsshim/functional/test.go rename to vendor/github.com/Microsoft/hcsshim/test/functional/test.go diff --git a/vendor/github.com/Microsoft/hcsshim/functional/utilities/createuvm.go b/vendor/github.com/Microsoft/hcsshim/test/functional/utilities/createuvm.go similarity index 82% rename from vendor/github.com/Microsoft/hcsshim/functional/utilities/createuvm.go rename to vendor/github.com/Microsoft/hcsshim/test/functional/utilities/createuvm.go index 3d74aea3fa..1f45bc0757 100644 --- a/vendor/github.com/Microsoft/hcsshim/functional/utilities/createuvm.go +++ b/vendor/github.com/Microsoft/hcsshim/test/functional/utilities/createuvm.go @@ -4,14 +4,13 @@ import ( "os" "testing" - "github.com/Microsoft/hcsshim/internal/guid" "github.com/Microsoft/hcsshim/internal/uvm" ) // CreateWCOWUVM creates a WCOW utility VM with all default options. Returns the // UtilityVM object; folder used as its scratch func CreateWCOWUVM(t *testing.T, id, image string) (*uvm.UtilityVM, []string, string) { - return CreateWCOWUVMFromOptsWithImage(t, &uvm.OptionsWCOW{Options: &uvm.Options{ID: id}}, image) + return CreateWCOWUVMFromOptsWithImage(t, uvm.NewDefaultOptionsWCOW(id, ""), image) } @@ -20,9 +19,6 @@ func CreateWCOWUVMFromOpts(t *testing.T, opts *uvm.OptionsWCOW) *uvm.UtilityVM { if opts == nil || len(opts.LayerFolders) < 2 { t.Fatalf("opts must bet set with LayerFolders") } - if opts.ID == "" { - opts.ID = guid.New().String() - } uvm, err := uvm.CreateWCOW(opts) if err != nil { @@ -59,18 +55,13 @@ func CreateWCOWUVMFromOptsWithImage(t *testing.T, opts *uvm.OptionsWCOW, image s // CreateLCOWUVM with all default options. func CreateLCOWUVM(t *testing.T, id string) *uvm.UtilityVM { - return CreateLCOWUVMFromOpts(t, &uvm.OptionsLCOW{Options: &uvm.Options{ID: id}}) + return CreateLCOWUVMFromOpts(t, uvm.NewDefaultOptionsLCOW(id, "")) } // CreateLCOWUVMFromOpts creates an LCOW utility VM with the specified options. func CreateLCOWUVMFromOpts(t *testing.T, opts *uvm.OptionsLCOW) *uvm.UtilityVM { if opts == nil { - opts = &uvm.OptionsLCOW{ - Options: &uvm.Options{}, - } - } - if opts.ID == "" { - opts.ID = guid.New().String() + t.Fatal("opts must be set") } uvm, err := uvm.CreateLCOW(opts) diff --git a/vendor/github.com/Microsoft/hcsshim/functional/utilities/defaultlinuxspec.go b/vendor/github.com/Microsoft/hcsshim/test/functional/utilities/defaultlinuxspec.go similarity index 100% rename from vendor/github.com/Microsoft/hcsshim/functional/utilities/defaultlinuxspec.go rename to vendor/github.com/Microsoft/hcsshim/test/functional/utilities/defaultlinuxspec.go diff --git a/vendor/github.com/Microsoft/hcsshim/functional/utilities/defaultwindowsspec.go b/vendor/github.com/Microsoft/hcsshim/test/functional/utilities/defaultwindowsspec.go similarity index 100% rename from vendor/github.com/Microsoft/hcsshim/functional/utilities/defaultwindowsspec.go rename to vendor/github.com/Microsoft/hcsshim/test/functional/utilities/defaultwindowsspec.go diff --git a/vendor/github.com/Microsoft/hcsshim/functional/utilities/layerfolders.go b/vendor/github.com/Microsoft/hcsshim/test/functional/utilities/layerfolders.go similarity index 100% rename from vendor/github.com/Microsoft/hcsshim/functional/utilities/layerfolders.go rename to vendor/github.com/Microsoft/hcsshim/test/functional/utilities/layerfolders.go diff --git a/vendor/github.com/Microsoft/hcsshim/functional/utilities/requiresbuild.go b/vendor/github.com/Microsoft/hcsshim/test/functional/utilities/requiresbuild.go similarity index 100% rename from vendor/github.com/Microsoft/hcsshim/functional/utilities/requiresbuild.go rename to vendor/github.com/Microsoft/hcsshim/test/functional/utilities/requiresbuild.go diff --git a/vendor/github.com/Microsoft/hcsshim/functional/utilities/scratch.go b/vendor/github.com/Microsoft/hcsshim/test/functional/utilities/scratch.go similarity index 100% rename from vendor/github.com/Microsoft/hcsshim/functional/utilities/scratch.go rename to vendor/github.com/Microsoft/hcsshim/test/functional/utilities/scratch.go diff --git a/vendor/github.com/Microsoft/hcsshim/functional/utilities/tempdir.go b/vendor/github.com/Microsoft/hcsshim/test/functional/utilities/tempdir.go similarity index 100% rename from vendor/github.com/Microsoft/hcsshim/functional/utilities/tempdir.go rename to vendor/github.com/Microsoft/hcsshim/test/functional/utilities/tempdir.go diff --git a/vendor/github.com/Microsoft/hcsshim/functional/uvm_mem_backingtype_test.go b/vendor/github.com/Microsoft/hcsshim/test/functional/uvm_mem_backingtype_test.go similarity index 54% rename from vendor/github.com/Microsoft/hcsshim/functional/uvm_mem_backingtype_test.go rename to vendor/github.com/Microsoft/hcsshim/test/functional/uvm_mem_backingtype_test.go index 6c911e5049..70b1b6f755 100644 --- a/vendor/github.com/Microsoft/hcsshim/functional/uvm_mem_backingtype_test.go +++ b/vendor/github.com/Microsoft/hcsshim/test/functional/uvm_mem_backingtype_test.go @@ -7,51 +7,48 @@ import ( "os" "testing" - "github.com/Microsoft/hcsshim/functional/utilities" "github.com/Microsoft/hcsshim/internal/uvm" "github.com/Microsoft/hcsshim/osversion" + testutilities "github.com/Microsoft/hcsshim/test/functional/utilities" "github.com/sirupsen/logrus" ) -func runMemStartLCOWTest(t *testing.T, opts *uvm.Options) { - u := testutilities.CreateLCOWUVMFromOpts(t, &uvm.OptionsLCOW{Options: opts}) +func runMemStartLCOWTest(t *testing.T, opts *uvm.OptionsLCOW) { + u := testutilities.CreateLCOWUVMFromOpts(t, opts) u.Close() } -func runMemStartWCOWTest(t *testing.T, opts *uvm.Options) { - u, _, scratchDir := testutilities.CreateWCOWUVMFromOptsWithImage(t, &uvm.OptionsWCOW{Options: opts}, "microsoft/nanoserver") +func runMemStartWCOWTest(t *testing.T, opts *uvm.OptionsWCOW) { + u, _, scratchDir := testutilities.CreateWCOWUVMFromOptsWithImage(t, opts, "microsoft/nanoserver") defer os.RemoveAll(scratchDir) u.Close() } func runMemTests(t *testing.T, os string) { type testCase struct { - allowOvercommit *bool - enableDeferredCommit *bool + allowOvercommit bool + enableDeferredCommit bool } - yes := true - no := false - testCases := []testCase{ - {nil, nil}, // Implicit default - Virtual - {allowOvercommit: &yes, enableDeferredCommit: &no}, // Explicit default - Virtual - {allowOvercommit: &yes, enableDeferredCommit: &yes}, // Virtual Deferred - {allowOvercommit: &no, enableDeferredCommit: &no}, // Physical + {allowOvercommit: true, enableDeferredCommit: false}, // Explicit default - Virtual + {allowOvercommit: true, enableDeferredCommit: true}, // Virtual Deferred + {allowOvercommit: false, enableDeferredCommit: false}, // Physical } for _, bt := range testCases { - opts := &uvm.Options{ - ID: t.Name(), - MemorySizeInMB: 512, - AllowOvercommit: bt.allowOvercommit, - EnableDeferredCommit: bt.enableDeferredCommit, - } - if os == "windows" { - runMemStartWCOWTest(t, opts) + wopts := uvm.NewDefaultOptionsWCOW(t.Name(), "") + wopts.MemorySizeInMB = 512 + wopts.AllowOvercommit = bt.allowOvercommit + wopts.EnableDeferredCommit = bt.enableDeferredCommit + runMemStartWCOWTest(t, wopts) } else { - runMemStartLCOWTest(t, opts) + lopts := uvm.NewDefaultOptionsLCOW(t.Name(), "") + lopts.MemorySizeInMB = 512 + lopts.AllowOvercommit = bt.allowOvercommit + lopts.EnableDeferredCommit = bt.enableDeferredCommit + runMemStartLCOWTest(t, lopts) } } } @@ -66,9 +63,9 @@ func TestMemBackingTypeLCOW(t *testing.T) { runMemTests(t, "linux") } -func runBenchMemStartTest(b *testing.B, opts *uvm.Options) { +func runBenchMemStartTest(b *testing.B, opts *uvm.OptionsLCOW) { // Cant use testutilities here because its `testing.B` not `testing.T` - u, err := uvm.CreateLCOW(&uvm.OptionsLCOW{Options: opts}) + u, err := uvm.CreateLCOW(opts) if err != nil { b.Fatal(err) } @@ -78,14 +75,12 @@ func runBenchMemStartTest(b *testing.B, opts *uvm.Options) { } } -func runBenchMemStartLcowTest(b *testing.B, allowOverCommit bool, enableDeferredCommit bool) { +func runBenchMemStartLcowTest(b *testing.B, allowOvercommit bool, enableDeferredCommit bool) { for i := 0; i < b.N; i++ { - opts := &uvm.Options{ - ID: b.Name(), - MemorySizeInMB: 512, - AllowOvercommit: &allowOverCommit, - EnableDeferredCommit: &enableDeferredCommit, - } + opts := uvm.NewDefaultOptionsLCOW(b.Name(), "") + opts.MemorySizeInMB = 512 + opts.AllowOvercommit = allowOvercommit + opts.EnableDeferredCommit = enableDeferredCommit runBenchMemStartTest(b, opts) } } diff --git a/vendor/github.com/Microsoft/hcsshim/functional/uvm_plannine_test.go b/vendor/github.com/Microsoft/hcsshim/test/functional/uvm_plannine_test.go similarity index 94% rename from vendor/github.com/Microsoft/hcsshim/functional/uvm_plannine_test.go rename to vendor/github.com/Microsoft/hcsshim/test/functional/uvm_plannine_test.go index 3a535c1aad..7e65c4b669 100644 --- a/vendor/github.com/Microsoft/hcsshim/functional/uvm_plannine_test.go +++ b/vendor/github.com/Microsoft/hcsshim/test/functional/uvm_plannine_test.go @@ -10,8 +10,8 @@ import ( "path/filepath" "testing" - "github.com/Microsoft/hcsshim/functional/utilities" "github.com/Microsoft/hcsshim/osversion" + "github.com/Microsoft/hcsshim/test/functional/utilities" ) // TestPlan9 tests adding/removing Plan9 shares to/from a v2 Linux utility VM diff --git a/vendor/github.com/Microsoft/hcsshim/functional/uvm_properties_test.go b/vendor/github.com/Microsoft/hcsshim/test/functional/uvm_properties_test.go similarity index 96% rename from vendor/github.com/Microsoft/hcsshim/functional/uvm_properties_test.go rename to vendor/github.com/Microsoft/hcsshim/test/functional/uvm_properties_test.go index 7ab92a685a..15540c6931 100644 --- a/vendor/github.com/Microsoft/hcsshim/functional/uvm_properties_test.go +++ b/vendor/github.com/Microsoft/hcsshim/test/functional/uvm_properties_test.go @@ -6,9 +6,9 @@ import ( "os" "testing" - "github.com/Microsoft/hcsshim/functional/utilities" "github.com/Microsoft/hcsshim/internal/schema1" "github.com/Microsoft/hcsshim/osversion" + "github.com/Microsoft/hcsshim/test/functional/utilities" ) func TestPropertiesGuestConnection_LCOW(t *testing.T) { diff --git a/vendor/github.com/Microsoft/hcsshim/functional/uvm_scratch_test.go b/vendor/github.com/Microsoft/hcsshim/test/functional/uvm_scratch_test.go similarity index 98% rename from vendor/github.com/Microsoft/hcsshim/functional/uvm_scratch_test.go rename to vendor/github.com/Microsoft/hcsshim/test/functional/uvm_scratch_test.go index 0f690f922f..671068247f 100644 --- a/vendor/github.com/Microsoft/hcsshim/functional/uvm_scratch_test.go +++ b/vendor/github.com/Microsoft/hcsshim/test/functional/uvm_scratch_test.go @@ -7,9 +7,9 @@ import ( "path/filepath" "testing" - "github.com/Microsoft/hcsshim/functional/utilities" "github.com/Microsoft/hcsshim/internal/lcow" "github.com/Microsoft/hcsshim/osversion" + "github.com/Microsoft/hcsshim/test/functional/utilities" ) func TestScratchCreateLCOW(t *testing.T) { diff --git a/vendor/github.com/Microsoft/hcsshim/functional/uvm_scsi_test.go b/vendor/github.com/Microsoft/hcsshim/test/functional/uvm_scsi_test.go similarity index 98% rename from vendor/github.com/Microsoft/hcsshim/functional/uvm_scsi_test.go rename to vendor/github.com/Microsoft/hcsshim/test/functional/uvm_scsi_test.go index c3d95f4a06..38b53b74a3 100644 --- a/vendor/github.com/Microsoft/hcsshim/functional/uvm_scsi_test.go +++ b/vendor/github.com/Microsoft/hcsshim/test/functional/uvm_scsi_test.go @@ -8,9 +8,9 @@ import ( "path/filepath" "testing" - "github.com/Microsoft/hcsshim/functional/utilities" "github.com/Microsoft/hcsshim/internal/uvm" "github.com/Microsoft/hcsshim/osversion" + "github.com/Microsoft/hcsshim/test/functional/utilities" "github.com/sirupsen/logrus" ) diff --git a/vendor/github.com/Microsoft/hcsshim/functional/uvm_vpmem_test.go b/vendor/github.com/Microsoft/hcsshim/test/functional/uvm_vpmem_test.go similarity index 95% rename from vendor/github.com/Microsoft/hcsshim/functional/uvm_vpmem_test.go rename to vendor/github.com/Microsoft/hcsshim/test/functional/uvm_vpmem_test.go index 43cb512471..eab0b06a5d 100644 --- a/vendor/github.com/Microsoft/hcsshim/functional/uvm_vpmem_test.go +++ b/vendor/github.com/Microsoft/hcsshim/test/functional/uvm_vpmem_test.go @@ -7,10 +7,10 @@ import ( "path/filepath" "testing" - "github.com/Microsoft/hcsshim/functional/utilities" "github.com/Microsoft/hcsshim/internal/copyfile" "github.com/Microsoft/hcsshim/internal/uvm" "github.com/Microsoft/hcsshim/osversion" + "github.com/Microsoft/hcsshim/test/functional/utilities" "github.com/sirupsen/logrus" ) diff --git a/vendor/github.com/Microsoft/hcsshim/functional/uvm_vsmb_test.go b/vendor/github.com/Microsoft/hcsshim/test/functional/uvm_vsmb_test.go similarity index 94% rename from vendor/github.com/Microsoft/hcsshim/functional/uvm_vsmb_test.go rename to vendor/github.com/Microsoft/hcsshim/test/functional/uvm_vsmb_test.go index 97158c39a7..4aeb0d3f2e 100644 --- a/vendor/github.com/Microsoft/hcsshim/functional/uvm_vsmb_test.go +++ b/vendor/github.com/Microsoft/hcsshim/test/functional/uvm_vsmb_test.go @@ -6,9 +6,9 @@ import ( "os" "testing" - "github.com/Microsoft/hcsshim/functional/utilities" "github.com/Microsoft/hcsshim/internal/schema2" "github.com/Microsoft/hcsshim/osversion" + "github.com/Microsoft/hcsshim/test/functional/utilities" ) // TestVSMB tests adding/removing VSMB layers from a v2 Windows utility VM diff --git a/vendor/github.com/Microsoft/hcsshim/functional/wcow_test.go b/vendor/github.com/Microsoft/hcsshim/test/functional/wcow_test.go similarity index 98% rename from vendor/github.com/Microsoft/hcsshim/functional/wcow_test.go rename to vendor/github.com/Microsoft/hcsshim/test/functional/wcow_test.go index 24290a26d0..0b9f104044 100644 --- a/vendor/github.com/Microsoft/hcsshim/functional/wcow_test.go +++ b/vendor/github.com/Microsoft/hcsshim/test/functional/wcow_test.go @@ -10,7 +10,6 @@ import ( "testing" "github.com/Microsoft/hcsshim" - "github.com/Microsoft/hcsshim/functional/utilities" "github.com/Microsoft/hcsshim/internal/hcs" "github.com/Microsoft/hcsshim/internal/hcsoci" "github.com/Microsoft/hcsshim/internal/schema1" @@ -20,6 +19,7 @@ import ( "github.com/Microsoft/hcsshim/internal/wclayer" "github.com/Microsoft/hcsshim/internal/wcow" "github.com/Microsoft/hcsshim/osversion" + "github.com/Microsoft/hcsshim/test/functional/utilities" specs "github.com/opencontainers/runtime-spec/specs-go" ) @@ -692,13 +692,9 @@ func TestWCOWXenonOciV2(t *testing.T) { t.Fatalf("failed to create scratch: %s", err) } - xenonOci2UVM, err = uvm.CreateWCOW( - &uvm.OptionsWCOW{ - Options: &uvm.Options{ - ID: xenonOci2UVMId, - }, - LayerFolders: append(imageLayers, xenonOci2UVMScratchDir), - }) + xenonOciOpts := uvm.NewDefaultOptionsWCOW(xenonOci2UVMId, "") + xenonOciOpts.LayerFolders = append(imageLayers, xenonOci2UVMScratchDir) + xenonOci2UVM, err = uvm.CreateWCOW(xenonOciOpts) if err != nil { t.Fatalf("Failed create UVM: %s", err) } diff --git a/vendor/github.com/Microsoft/hcsshim/functional/wcow_xenon_v2_test.go b/vendor/github.com/Microsoft/hcsshim/test/functional/wcow_xenon_v2_test.go similarity index 96% rename from vendor/github.com/Microsoft/hcsshim/functional/wcow_xenon_v2_test.go rename to vendor/github.com/Microsoft/hcsshim/test/functional/wcow_xenon_v2_test.go index 117bfb268d..69e0e6813a 100644 --- a/vendor/github.com/Microsoft/hcsshim/functional/wcow_xenon_v2_test.go +++ b/vendor/github.com/Microsoft/hcsshim/test/functional/wcow_xenon_v2_test.go @@ -6,7 +6,7 @@ package functional // "os" // "testing" -// "github.com/Microsoft/hcsshim/functional/utilities" +// "github.com/Microsoft/hcsshim/test/functional/utilities" // "github.com/Microsoft/hcsshim/internal/guid" // "github.com/Microsoft/hcsshim/internal/hcsoci" // "github.com/Microsoft/hcsshim/osversion" diff --git a/vendor/github.com/Microsoft/hcsshim/pkg/go-runhcs/runhcs_create-scratch_test.go b/vendor/github.com/Microsoft/hcsshim/test/runhcs/create-scratch_test.go similarity index 90% rename from vendor/github.com/Microsoft/hcsshim/pkg/go-runhcs/runhcs_create-scratch_test.go rename to vendor/github.com/Microsoft/hcsshim/test/runhcs/create-scratch_test.go index 4ce8c3d020..b5768bcf3d 100644 --- a/vendor/github.com/Microsoft/hcsshim/pkg/go-runhcs/runhcs_create-scratch_test.go +++ b/vendor/github.com/Microsoft/hcsshim/test/runhcs/create-scratch_test.go @@ -8,10 +8,12 @@ import ( "os" "path/filepath" "testing" + + runhcs "github.com/Microsoft/hcsshim/pkg/go-runhcs" ) func Test_CreateScratch_EmptyDestpath_Fail(t *testing.T) { - rhcs := Runhcs{ + rhcs := runhcs.Runhcs{ Debug: true, } @@ -23,7 +25,7 @@ func Test_CreateScratch_EmptyDestpath_Fail(t *testing.T) { } func Test_CreateScratch_DirDestpath_Failure(t *testing.T) { - rhcs := Runhcs{ + rhcs := runhcs.Runhcs{ Debug: true, } @@ -41,7 +43,7 @@ func Test_CreateScratch_DirDestpath_Failure(t *testing.T) { } func Test_CreateScratch_ValidDestpath_Success(t *testing.T) { - rhcs := Runhcs{ + rhcs := runhcs.Runhcs{ Debug: true, } diff --git a/vendor/github.com/Microsoft/hcsshim/pkg/go-runhcs/runhcs_e2e_matrix_test.go b/vendor/github.com/Microsoft/hcsshim/test/runhcs/e2e_matrix_test.go similarity index 97% rename from vendor/github.com/Microsoft/hcsshim/pkg/go-runhcs/runhcs_e2e_matrix_test.go rename to vendor/github.com/Microsoft/hcsshim/test/runhcs/e2e_matrix_test.go index bbe4657850..7a8684e1eb 100644 --- a/vendor/github.com/Microsoft/hcsshim/pkg/go-runhcs/runhcs_e2e_matrix_test.go +++ b/vendor/github.com/Microsoft/hcsshim/test/runhcs/e2e_matrix_test.go @@ -16,8 +16,9 @@ import ( "testing" "github.com/Microsoft/go-winio/vhd" - testutilities "github.com/Microsoft/hcsshim/functional/utilities" "github.com/Microsoft/hcsshim/osversion" + runhcs "github.com/Microsoft/hcsshim/pkg/go-runhcs" + testutilities "github.com/Microsoft/hcsshim/test/functional/utilities" runc "github.com/containerd/go-runc" "github.com/opencontainers/runtime-tools/generate" "github.com/pkg/errors" @@ -214,7 +215,7 @@ func testWindows(t *testing.T, version int, isolated bool) { // Create the Argon, Xenon, or UVM ctx := context.TODO() - rhcs := Runhcs{ + rhcs := runhcs.Runhcs{ Debug: true, } tio := newTestIO(t) @@ -226,7 +227,7 @@ func testWindows(t *testing.T, version int, isolated bool) { defer func() { tio.Close() }() - copts := &CreateOpts{ + copts := &runhcs.CreateOpts{ IO: tio, PidFile: filepath.Join(bundle, "pid-file.txt"), ShimLog: filepath.Join(bundle, "shim-log.txt"), @@ -240,7 +241,7 @@ func testWindows(t *testing.T, version int, isolated bool) { return } defer func() { - rhcs.Delete(ctx, t.Name(), &DeleteOpts{Force: true}) + rhcs.Delete(ctx, t.Name(), &runhcs.DeleteOpts{Force: true}) }() // Find the shim/vmshim process and begin exit wait diff --git a/vendor/github.com/Microsoft/hcsshim/pkg/go-runhcs/runhcs_list_test.go b/vendor/github.com/Microsoft/hcsshim/test/runhcs/list_test.go similarity index 82% rename from vendor/github.com/Microsoft/hcsshim/pkg/go-runhcs/runhcs_list_test.go rename to vendor/github.com/Microsoft/hcsshim/test/runhcs/list_test.go index c393f40c54..c0036aeeb2 100644 --- a/vendor/github.com/Microsoft/hcsshim/pkg/go-runhcs/runhcs_list_test.go +++ b/vendor/github.com/Microsoft/hcsshim/test/runhcs/list_test.go @@ -5,10 +5,12 @@ package runhcs import ( "context" "testing" + + runhcs "github.com/Microsoft/hcsshim/pkg/go-runhcs" ) func Test_List_NoContainers(t *testing.T) { - rhcs := Runhcs{ + rhcs := runhcs.Runhcs{ Debug: true, } diff --git a/vendor/github.com/Microsoft/hcsshim/test/runhcs/runhcs_test.go b/vendor/github.com/Microsoft/hcsshim/test/runhcs/runhcs_test.go new file mode 100644 index 0000000000..c59a9c99f0 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/test/runhcs/runhcs_test.go @@ -0,0 +1,7 @@ +// +build integration + +package runhcs + +import ( + _ "github.com/Microsoft/hcsshim/test/functional/manifest" +) diff --git a/vendor/github.com/Microsoft/hcsshim/tools/uvmboot/main.go b/vendor/github.com/Microsoft/hcsshim/tools/uvmboot/main.go index 627e004bfe..0cc4e04389 100644 --- a/vendor/github.com/Microsoft/hcsshim/tools/uvmboot/main.go +++ b/vendor/github.com/Microsoft/hcsshim/tools/uvmboot/main.go @@ -32,6 +32,7 @@ const ( forwardStderrArgName = "fwd-stderr" debugArgName = "debug" outputHandlingArgName = "output-handling" + consolePipeArgName = "console-pipe" ) func main() { @@ -88,7 +89,7 @@ func main() { }, cli.StringFlag{ Name: rootFSTypeArgName, - Usage: "Either 'initrd' or 'vhd'. Uses hcsshim default if not specified", + Usage: "Either 'initrd' or 'vhd'. (default: 'vhd' if rootfs.vhd exists)", }, cli.UintFlag{ Name: vpMemMaxCountArgName, @@ -100,7 +101,7 @@ func main() { }, cli.BoolFlag{ Name: kernelDirectArgName, - Usage: "Use kernel direct booting for UVM", + Usage: "Use kernel direct booting for UVM (default: true on builds >= 18286)", }, cli.StringFlag{ Name: execCommandLineArgName, @@ -118,6 +119,10 @@ func main() { Name: outputHandlingArgName, Usage: "Controls how output from UVM is handled. Use 'stdout' to print all output to stdout", }, + cli.StringFlag{ + Name: consolePipeArgName, + Usage: "Named pipe for serial console output (which will be enabled)", + }, }, Action: func(c *cli.Context) error { if c.GlobalBool("debug") { @@ -142,16 +147,8 @@ func main() { id := fmt.Sprintf("uvmboot-%d", i) - options := uvm.OptionsLCOW{ - Options: &uvm.Options{ - ID: id, - }, - } - - { - val := false - options.UseGuestConnection = &val - } + options := uvm.NewDefaultOptionsLCOW(id, "") + options.UseGuestConnection = false if c.GlobalIsSet(cpusArgName) { options.ProcessorCount = int32(c.GlobalUint64(cpusArgName)) @@ -160,12 +157,10 @@ func main() { options.MemorySizeInMB = int32(c.GlobalUint64(memoryArgName)) } if c.GlobalIsSet(allowOvercommitArgName) { - val := c.GlobalBool(allowOvercommitArgName) - options.AllowOvercommit = &val + options.AllowOvercommit = c.GlobalBool(allowOvercommitArgName) } if c.GlobalIsSet(enableDeferredCommitArgName) { - val := c.GlobalBool(enableDeferredCommitArgName) - options.EnableDeferredCommit = &val + options.EnableDeferredCommit = c.GlobalBool(enableDeferredCommitArgName) } if c.IsSet(kernelDirectArgName) { @@ -174,11 +169,11 @@ func main() { if c.IsSet(rootFSTypeArgName) { switch strings.ToLower(c.String(rootFSTypeArgName)) { case "initrd": - val := uvm.PreferredRootFSTypeInitRd - options.PreferredRootFSType = &val + options.RootFSFile = uvm.InitrdFile + options.PreferredRootFSType = uvm.PreferredRootFSTypeInitRd case "vhd": - val := uvm.PreferredRootFSTypeVHD - options.PreferredRootFSType = &val + options.RootFSFile = uvm.VhdFile + options.PreferredRootFSType = uvm.PreferredRootFSTypeVHD default: logrus.Fatalf("Unrecognized value '%s' for option %s", c.String(rootFSTypeArgName), rootFSTypeArgName) } @@ -187,35 +182,33 @@ func main() { options.KernelBootOptions = c.String(kernelArgsArgName) } if c.IsSet(vpMemMaxCountArgName) { - val := uint32(c.Uint(vpMemMaxCountArgName)) - options.VPMemDeviceCount = &val + options.VPMemDeviceCount = uint32(c.Uint(vpMemMaxCountArgName)) } if c.IsSet(vpMemMaxSizeArgName) { - val := c.Uint64(vpMemMaxSizeArgName) * 1024 * 1024 // convert from MB to bytes - options.VPMemSizeBytes = &val + options.VPMemSizeBytes = c.Uint64(vpMemMaxSizeArgName) * 1024 * 1024 // convert from MB to bytes } if c.IsSet(execCommandLineArgName) { options.ExecCommandLine = c.String(execCommandLineArgName) } if c.IsSet(forwardStdoutArgName) { - val := c.Bool(forwardStdoutArgName) - options.ForwardStdout = &val + options.ForwardStdout = c.Bool(forwardStdoutArgName) } if c.IsSet(forwardStderrArgName) { - val := c.Bool(forwardStderrArgName) - options.ForwardStderr = &val + options.ForwardStderr = c.Bool(forwardStderrArgName) } if c.IsSet(outputHandlingArgName) { switch strings.ToLower(c.String(outputHandlingArgName)) { case "stdout": - val := uvm.OutputHandler(func(r io.Reader) { io.Copy(os.Stdout, r) }) - options.OutputHandler = &val + options.OutputHandler = uvm.OutputHandler(func(r io.Reader) { io.Copy(os.Stdout, r) }) default: logrus.Fatalf("Unrecognized value '%s' for option %s", c.String(outputHandlingArgName), outputHandlingArgName) } } + if c.IsSet(consolePipeArgName) { + options.ConsolePipe = c.String(consolePipeArgName) + } - if err := run(&options); err != nil { + if err := run(options); err != nil { logrus.WithField("uvm-id", id).Error(err) } } diff --git a/vendor/github.com/Microsoft/hcsshim/vendor.conf b/vendor/github.com/Microsoft/hcsshim/vendor.conf new file mode 100644 index 0000000000..6e0ed15662 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor.conf @@ -0,0 +1,21 @@ +github.com/blang/semver v3.1.0 +github.com/containerd/console c12b1e7919c14469339a5d38f2f8ed9b64a9de23 +github.com/containerd/go-runc 5a6d9f37cfa36b15efba46dc7ea349fa9b7143c3 +github.com/hashicorp/errwrap 7554cd9344cec97297fa6649b055a8c98c2a1e55 +github.com/hashicorp/go-multierror ed905158d87462226a13fe39ddf685ea65f1c11f +github.com/konsorten/go-windows-terminal-sequences v1.0.1 +github.com/linuxkit/virtsock 8e79449dea0735c1c056d814934dd035734cc97c +github.com/Microsoft/go-winio 16cfc975803886a5e47c4257a24c8d8c52e178b2 +github.com/Microsoft/opengcs v0.3.9 +github.com/opencontainers/runtime-spec eba862dc2470385a233c7507392675cbeadf7353 +github.com/opencontainers/runtime-tools 1d69bd0f9c39677d0630e50664fbc3154ae61b88 +github.com/pkg/errors v0.8.1 +github.com/sirupsen/logrus v1.3.0 +github.com/syndtr/gocapability db04d3cc01c8b54962a58ec7e491717d06cfcc16 +github.com/urfave/cli 7bc6a0acffa589f415f88aca16cc1de5ffd66f9c +github.com/xeipuuv/gojsonpointer 4e3ac2762d5f479393488629ee9370b50873b3a6 +github.com/xeipuuv/gojsonreference bd5ef7bd5415a7ac448318e64f11a24cd21e594b +github.com/xeipuuv/gojsonschema 1d523034197ff1f222f6429836dd36a2457a1874 +golang.org/x/crypto ff983b9c42bc9fbf91556e191cc8efb585c16908 +golang.org/x/sync 37e7f081c4d4c64e13b10787722085407fe5d15f +golang.org/x/sys e5ecc2a6747ce8d4af18ed98b3de5ae30eb3a5bb \ No newline at end of file diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/LICENSE b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/LICENSE new file mode 100644 index 0000000000..b8b569d774 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/LICENSE @@ -0,0 +1,22 @@ +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. + diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/README.md b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/README.md new file mode 100644 index 0000000000..5680010575 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/README.md @@ -0,0 +1,22 @@ +# go-winio + +This repository contains utilities for efficiently performing Win32 IO operations in +Go. Currently, this is focused on accessing named pipes and other file handles, and +for using named pipes as a net transport. + +This code relies on IO completion ports to avoid blocking IO on system threads, allowing Go +to reuse the thread to schedule another goroutine. This limits support to Windows Vista and +newer operating systems. This is similar to the implementation of network sockets in Go's net +package. + +Please see the LICENSE file for licensing information. + +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. + +Thanks to natefinch for the inspiration for this library. See https://github.com/natefinch/npipe +for another named pipe implementation. diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/archive/tar/LICENSE b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/archive/tar/LICENSE new file mode 100644 index 0000000000..7448756763 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/archive/tar/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2012 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/archive/tar/common.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/archive/tar/common.go new file mode 100644 index 0000000000..0378401c0d --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/archive/tar/common.go @@ -0,0 +1,344 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package tar implements access to tar archives. +// It aims to cover most of the variations, including those produced +// by GNU and BSD tars. +// +// References: +// http://www.freebsd.org/cgi/man.cgi?query=tar&sektion=5 +// http://www.gnu.org/software/tar/manual/html_node/Standard.html +// http://pubs.opengroup.org/onlinepubs/9699919799/utilities/pax.html +package tar + +import ( + "bytes" + "errors" + "fmt" + "os" + "path" + "time" +) + +const ( + blockSize = 512 + + // Types + TypeReg = '0' // regular file + TypeRegA = '\x00' // regular file + TypeLink = '1' // hard link + TypeSymlink = '2' // symbolic link + TypeChar = '3' // character device node + TypeBlock = '4' // block device node + TypeDir = '5' // directory + TypeFifo = '6' // fifo node + TypeCont = '7' // reserved + TypeXHeader = 'x' // extended header + TypeXGlobalHeader = 'g' // global extended header + TypeGNULongName = 'L' // Next file has a long name + TypeGNULongLink = 'K' // Next file symlinks to a file w/ a long name + TypeGNUSparse = 'S' // sparse file +) + +// A Header represents a single header in a tar archive. +// Some fields may not be populated. +type Header struct { + Name string // name of header file entry + Mode int64 // permission and mode bits + Uid int // user id of owner + Gid int // group id of owner + Size int64 // length in bytes + ModTime time.Time // modified time + Typeflag byte // type of header entry + Linkname string // target name of link + Uname string // user name of owner + Gname string // group name of owner + Devmajor int64 // major number of character or block device + Devminor int64 // minor number of character or block device + AccessTime time.Time // access time + ChangeTime time.Time // status change time + CreationTime time.Time // creation time + Xattrs map[string]string + Winheaders map[string]string +} + +// File name constants from the tar spec. +const ( + fileNameSize = 100 // Maximum number of bytes in a standard tar name. + fileNamePrefixSize = 155 // Maximum number of ustar extension bytes. +) + +// FileInfo returns an os.FileInfo for the Header. +func (h *Header) FileInfo() os.FileInfo { + return headerFileInfo{h} +} + +// headerFileInfo implements os.FileInfo. +type headerFileInfo struct { + h *Header +} + +func (fi headerFileInfo) Size() int64 { return fi.h.Size } +func (fi headerFileInfo) IsDir() bool { return fi.Mode().IsDir() } +func (fi headerFileInfo) ModTime() time.Time { return fi.h.ModTime } +func (fi headerFileInfo) Sys() interface{} { return fi.h } + +// Name returns the base name of the file. +func (fi headerFileInfo) Name() string { + if fi.IsDir() { + return path.Base(path.Clean(fi.h.Name)) + } + return path.Base(fi.h.Name) +} + +// Mode returns the permission and mode bits for the headerFileInfo. +func (fi headerFileInfo) Mode() (mode os.FileMode) { + // Set file permission bits. + mode = os.FileMode(fi.h.Mode).Perm() + + // Set setuid, setgid and sticky bits. + if fi.h.Mode&c_ISUID != 0 { + // setuid + mode |= os.ModeSetuid + } + if fi.h.Mode&c_ISGID != 0 { + // setgid + mode |= os.ModeSetgid + } + if fi.h.Mode&c_ISVTX != 0 { + // sticky + mode |= os.ModeSticky + } + + // Set file mode bits. + // clear perm, setuid, setgid and sticky bits. + m := os.FileMode(fi.h.Mode) &^ 07777 + if m == c_ISDIR { + // directory + mode |= os.ModeDir + } + if m == c_ISFIFO { + // named pipe (FIFO) + mode |= os.ModeNamedPipe + } + if m == c_ISLNK { + // symbolic link + mode |= os.ModeSymlink + } + if m == c_ISBLK { + // device file + mode |= os.ModeDevice + } + if m == c_ISCHR { + // Unix character device + mode |= os.ModeDevice + mode |= os.ModeCharDevice + } + if m == c_ISSOCK { + // Unix domain socket + mode |= os.ModeSocket + } + + switch fi.h.Typeflag { + case TypeSymlink: + // symbolic link + mode |= os.ModeSymlink + case TypeChar: + // character device node + mode |= os.ModeDevice + mode |= os.ModeCharDevice + case TypeBlock: + // block device node + mode |= os.ModeDevice + case TypeDir: + // directory + mode |= os.ModeDir + case TypeFifo: + // fifo node + mode |= os.ModeNamedPipe + } + + return mode +} + +// sysStat, if non-nil, populates h from system-dependent fields of fi. +var sysStat func(fi os.FileInfo, h *Header) error + +// Mode constants from the tar spec. +const ( + c_ISUID = 04000 // Set uid + c_ISGID = 02000 // Set gid + c_ISVTX = 01000 // Save text (sticky bit) + c_ISDIR = 040000 // Directory + c_ISFIFO = 010000 // FIFO + c_ISREG = 0100000 // Regular file + c_ISLNK = 0120000 // Symbolic link + c_ISBLK = 060000 // Block special file + c_ISCHR = 020000 // Character special file + c_ISSOCK = 0140000 // Socket +) + +// Keywords for the PAX Extended Header +const ( + paxAtime = "atime" + paxCharset = "charset" + paxComment = "comment" + paxCtime = "ctime" // please note that ctime is not a valid pax header. + paxCreationTime = "LIBARCHIVE.creationtime" + paxGid = "gid" + paxGname = "gname" + paxLinkpath = "linkpath" + paxMtime = "mtime" + paxPath = "path" + paxSize = "size" + paxUid = "uid" + paxUname = "uname" + paxXattr = "SCHILY.xattr." + paxWindows = "MSWINDOWS." + paxNone = "" +) + +// FileInfoHeader creates a partially-populated Header from fi. +// If fi describes a symlink, FileInfoHeader records link as the link target. +// If fi describes a directory, a slash is appended to the name. +// Because os.FileInfo's Name method returns only the base name of +// the file it describes, it may be necessary to modify the Name field +// of the returned header to provide the full path name of the file. +func FileInfoHeader(fi os.FileInfo, link string) (*Header, error) { + if fi == nil { + return nil, errors.New("tar: FileInfo is nil") + } + fm := fi.Mode() + h := &Header{ + Name: fi.Name(), + ModTime: fi.ModTime(), + Mode: int64(fm.Perm()), // or'd with c_IS* constants later + } + switch { + case fm.IsRegular(): + h.Mode |= c_ISREG + h.Typeflag = TypeReg + h.Size = fi.Size() + case fi.IsDir(): + h.Typeflag = TypeDir + h.Mode |= c_ISDIR + h.Name += "/" + case fm&os.ModeSymlink != 0: + h.Typeflag = TypeSymlink + h.Mode |= c_ISLNK + h.Linkname = link + case fm&os.ModeDevice != 0: + if fm&os.ModeCharDevice != 0 { + h.Mode |= c_ISCHR + h.Typeflag = TypeChar + } else { + h.Mode |= c_ISBLK + h.Typeflag = TypeBlock + } + case fm&os.ModeNamedPipe != 0: + h.Typeflag = TypeFifo + h.Mode |= c_ISFIFO + case fm&os.ModeSocket != 0: + h.Mode |= c_ISSOCK + default: + return nil, fmt.Errorf("archive/tar: unknown file mode %v", fm) + } + if fm&os.ModeSetuid != 0 { + h.Mode |= c_ISUID + } + if fm&os.ModeSetgid != 0 { + h.Mode |= c_ISGID + } + if fm&os.ModeSticky != 0 { + h.Mode |= c_ISVTX + } + // If possible, populate additional fields from OS-specific + // FileInfo fields. + if sys, ok := fi.Sys().(*Header); ok { + // This FileInfo came from a Header (not the OS). Use the + // original Header to populate all remaining fields. + h.Uid = sys.Uid + h.Gid = sys.Gid + h.Uname = sys.Uname + h.Gname = sys.Gname + h.AccessTime = sys.AccessTime + h.ChangeTime = sys.ChangeTime + if sys.Xattrs != nil { + h.Xattrs = make(map[string]string) + for k, v := range sys.Xattrs { + h.Xattrs[k] = v + } + } + if sys.Typeflag == TypeLink { + // hard link + h.Typeflag = TypeLink + h.Size = 0 + h.Linkname = sys.Linkname + } + } + if sysStat != nil { + return h, sysStat(fi, h) + } + return h, nil +} + +var zeroBlock = make([]byte, blockSize) + +// POSIX specifies a sum of the unsigned byte values, but the Sun tar uses signed byte values. +// We compute and return both. +func checksum(header []byte) (unsigned int64, signed int64) { + for i := 0; i < len(header); i++ { + if i == 148 { + // The chksum field (header[148:156]) is special: it should be treated as space bytes. + unsigned += ' ' * 8 + signed += ' ' * 8 + i += 7 + continue + } + unsigned += int64(header[i]) + signed += int64(int8(header[i])) + } + return +} + +type slicer []byte + +func (sp *slicer) next(n int) (b []byte) { + s := *sp + b, *sp = s[0:n], s[n:] + return +} + +func isASCII(s string) bool { + for _, c := range s { + if c >= 0x80 { + return false + } + } + return true +} + +func toASCII(s string) string { + if isASCII(s) { + return s + } + var buf bytes.Buffer + for _, c := range s { + if c < 0x80 { + buf.WriteByte(byte(c)) + } + } + return buf.String() +} + +// isHeaderOnlyType checks if the given type flag is of the type that has no +// data section even if a size is specified. +func isHeaderOnlyType(flag byte) bool { + switch flag { + case TypeLink, TypeSymlink, TypeChar, TypeBlock, TypeDir, TypeFifo: + return true + default: + return false + } +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/archive/tar/reader.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/archive/tar/reader.go new file mode 100644 index 0000000000..e210c618a1 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/archive/tar/reader.go @@ -0,0 +1,1002 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package tar + +// TODO(dsymonds): +// - pax extensions + +import ( + "bytes" + "errors" + "io" + "io/ioutil" + "math" + "os" + "strconv" + "strings" + "time" +) + +var ( + ErrHeader = errors.New("archive/tar: invalid tar header") +) + +const maxNanoSecondIntSize = 9 + +// A Reader provides sequential access to the contents of a tar archive. +// A tar archive consists of a sequence of files. +// The Next method advances to the next file in the archive (including the first), +// and then it can be treated as an io.Reader to access the file's data. +type Reader struct { + r io.Reader + err error + pad int64 // amount of padding (ignored) after current file entry + curr numBytesReader // reader for current file entry + hdrBuff [blockSize]byte // buffer to use in readHeader +} + +type parser struct { + err error // Last error seen +} + +// A numBytesReader is an io.Reader with a numBytes method, returning the number +// of bytes remaining in the underlying encoded data. +type numBytesReader interface { + io.Reader + numBytes() int64 +} + +// A regFileReader is a numBytesReader for reading file data from a tar archive. +type regFileReader struct { + r io.Reader // underlying reader + nb int64 // number of unread bytes for current file entry +} + +// A sparseFileReader is a numBytesReader for reading sparse file data from a +// tar archive. +type sparseFileReader struct { + rfr numBytesReader // Reads the sparse-encoded file data + sp []sparseEntry // The sparse map for the file + pos int64 // Keeps track of file position + total int64 // Total size of the file +} + +// A sparseEntry holds a single entry in a sparse file's sparse map. +// +// Sparse files are represented using a series of sparseEntrys. +// Despite the name, a sparseEntry represents an actual data fragment that +// references data found in the underlying archive stream. All regions not +// covered by a sparseEntry are logically filled with zeros. +// +// For example, if the underlying raw file contains the 10-byte data: +// var compactData = "abcdefgh" +// +// And the sparse map has the following entries: +// var sp = []sparseEntry{ +// {offset: 2, numBytes: 5} // Data fragment for [2..7] +// {offset: 18, numBytes: 3} // Data fragment for [18..21] +// } +// +// Then the content of the resulting sparse file with a "real" size of 25 is: +// var sparseData = "\x00"*2 + "abcde" + "\x00"*11 + "fgh" + "\x00"*4 +type sparseEntry struct { + offset int64 // Starting position of the fragment + numBytes int64 // Length of the fragment +} + +// Keywords for GNU sparse files in a PAX extended header +const ( + paxGNUSparseNumBlocks = "GNU.sparse.numblocks" + paxGNUSparseOffset = "GNU.sparse.offset" + paxGNUSparseNumBytes = "GNU.sparse.numbytes" + paxGNUSparseMap = "GNU.sparse.map" + paxGNUSparseName = "GNU.sparse.name" + paxGNUSparseMajor = "GNU.sparse.major" + paxGNUSparseMinor = "GNU.sparse.minor" + paxGNUSparseSize = "GNU.sparse.size" + paxGNUSparseRealSize = "GNU.sparse.realsize" +) + +// Keywords for old GNU sparse headers +const ( + oldGNUSparseMainHeaderOffset = 386 + oldGNUSparseMainHeaderIsExtendedOffset = 482 + oldGNUSparseMainHeaderNumEntries = 4 + oldGNUSparseExtendedHeaderIsExtendedOffset = 504 + oldGNUSparseExtendedHeaderNumEntries = 21 + oldGNUSparseOffsetSize = 12 + oldGNUSparseNumBytesSize = 12 +) + +// NewReader creates a new Reader reading from r. +func NewReader(r io.Reader) *Reader { return &Reader{r: r} } + +// Next advances to the next entry in the tar archive. +// +// io.EOF is returned at the end of the input. +func (tr *Reader) Next() (*Header, error) { + if tr.err != nil { + return nil, tr.err + } + + var hdr *Header + var extHdrs map[string]string + + // Externally, Next iterates through the tar archive as if it is a series of + // files. Internally, the tar format often uses fake "files" to add meta + // data that describes the next file. These meta data "files" should not + // normally be visible to the outside. As such, this loop iterates through + // one or more "header files" until it finds a "normal file". +loop: + for { + tr.err = tr.skipUnread() + if tr.err != nil { + return nil, tr.err + } + + hdr = tr.readHeader() + if tr.err != nil { + return nil, tr.err + } + + // Check for PAX/GNU special headers and files. + switch hdr.Typeflag { + case TypeXHeader: + extHdrs, tr.err = parsePAX(tr) + if tr.err != nil { + return nil, tr.err + } + continue loop // This is a meta header affecting the next header + case TypeGNULongName, TypeGNULongLink: + var realname []byte + realname, tr.err = ioutil.ReadAll(tr) + if tr.err != nil { + return nil, tr.err + } + + // Convert GNU extensions to use PAX headers. + if extHdrs == nil { + extHdrs = make(map[string]string) + } + var p parser + switch hdr.Typeflag { + case TypeGNULongName: + extHdrs[paxPath] = p.parseString(realname) + case TypeGNULongLink: + extHdrs[paxLinkpath] = p.parseString(realname) + } + if p.err != nil { + tr.err = p.err + return nil, tr.err + } + continue loop // This is a meta header affecting the next header + default: + mergePAX(hdr, extHdrs) + + // Check for a PAX format sparse file + sp, err := tr.checkForGNUSparsePAXHeaders(hdr, extHdrs) + if err != nil { + tr.err = err + return nil, err + } + if sp != nil { + // Current file is a PAX format GNU sparse file. + // Set the current file reader to a sparse file reader. + tr.curr, tr.err = newSparseFileReader(tr.curr, sp, hdr.Size) + if tr.err != nil { + return nil, tr.err + } + } + break loop // This is a file, so stop + } + } + return hdr, nil +} + +// checkForGNUSparsePAXHeaders checks the PAX headers for GNU sparse headers. If they are found, then +// this function reads the sparse map and returns it. Unknown sparse formats are ignored, causing the file to +// be treated as a regular file. +func (tr *Reader) checkForGNUSparsePAXHeaders(hdr *Header, headers map[string]string) ([]sparseEntry, error) { + var sparseFormat string + + // Check for sparse format indicators + major, majorOk := headers[paxGNUSparseMajor] + minor, minorOk := headers[paxGNUSparseMinor] + sparseName, sparseNameOk := headers[paxGNUSparseName] + _, sparseMapOk := headers[paxGNUSparseMap] + sparseSize, sparseSizeOk := headers[paxGNUSparseSize] + sparseRealSize, sparseRealSizeOk := headers[paxGNUSparseRealSize] + + // Identify which, if any, sparse format applies from which PAX headers are set + if majorOk && minorOk { + sparseFormat = major + "." + minor + } else if sparseNameOk && sparseMapOk { + sparseFormat = "0.1" + } else if sparseSizeOk { + sparseFormat = "0.0" + } else { + // Not a PAX format GNU sparse file. + return nil, nil + } + + // Check for unknown sparse format + if sparseFormat != "0.0" && sparseFormat != "0.1" && sparseFormat != "1.0" { + return nil, nil + } + + // Update hdr from GNU sparse PAX headers + if sparseNameOk { + hdr.Name = sparseName + } + if sparseSizeOk { + realSize, err := strconv.ParseInt(sparseSize, 10, 0) + if err != nil { + return nil, ErrHeader + } + hdr.Size = realSize + } else if sparseRealSizeOk { + realSize, err := strconv.ParseInt(sparseRealSize, 10, 0) + if err != nil { + return nil, ErrHeader + } + hdr.Size = realSize + } + + // Set up the sparse map, according to the particular sparse format in use + var sp []sparseEntry + var err error + switch sparseFormat { + case "0.0", "0.1": + sp, err = readGNUSparseMap0x1(headers) + case "1.0": + sp, err = readGNUSparseMap1x0(tr.curr) + } + return sp, err +} + +// mergePAX merges well known headers according to PAX standard. +// In general headers with the same name as those found +// in the header struct overwrite those found in the header +// struct with higher precision or longer values. Esp. useful +// for name and linkname fields. +func mergePAX(hdr *Header, headers map[string]string) error { + for k, v := range headers { + switch k { + case paxPath: + hdr.Name = v + case paxLinkpath: + hdr.Linkname = v + case paxGname: + hdr.Gname = v + case paxUname: + hdr.Uname = v + case paxUid: + uid, err := strconv.ParseInt(v, 10, 0) + if err != nil { + return err + } + hdr.Uid = int(uid) + case paxGid: + gid, err := strconv.ParseInt(v, 10, 0) + if err != nil { + return err + } + hdr.Gid = int(gid) + case paxAtime: + t, err := parsePAXTime(v) + if err != nil { + return err + } + hdr.AccessTime = t + case paxMtime: + t, err := parsePAXTime(v) + if err != nil { + return err + } + hdr.ModTime = t + case paxCtime: + t, err := parsePAXTime(v) + if err != nil { + return err + } + hdr.ChangeTime = t + case paxCreationTime: + t, err := parsePAXTime(v) + if err != nil { + return err + } + hdr.CreationTime = t + case paxSize: + size, err := strconv.ParseInt(v, 10, 0) + if err != nil { + return err + } + hdr.Size = int64(size) + default: + if strings.HasPrefix(k, paxXattr) { + if hdr.Xattrs == nil { + hdr.Xattrs = make(map[string]string) + } + hdr.Xattrs[k[len(paxXattr):]] = v + } else if strings.HasPrefix(k, paxWindows) { + if hdr.Winheaders == nil { + hdr.Winheaders = make(map[string]string) + } + hdr.Winheaders[k[len(paxWindows):]] = v + } + } + } + return nil +} + +// parsePAXTime takes a string of the form %d.%d as described in +// the PAX specification. +func parsePAXTime(t string) (time.Time, error) { + buf := []byte(t) + pos := bytes.IndexByte(buf, '.') + var seconds, nanoseconds int64 + var err error + if pos == -1 { + seconds, err = strconv.ParseInt(t, 10, 0) + if err != nil { + return time.Time{}, err + } + } else { + seconds, err = strconv.ParseInt(string(buf[:pos]), 10, 0) + if err != nil { + return time.Time{}, err + } + nano_buf := string(buf[pos+1:]) + // Pad as needed before converting to a decimal. + // For example .030 -> .030000000 -> 30000000 nanoseconds + if len(nano_buf) < maxNanoSecondIntSize { + // Right pad + nano_buf += strings.Repeat("0", maxNanoSecondIntSize-len(nano_buf)) + } else if len(nano_buf) > maxNanoSecondIntSize { + // Right truncate + nano_buf = nano_buf[:maxNanoSecondIntSize] + } + nanoseconds, err = strconv.ParseInt(string(nano_buf), 10, 0) + if err != nil { + return time.Time{}, err + } + } + ts := time.Unix(seconds, nanoseconds) + return ts, nil +} + +// parsePAX parses PAX headers. +// If an extended header (type 'x') is invalid, ErrHeader is returned +func parsePAX(r io.Reader) (map[string]string, error) { + buf, err := ioutil.ReadAll(r) + if err != nil { + return nil, err + } + sbuf := string(buf) + + // For GNU PAX sparse format 0.0 support. + // This function transforms the sparse format 0.0 headers into sparse format 0.1 headers. + var sparseMap bytes.Buffer + + headers := make(map[string]string) + // Each record is constructed as + // "%d %s=%s\n", length, keyword, value + for len(sbuf) > 0 { + key, value, residual, err := parsePAXRecord(sbuf) + if err != nil { + return nil, ErrHeader + } + sbuf = residual + + keyStr := string(key) + if keyStr == paxGNUSparseOffset || keyStr == paxGNUSparseNumBytes { + // GNU sparse format 0.0 special key. Write to sparseMap instead of using the headers map. + sparseMap.WriteString(value) + sparseMap.Write([]byte{','}) + } else { + // Normal key. Set the value in the headers map. + headers[keyStr] = string(value) + } + } + if sparseMap.Len() != 0 { + // Add sparse info to headers, chopping off the extra comma + sparseMap.Truncate(sparseMap.Len() - 1) + headers[paxGNUSparseMap] = sparseMap.String() + } + return headers, nil +} + +// parsePAXRecord parses the input PAX record string into a key-value pair. +// If parsing is successful, it will slice off the currently read record and +// return the remainder as r. +// +// A PAX record is of the following form: +// "%d %s=%s\n" % (size, key, value) +func parsePAXRecord(s string) (k, v, r string, err error) { + // The size field ends at the first space. + sp := strings.IndexByte(s, ' ') + if sp == -1 { + return "", "", s, ErrHeader + } + + // Parse the first token as a decimal integer. + n, perr := strconv.ParseInt(s[:sp], 10, 0) // Intentionally parse as native int + if perr != nil || n < 5 || int64(len(s)) < n { + return "", "", s, ErrHeader + } + + // Extract everything between the space and the final newline. + rec, nl, rem := s[sp+1:n-1], s[n-1:n], s[n:] + if nl != "\n" { + return "", "", s, ErrHeader + } + + // The first equals separates the key from the value. + eq := strings.IndexByte(rec, '=') + if eq == -1 { + return "", "", s, ErrHeader + } + return rec[:eq], rec[eq+1:], rem, nil +} + +// parseString parses bytes as a NUL-terminated C-style string. +// If a NUL byte is not found then the whole slice is returned as a string. +func (*parser) parseString(b []byte) string { + n := 0 + for n < len(b) && b[n] != 0 { + n++ + } + return string(b[0:n]) +} + +// parseNumeric parses the input as being encoded in either base-256 or octal. +// This function may return negative numbers. +// If parsing fails or an integer overflow occurs, err will be set. +func (p *parser) parseNumeric(b []byte) int64 { + // Check for base-256 (binary) format first. + // If the first bit is set, then all following bits constitute a two's + // complement encoded number in big-endian byte order. + if len(b) > 0 && b[0]&0x80 != 0 { + // Handling negative numbers relies on the following identity: + // -a-1 == ^a + // + // If the number is negative, we use an inversion mask to invert the + // data bytes and treat the value as an unsigned number. + var inv byte // 0x00 if positive or zero, 0xff if negative + if b[0]&0x40 != 0 { + inv = 0xff + } + + var x uint64 + for i, c := range b { + c ^= inv // Inverts c only if inv is 0xff, otherwise does nothing + if i == 0 { + c &= 0x7f // Ignore signal bit in first byte + } + if (x >> 56) > 0 { + p.err = ErrHeader // Integer overflow + return 0 + } + x = x<<8 | uint64(c) + } + if (x >> 63) > 0 { + p.err = ErrHeader // Integer overflow + return 0 + } + if inv == 0xff { + return ^int64(x) + } + return int64(x) + } + + // Normal case is base-8 (octal) format. + return p.parseOctal(b) +} + +func (p *parser) parseOctal(b []byte) int64 { + // Because unused fields are filled with NULs, we need + // to skip leading NULs. Fields may also be padded with + // spaces or NULs. + // So we remove leading and trailing NULs and spaces to + // be sure. + b = bytes.Trim(b, " \x00") + + if len(b) == 0 { + return 0 + } + x, perr := strconv.ParseUint(p.parseString(b), 8, 64) + if perr != nil { + p.err = ErrHeader + } + return int64(x) +} + +// skipUnread skips any unread bytes in the existing file entry, as well as any +// alignment padding. It returns io.ErrUnexpectedEOF if any io.EOF is +// encountered in the data portion; it is okay to hit io.EOF in the padding. +// +// Note that this function still works properly even when sparse files are being +// used since numBytes returns the bytes remaining in the underlying io.Reader. +func (tr *Reader) skipUnread() error { + dataSkip := tr.numBytes() // Number of data bytes to skip + totalSkip := dataSkip + tr.pad // Total number of bytes to skip + tr.curr, tr.pad = nil, 0 + + // If possible, Seek to the last byte before the end of the data section. + // Do this because Seek is often lazy about reporting errors; this will mask + // the fact that the tar stream may be truncated. We can rely on the + // io.CopyN done shortly afterwards to trigger any IO errors. + var seekSkipped int64 // Number of bytes skipped via Seek + if sr, ok := tr.r.(io.Seeker); ok && dataSkip > 1 { + // Not all io.Seeker can actually Seek. For example, os.Stdin implements + // io.Seeker, but calling Seek always returns an error and performs + // no action. Thus, we try an innocent seek to the current position + // to see if Seek is really supported. + pos1, err := sr.Seek(0, os.SEEK_CUR) + if err == nil { + // Seek seems supported, so perform the real Seek. + pos2, err := sr.Seek(dataSkip-1, os.SEEK_CUR) + if err != nil { + tr.err = err + return tr.err + } + seekSkipped = pos2 - pos1 + } + } + + var copySkipped int64 // Number of bytes skipped via CopyN + copySkipped, tr.err = io.CopyN(ioutil.Discard, tr.r, totalSkip-seekSkipped) + if tr.err == io.EOF && seekSkipped+copySkipped < dataSkip { + tr.err = io.ErrUnexpectedEOF + } + return tr.err +} + +func (tr *Reader) verifyChecksum(header []byte) bool { + if tr.err != nil { + return false + } + + var p parser + given := p.parseOctal(header[148:156]) + unsigned, signed := checksum(header) + return p.err == nil && (given == unsigned || given == signed) +} + +// readHeader reads the next block header and assumes that the underlying reader +// is already aligned to a block boundary. +// +// The err will be set to io.EOF only when one of the following occurs: +// * Exactly 0 bytes are read and EOF is hit. +// * Exactly 1 block of zeros is read and EOF is hit. +// * At least 2 blocks of zeros are read. +func (tr *Reader) readHeader() *Header { + header := tr.hdrBuff[:] + copy(header, zeroBlock) + + if _, tr.err = io.ReadFull(tr.r, header); tr.err != nil { + return nil // io.EOF is okay here + } + + // Two blocks of zero bytes marks the end of the archive. + if bytes.Equal(header, zeroBlock[0:blockSize]) { + if _, tr.err = io.ReadFull(tr.r, header); tr.err != nil { + return nil // io.EOF is okay here + } + if bytes.Equal(header, zeroBlock[0:blockSize]) { + tr.err = io.EOF + } else { + tr.err = ErrHeader // zero block and then non-zero block + } + return nil + } + + if !tr.verifyChecksum(header) { + tr.err = ErrHeader + return nil + } + + // Unpack + var p parser + hdr := new(Header) + s := slicer(header) + + hdr.Name = p.parseString(s.next(100)) + hdr.Mode = p.parseNumeric(s.next(8)) + hdr.Uid = int(p.parseNumeric(s.next(8))) + hdr.Gid = int(p.parseNumeric(s.next(8))) + hdr.Size = p.parseNumeric(s.next(12)) + hdr.ModTime = time.Unix(p.parseNumeric(s.next(12)), 0) + s.next(8) // chksum + hdr.Typeflag = s.next(1)[0] + hdr.Linkname = p.parseString(s.next(100)) + + // The remainder of the header depends on the value of magic. + // The original (v7) version of tar had no explicit magic field, + // so its magic bytes, like the rest of the block, are NULs. + magic := string(s.next(8)) // contains version field as well. + var format string + switch { + case magic[:6] == "ustar\x00": // POSIX tar (1003.1-1988) + if string(header[508:512]) == "tar\x00" { + format = "star" + } else { + format = "posix" + } + case magic == "ustar \x00": // old GNU tar + format = "gnu" + } + + switch format { + case "posix", "gnu", "star": + hdr.Uname = p.parseString(s.next(32)) + hdr.Gname = p.parseString(s.next(32)) + devmajor := s.next(8) + devminor := s.next(8) + if hdr.Typeflag == TypeChar || hdr.Typeflag == TypeBlock { + hdr.Devmajor = p.parseNumeric(devmajor) + hdr.Devminor = p.parseNumeric(devminor) + } + var prefix string + switch format { + case "posix", "gnu": + prefix = p.parseString(s.next(155)) + case "star": + prefix = p.parseString(s.next(131)) + hdr.AccessTime = time.Unix(p.parseNumeric(s.next(12)), 0) + hdr.ChangeTime = time.Unix(p.parseNumeric(s.next(12)), 0) + } + if len(prefix) > 0 { + hdr.Name = prefix + "/" + hdr.Name + } + } + + if p.err != nil { + tr.err = p.err + return nil + } + + nb := hdr.Size + if isHeaderOnlyType(hdr.Typeflag) { + nb = 0 + } + if nb < 0 { + tr.err = ErrHeader + return nil + } + + // Set the current file reader. + tr.pad = -nb & (blockSize - 1) // blockSize is a power of two + tr.curr = ®FileReader{r: tr.r, nb: nb} + + // Check for old GNU sparse format entry. + if hdr.Typeflag == TypeGNUSparse { + // Get the real size of the file. + hdr.Size = p.parseNumeric(header[483:495]) + if p.err != nil { + tr.err = p.err + return nil + } + + // Read the sparse map. + sp := tr.readOldGNUSparseMap(header) + if tr.err != nil { + return nil + } + + // Current file is a GNU sparse file. Update the current file reader. + tr.curr, tr.err = newSparseFileReader(tr.curr, sp, hdr.Size) + if tr.err != nil { + return nil + } + } + + return hdr +} + +// readOldGNUSparseMap reads the sparse map as stored in the old GNU sparse format. +// The sparse map is stored in the tar header if it's small enough. If it's larger than four entries, +// then one or more extension headers are used to store the rest of the sparse map. +func (tr *Reader) readOldGNUSparseMap(header []byte) []sparseEntry { + var p parser + isExtended := header[oldGNUSparseMainHeaderIsExtendedOffset] != 0 + spCap := oldGNUSparseMainHeaderNumEntries + if isExtended { + spCap += oldGNUSparseExtendedHeaderNumEntries + } + sp := make([]sparseEntry, 0, spCap) + s := slicer(header[oldGNUSparseMainHeaderOffset:]) + + // Read the four entries from the main tar header + for i := 0; i < oldGNUSparseMainHeaderNumEntries; i++ { + offset := p.parseNumeric(s.next(oldGNUSparseOffsetSize)) + numBytes := p.parseNumeric(s.next(oldGNUSparseNumBytesSize)) + if p.err != nil { + tr.err = p.err + return nil + } + if offset == 0 && numBytes == 0 { + break + } + sp = append(sp, sparseEntry{offset: offset, numBytes: numBytes}) + } + + for isExtended { + // There are more entries. Read an extension header and parse its entries. + sparseHeader := make([]byte, blockSize) + if _, tr.err = io.ReadFull(tr.r, sparseHeader); tr.err != nil { + return nil + } + isExtended = sparseHeader[oldGNUSparseExtendedHeaderIsExtendedOffset] != 0 + s = slicer(sparseHeader) + for i := 0; i < oldGNUSparseExtendedHeaderNumEntries; i++ { + offset := p.parseNumeric(s.next(oldGNUSparseOffsetSize)) + numBytes := p.parseNumeric(s.next(oldGNUSparseNumBytesSize)) + if p.err != nil { + tr.err = p.err + return nil + } + if offset == 0 && numBytes == 0 { + break + } + sp = append(sp, sparseEntry{offset: offset, numBytes: numBytes}) + } + } + return sp +} + +// readGNUSparseMap1x0 reads the sparse map as stored in GNU's PAX sparse format +// version 1.0. The format of the sparse map consists of a series of +// newline-terminated numeric fields. The first field is the number of entries +// and is always present. Following this are the entries, consisting of two +// fields (offset, numBytes). This function must stop reading at the end +// boundary of the block containing the last newline. +// +// Note that the GNU manual says that numeric values should be encoded in octal +// format. However, the GNU tar utility itself outputs these values in decimal. +// As such, this library treats values as being encoded in decimal. +func readGNUSparseMap1x0(r io.Reader) ([]sparseEntry, error) { + var cntNewline int64 + var buf bytes.Buffer + var blk = make([]byte, blockSize) + + // feedTokens copies data in numBlock chunks from r into buf until there are + // at least cnt newlines in buf. It will not read more blocks than needed. + var feedTokens = func(cnt int64) error { + for cntNewline < cnt { + if _, err := io.ReadFull(r, blk); err != nil { + if err == io.EOF { + err = io.ErrUnexpectedEOF + } + return err + } + buf.Write(blk) + for _, c := range blk { + if c == '\n' { + cntNewline++ + } + } + } + return nil + } + + // nextToken gets the next token delimited by a newline. This assumes that + // at least one newline exists in the buffer. + var nextToken = func() string { + cntNewline-- + tok, _ := buf.ReadString('\n') + return tok[:len(tok)-1] // Cut off newline + } + + // Parse for the number of entries. + // Use integer overflow resistant math to check this. + if err := feedTokens(1); err != nil { + return nil, err + } + numEntries, err := strconv.ParseInt(nextToken(), 10, 0) // Intentionally parse as native int + if err != nil || numEntries < 0 || int(2*numEntries) < int(numEntries) { + return nil, ErrHeader + } + + // Parse for all member entries. + // numEntries is trusted after this since a potential attacker must have + // committed resources proportional to what this library used. + if err := feedTokens(2 * numEntries); err != nil { + return nil, err + } + sp := make([]sparseEntry, 0, numEntries) + for i := int64(0); i < numEntries; i++ { + offset, err := strconv.ParseInt(nextToken(), 10, 64) + if err != nil { + return nil, ErrHeader + } + numBytes, err := strconv.ParseInt(nextToken(), 10, 64) + if err != nil { + return nil, ErrHeader + } + sp = append(sp, sparseEntry{offset: offset, numBytes: numBytes}) + } + return sp, nil +} + +// readGNUSparseMap0x1 reads the sparse map as stored in GNU's PAX sparse format +// version 0.1. The sparse map is stored in the PAX headers. +func readGNUSparseMap0x1(extHdrs map[string]string) ([]sparseEntry, error) { + // Get number of entries. + // Use integer overflow resistant math to check this. + numEntriesStr := extHdrs[paxGNUSparseNumBlocks] + numEntries, err := strconv.ParseInt(numEntriesStr, 10, 0) // Intentionally parse as native int + if err != nil || numEntries < 0 || int(2*numEntries) < int(numEntries) { + return nil, ErrHeader + } + + // There should be two numbers in sparseMap for each entry. + sparseMap := strings.Split(extHdrs[paxGNUSparseMap], ",") + if int64(len(sparseMap)) != 2*numEntries { + return nil, ErrHeader + } + + // Loop through the entries in the sparse map. + // numEntries is trusted now. + sp := make([]sparseEntry, 0, numEntries) + for i := int64(0); i < numEntries; i++ { + offset, err := strconv.ParseInt(sparseMap[2*i], 10, 64) + if err != nil { + return nil, ErrHeader + } + numBytes, err := strconv.ParseInt(sparseMap[2*i+1], 10, 64) + if err != nil { + return nil, ErrHeader + } + sp = append(sp, sparseEntry{offset: offset, numBytes: numBytes}) + } + return sp, nil +} + +// numBytes returns the number of bytes left to read in the current file's entry +// in the tar archive, or 0 if there is no current file. +func (tr *Reader) numBytes() int64 { + if tr.curr == nil { + // No current file, so no bytes + return 0 + } + return tr.curr.numBytes() +} + +// Read reads from the current entry in the tar archive. +// It returns 0, io.EOF when it reaches the end of that entry, +// until Next is called to advance to the next entry. +// +// Calling Read on special types like TypeLink, TypeSymLink, TypeChar, +// TypeBlock, TypeDir, and TypeFifo returns 0, io.EOF regardless of what +// the Header.Size claims. +func (tr *Reader) Read(b []byte) (n int, err error) { + if tr.err != nil { + return 0, tr.err + } + if tr.curr == nil { + return 0, io.EOF + } + + n, err = tr.curr.Read(b) + if err != nil && err != io.EOF { + tr.err = err + } + return +} + +func (rfr *regFileReader) Read(b []byte) (n int, err error) { + if rfr.nb == 0 { + // file consumed + return 0, io.EOF + } + if int64(len(b)) > rfr.nb { + b = b[0:rfr.nb] + } + n, err = rfr.r.Read(b) + rfr.nb -= int64(n) + + if err == io.EOF && rfr.nb > 0 { + err = io.ErrUnexpectedEOF + } + return +} + +// numBytes returns the number of bytes left to read in the file's data in the tar archive. +func (rfr *regFileReader) numBytes() int64 { + return rfr.nb +} + +// newSparseFileReader creates a new sparseFileReader, but validates all of the +// sparse entries before doing so. +func newSparseFileReader(rfr numBytesReader, sp []sparseEntry, total int64) (*sparseFileReader, error) { + if total < 0 { + return nil, ErrHeader // Total size cannot be negative + } + + // Validate all sparse entries. These are the same checks as performed by + // the BSD tar utility. + for i, s := range sp { + switch { + case s.offset < 0 || s.numBytes < 0: + return nil, ErrHeader // Negative values are never okay + case s.offset > math.MaxInt64-s.numBytes: + return nil, ErrHeader // Integer overflow with large length + case s.offset+s.numBytes > total: + return nil, ErrHeader // Region extends beyond the "real" size + case i > 0 && sp[i-1].offset+sp[i-1].numBytes > s.offset: + return nil, ErrHeader // Regions can't overlap and must be in order + } + } + return &sparseFileReader{rfr: rfr, sp: sp, total: total}, nil +} + +// readHole reads a sparse hole ending at endOffset. +func (sfr *sparseFileReader) readHole(b []byte, endOffset int64) int { + n64 := endOffset - sfr.pos + if n64 > int64(len(b)) { + n64 = int64(len(b)) + } + n := int(n64) + for i := 0; i < n; i++ { + b[i] = 0 + } + sfr.pos += n64 + return n +} + +// Read reads the sparse file data in expanded form. +func (sfr *sparseFileReader) Read(b []byte) (n int, err error) { + // Skip past all empty fragments. + for len(sfr.sp) > 0 && sfr.sp[0].numBytes == 0 { + sfr.sp = sfr.sp[1:] + } + + // If there are no more fragments, then it is possible that there + // is one last sparse hole. + if len(sfr.sp) == 0 { + // This behavior matches the BSD tar utility. + // However, GNU tar stops returning data even if sfr.total is unmet. + if sfr.pos < sfr.total { + return sfr.readHole(b, sfr.total), nil + } + return 0, io.EOF + } + + // In front of a data fragment, so read a hole. + if sfr.pos < sfr.sp[0].offset { + return sfr.readHole(b, sfr.sp[0].offset), nil + } + + // In a data fragment, so read from it. + // This math is overflow free since we verify that offset and numBytes can + // be safely added when creating the sparseFileReader. + endPos := sfr.sp[0].offset + sfr.sp[0].numBytes // End offset of fragment + bytesLeft := endPos - sfr.pos // Bytes left in fragment + if int64(len(b)) > bytesLeft { + b = b[:bytesLeft] + } + + n, err = sfr.rfr.Read(b) + sfr.pos += int64(n) + if err == io.EOF { + if sfr.pos < endPos { + err = io.ErrUnexpectedEOF // There was supposed to be more data + } else if sfr.pos < sfr.total { + err = nil // There is still an implicit sparse hole at the end + } + } + + if sfr.pos == endPos { + sfr.sp = sfr.sp[1:] // We are done with this fragment, so pop it + } + return n, err +} + +// numBytes returns the number of bytes left to read in the sparse file's +// sparse-encoded data in the tar archive. +func (sfr *sparseFileReader) numBytes() int64 { + return sfr.rfr.numBytes() +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/archive/tar/stat_atim.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/archive/tar/stat_atim.go new file mode 100644 index 0000000000..cf9cc79c59 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/archive/tar/stat_atim.go @@ -0,0 +1,20 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build linux dragonfly openbsd solaris + +package tar + +import ( + "syscall" + "time" +) + +func statAtime(st *syscall.Stat_t) time.Time { + return time.Unix(st.Atim.Unix()) +} + +func statCtime(st *syscall.Stat_t) time.Time { + return time.Unix(st.Ctim.Unix()) +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/archive/tar/stat_atimespec.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/archive/tar/stat_atimespec.go new file mode 100644 index 0000000000..6f17dbe307 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/archive/tar/stat_atimespec.go @@ -0,0 +1,20 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin freebsd netbsd + +package tar + +import ( + "syscall" + "time" +) + +func statAtime(st *syscall.Stat_t) time.Time { + return time.Unix(st.Atimespec.Unix()) +} + +func statCtime(st *syscall.Stat_t) time.Time { + return time.Unix(st.Ctimespec.Unix()) +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/archive/tar/stat_unix.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/archive/tar/stat_unix.go new file mode 100644 index 0000000000..cb843db4cf --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/archive/tar/stat_unix.go @@ -0,0 +1,32 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build linux darwin dragonfly freebsd openbsd netbsd solaris + +package tar + +import ( + "os" + "syscall" +) + +func init() { + sysStat = statUnix +} + +func statUnix(fi os.FileInfo, h *Header) error { + sys, ok := fi.Sys().(*syscall.Stat_t) + if !ok { + return nil + } + h.Uid = int(sys.Uid) + h.Gid = int(sys.Gid) + // TODO(bradfitz): populate username & group. os/user + // doesn't cache LookupId lookups, and lacks group + // lookup functions. + h.AccessTime = statAtime(sys) + h.ChangeTime = statCtime(sys) + // TODO(bradfitz): major/minor device numbers? + return nil +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/archive/tar/writer.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/archive/tar/writer.go new file mode 100644 index 0000000000..30d7e606d6 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/archive/tar/writer.go @@ -0,0 +1,444 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package tar + +// TODO(dsymonds): +// - catch more errors (no first header, etc.) + +import ( + "bytes" + "errors" + "fmt" + "io" + "path" + "sort" + "strconv" + "strings" + "time" +) + +var ( + ErrWriteTooLong = errors.New("archive/tar: write too long") + ErrFieldTooLong = errors.New("archive/tar: header field too long") + ErrWriteAfterClose = errors.New("archive/tar: write after close") + errInvalidHeader = errors.New("archive/tar: header field too long or contains invalid values") +) + +// A Writer provides sequential writing of a tar archive in POSIX.1 format. +// A tar archive consists of a sequence of files. +// Call WriteHeader to begin a new file, and then call Write to supply that file's data, +// writing at most hdr.Size bytes in total. +type Writer struct { + w io.Writer + err error + nb int64 // number of unwritten bytes for current file entry + pad int64 // amount of padding to write after current file entry + closed bool + usedBinary bool // whether the binary numeric field extension was used + preferPax bool // use pax header instead of binary numeric header + hdrBuff [blockSize]byte // buffer to use in writeHeader when writing a regular header + paxHdrBuff [blockSize]byte // buffer to use in writeHeader when writing a pax header +} + +type formatter struct { + err error // Last error seen +} + +// NewWriter creates a new Writer writing to w. +func NewWriter(w io.Writer) *Writer { return &Writer{w: w, preferPax: true} } + +// Flush finishes writing the current file (optional). +func (tw *Writer) Flush() error { + if tw.nb > 0 { + tw.err = fmt.Errorf("archive/tar: missed writing %d bytes", tw.nb) + return tw.err + } + + n := tw.nb + tw.pad + for n > 0 && tw.err == nil { + nr := n + if nr > blockSize { + nr = blockSize + } + var nw int + nw, tw.err = tw.w.Write(zeroBlock[0:nr]) + n -= int64(nw) + } + tw.nb = 0 + tw.pad = 0 + return tw.err +} + +// Write s into b, terminating it with a NUL if there is room. +func (f *formatter) formatString(b []byte, s string) { + if len(s) > len(b) { + f.err = ErrFieldTooLong + return + } + ascii := toASCII(s) + copy(b, ascii) + if len(ascii) < len(b) { + b[len(ascii)] = 0 + } +} + +// Encode x as an octal ASCII string and write it into b with leading zeros. +func (f *formatter) formatOctal(b []byte, x int64) { + s := strconv.FormatInt(x, 8) + // leading zeros, but leave room for a NUL. + for len(s)+1 < len(b) { + s = "0" + s + } + f.formatString(b, s) +} + +// fitsInBase256 reports whether x can be encoded into n bytes using base-256 +// encoding. Unlike octal encoding, base-256 encoding does not require that the +// string ends with a NUL character. Thus, all n bytes are available for output. +// +// If operating in binary mode, this assumes strict GNU binary mode; which means +// that the first byte can only be either 0x80 or 0xff. Thus, the first byte is +// equivalent to the sign bit in two's complement form. +func fitsInBase256(n int, x int64) bool { + var binBits = uint(n-1) * 8 + return n >= 9 || (x >= -1<= 0; i-- { + b[i] = byte(x) + x >>= 8 + } + b[0] |= 0x80 // Highest bit indicates binary format + return + } + + f.formatOctal(b, 0) // Last resort, just write zero + f.err = ErrFieldTooLong +} + +var ( + minTime = time.Unix(0, 0) + // There is room for 11 octal digits (33 bits) of mtime. + maxTime = minTime.Add((1<<33 - 1) * time.Second) +) + +// WriteHeader writes hdr and prepares to accept the file's contents. +// WriteHeader calls Flush if it is not the first header. +// Calling after a Close will return ErrWriteAfterClose. +func (tw *Writer) WriteHeader(hdr *Header) error { + return tw.writeHeader(hdr, true) +} + +// WriteHeader writes hdr and prepares to accept the file's contents. +// WriteHeader calls Flush if it is not the first header. +// Calling after a Close will return ErrWriteAfterClose. +// As this method is called internally by writePax header to allow it to +// suppress writing the pax header. +func (tw *Writer) writeHeader(hdr *Header, allowPax bool) error { + if tw.closed { + return ErrWriteAfterClose + } + if tw.err == nil { + tw.Flush() + } + if tw.err != nil { + return tw.err + } + + // a map to hold pax header records, if any are needed + paxHeaders := make(map[string]string) + + // TODO(shanemhansen): we might want to use PAX headers for + // subsecond time resolution, but for now let's just capture + // too long fields or non ascii characters + + var f formatter + var header []byte + + // We need to select which scratch buffer to use carefully, + // since this method is called recursively to write PAX headers. + // If allowPax is true, this is the non-recursive call, and we will use hdrBuff. + // If allowPax is false, we are being called by writePAXHeader, and hdrBuff is + // already being used by the non-recursive call, so we must use paxHdrBuff. + header = tw.hdrBuff[:] + if !allowPax { + header = tw.paxHdrBuff[:] + } + copy(header, zeroBlock) + s := slicer(header) + + // Wrappers around formatter that automatically sets paxHeaders if the + // argument extends beyond the capacity of the input byte slice. + var formatString = func(b []byte, s string, paxKeyword string) { + needsPaxHeader := paxKeyword != paxNone && len(s) > len(b) || !isASCII(s) + if needsPaxHeader { + paxHeaders[paxKeyword] = s + return + } + f.formatString(b, s) + } + var formatNumeric = func(b []byte, x int64, paxKeyword string) { + // Try octal first. + s := strconv.FormatInt(x, 8) + if len(s) < len(b) { + f.formatOctal(b, x) + return + } + + // If it is too long for octal, and PAX is preferred, use a PAX header. + if paxKeyword != paxNone && tw.preferPax { + f.formatOctal(b, 0) + s := strconv.FormatInt(x, 10) + paxHeaders[paxKeyword] = s + return + } + + tw.usedBinary = true + f.formatNumeric(b, x) + } + var formatTime = func(b []byte, t time.Time, paxKeyword string) { + var unixTime int64 + if !t.Before(minTime) && !t.After(maxTime) { + unixTime = t.Unix() + } + formatNumeric(b, unixTime, paxNone) + + // Write a PAX header if the time didn't fit precisely. + if paxKeyword != "" && tw.preferPax && allowPax && (t.Nanosecond() != 0 || !t.Before(minTime) || !t.After(maxTime)) { + paxHeaders[paxKeyword] = formatPAXTime(t) + } + } + + // keep a reference to the filename to allow to overwrite it later if we detect that we can use ustar longnames instead of pax + pathHeaderBytes := s.next(fileNameSize) + + formatString(pathHeaderBytes, hdr.Name, paxPath) + + f.formatOctal(s.next(8), hdr.Mode) // 100:108 + formatNumeric(s.next(8), int64(hdr.Uid), paxUid) // 108:116 + formatNumeric(s.next(8), int64(hdr.Gid), paxGid) // 116:124 + formatNumeric(s.next(12), hdr.Size, paxSize) // 124:136 + formatTime(s.next(12), hdr.ModTime, paxMtime) // 136:148 + s.next(8) // chksum (148:156) + s.next(1)[0] = hdr.Typeflag // 156:157 + + formatString(s.next(100), hdr.Linkname, paxLinkpath) + + copy(s.next(8), []byte("ustar\x0000")) // 257:265 + formatString(s.next(32), hdr.Uname, paxUname) // 265:297 + formatString(s.next(32), hdr.Gname, paxGname) // 297:329 + formatNumeric(s.next(8), hdr.Devmajor, paxNone) // 329:337 + formatNumeric(s.next(8), hdr.Devminor, paxNone) // 337:345 + + // keep a reference to the prefix to allow to overwrite it later if we detect that we can use ustar longnames instead of pax + prefixHeaderBytes := s.next(155) + formatString(prefixHeaderBytes, "", paxNone) // 345:500 prefix + + // Use the GNU magic instead of POSIX magic if we used any GNU extensions. + if tw.usedBinary { + copy(header[257:265], []byte("ustar \x00")) + } + + _, paxPathUsed := paxHeaders[paxPath] + // try to use a ustar header when only the name is too long + if !tw.preferPax && len(paxHeaders) == 1 && paxPathUsed { + prefix, suffix, ok := splitUSTARPath(hdr.Name) + if ok { + // Since we can encode in USTAR format, disable PAX header. + delete(paxHeaders, paxPath) + + // Update the path fields + formatString(pathHeaderBytes, suffix, paxNone) + formatString(prefixHeaderBytes, prefix, paxNone) + } + } + + // The chksum field is terminated by a NUL and a space. + // This is different from the other octal fields. + chksum, _ := checksum(header) + f.formatOctal(header[148:155], chksum) // Never fails + header[155] = ' ' + + // Check if there were any formatting errors. + if f.err != nil { + tw.err = f.err + return tw.err + } + + if allowPax { + if !hdr.AccessTime.IsZero() { + paxHeaders[paxAtime] = formatPAXTime(hdr.AccessTime) + } + if !hdr.ChangeTime.IsZero() { + paxHeaders[paxCtime] = formatPAXTime(hdr.ChangeTime) + } + if !hdr.CreationTime.IsZero() { + paxHeaders[paxCreationTime] = formatPAXTime(hdr.CreationTime) + } + for k, v := range hdr.Xattrs { + paxHeaders[paxXattr+k] = v + } + for k, v := range hdr.Winheaders { + paxHeaders[paxWindows+k] = v + } + } + + if len(paxHeaders) > 0 { + if !allowPax { + return errInvalidHeader + } + if err := tw.writePAXHeader(hdr, paxHeaders); err != nil { + return err + } + } + tw.nb = int64(hdr.Size) + tw.pad = (blockSize - (tw.nb % blockSize)) % blockSize + + _, tw.err = tw.w.Write(header) + return tw.err +} + +func formatPAXTime(t time.Time) string { + sec := t.Unix() + usec := t.Nanosecond() + s := strconv.FormatInt(sec, 10) + if usec != 0 { + s = fmt.Sprintf("%s.%09d", s, usec) + } + return s +} + +// splitUSTARPath splits a path according to USTAR prefix and suffix rules. +// If the path is not splittable, then it will return ("", "", false). +func splitUSTARPath(name string) (prefix, suffix string, ok bool) { + length := len(name) + if length <= fileNameSize || !isASCII(name) { + return "", "", false + } else if length > fileNamePrefixSize+1 { + length = fileNamePrefixSize + 1 + } else if name[length-1] == '/' { + length-- + } + + i := strings.LastIndex(name[:length], "/") + nlen := len(name) - i - 1 // nlen is length of suffix + plen := i // plen is length of prefix + if i <= 0 || nlen > fileNameSize || nlen == 0 || plen > fileNamePrefixSize { + return "", "", false + } + return name[:i], name[i+1:], true +} + +// writePaxHeader writes an extended pax header to the +// archive. +func (tw *Writer) writePAXHeader(hdr *Header, paxHeaders map[string]string) error { + // Prepare extended header + ext := new(Header) + ext.Typeflag = TypeXHeader + // Setting ModTime is required for reader parsing to + // succeed, and seems harmless enough. + ext.ModTime = hdr.ModTime + // The spec asks that we namespace our pseudo files + // with the current pid. However, this results in differing outputs + // for identical inputs. As such, the constant 0 is now used instead. + // golang.org/issue/12358 + dir, file := path.Split(hdr.Name) + fullName := path.Join(dir, "PaxHeaders.0", file) + + ascii := toASCII(fullName) + if len(ascii) > 100 { + ascii = ascii[:100] + } + ext.Name = ascii + // Construct the body + var buf bytes.Buffer + + // Keys are sorted before writing to body to allow deterministic output. + var keys []string + for k := range paxHeaders { + keys = append(keys, k) + } + sort.Strings(keys) + + for _, k := range keys { + fmt.Fprint(&buf, formatPAXRecord(k, paxHeaders[k])) + } + + ext.Size = int64(len(buf.Bytes())) + if err := tw.writeHeader(ext, false); err != nil { + return err + } + if _, err := tw.Write(buf.Bytes()); err != nil { + return err + } + if err := tw.Flush(); err != nil { + return err + } + return nil +} + +// formatPAXRecord formats a single PAX record, prefixing it with the +// appropriate length. +func formatPAXRecord(k, v string) string { + const padding = 3 // Extra padding for ' ', '=', and '\n' + size := len(k) + len(v) + padding + size += len(strconv.Itoa(size)) + record := fmt.Sprintf("%d %s=%s\n", size, k, v) + + // Final adjustment if adding size field increased the record size. + if len(record) != size { + size = len(record) + record = fmt.Sprintf("%d %s=%s\n", size, k, v) + } + return record +} + +// Write writes to the current entry in the tar archive. +// Write returns the error ErrWriteTooLong if more than +// hdr.Size bytes are written after WriteHeader. +func (tw *Writer) Write(b []byte) (n int, err error) { + if tw.closed { + err = ErrWriteAfterClose + return + } + overwrite := false + if int64(len(b)) > tw.nb { + b = b[0:tw.nb] + overwrite = true + } + n, err = tw.w.Write(b) + tw.nb -= int64(n) + if err == nil && overwrite { + err = ErrWriteTooLong + return + } + tw.err = err + return +} + +// Close closes the tar archive, flushing any unwritten +// data to the underlying writer. +func (tw *Writer) Close() error { + if tw.err != nil || tw.closed { + return tw.err + } + tw.Flush() + tw.closed = true + if tw.err != nil { + return tw.err + } + + // trailer: two zero blocks + for i := 0; i < 2; i++ { + _, tw.err = tw.w.Write(zeroBlock) + if tw.err != nil { + break + } + } + return tw.err +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/backup.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/backup.go new file mode 100644 index 0000000000..2be34af431 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/backup.go @@ -0,0 +1,280 @@ +// +build windows + +package winio + +import ( + "encoding/binary" + "errors" + "fmt" + "io" + "io/ioutil" + "os" + "runtime" + "syscall" + "unicode/utf16" +) + +//sys backupRead(h syscall.Handle, b []byte, bytesRead *uint32, abort bool, processSecurity bool, context *uintptr) (err error) = BackupRead +//sys backupWrite(h syscall.Handle, b []byte, bytesWritten *uint32, abort bool, processSecurity bool, context *uintptr) (err error) = BackupWrite + +const ( + BackupData = uint32(iota + 1) + BackupEaData + BackupSecurity + BackupAlternateData + BackupLink + BackupPropertyData + BackupObjectId + BackupReparseData + BackupSparseBlock + BackupTxfsData +) + +const ( + StreamSparseAttributes = uint32(8) +) + +const ( + WRITE_DAC = 0x40000 + WRITE_OWNER = 0x80000 + ACCESS_SYSTEM_SECURITY = 0x1000000 +) + +// BackupHeader represents a backup stream of a file. +type BackupHeader struct { + Id uint32 // The backup stream ID + Attributes uint32 // Stream attributes + Size int64 // The size of the stream in bytes + Name string // The name of the stream (for BackupAlternateData only). + Offset int64 // The offset of the stream in the file (for BackupSparseBlock only). +} + +type win32StreamId struct { + StreamId uint32 + Attributes uint32 + Size uint64 + NameSize uint32 +} + +// BackupStreamReader reads from a stream produced by the BackupRead Win32 API and produces a series +// of BackupHeader values. +type BackupStreamReader struct { + r io.Reader + bytesLeft int64 +} + +// NewBackupStreamReader produces a BackupStreamReader from any io.Reader. +func NewBackupStreamReader(r io.Reader) *BackupStreamReader { + return &BackupStreamReader{r, 0} +} + +// Next returns the next backup stream and prepares for calls to Read(). It skips the remainder of the current stream if +// it was not completely read. +func (r *BackupStreamReader) Next() (*BackupHeader, error) { + if r.bytesLeft > 0 { + if s, ok := r.r.(io.Seeker); ok { + // Make sure Seek on io.SeekCurrent sometimes succeeds + // before trying the actual seek. + if _, err := s.Seek(0, io.SeekCurrent); err == nil { + if _, err = s.Seek(r.bytesLeft, io.SeekCurrent); err != nil { + return nil, err + } + r.bytesLeft = 0 + } + } + if _, err := io.Copy(ioutil.Discard, r); err != nil { + return nil, err + } + } + var wsi win32StreamId + if err := binary.Read(r.r, binary.LittleEndian, &wsi); err != nil { + return nil, err + } + hdr := &BackupHeader{ + Id: wsi.StreamId, + Attributes: wsi.Attributes, + Size: int64(wsi.Size), + } + if wsi.NameSize != 0 { + name := make([]uint16, int(wsi.NameSize/2)) + if err := binary.Read(r.r, binary.LittleEndian, name); err != nil { + return nil, err + } + hdr.Name = syscall.UTF16ToString(name) + } + if wsi.StreamId == BackupSparseBlock { + if err := binary.Read(r.r, binary.LittleEndian, &hdr.Offset); err != nil { + return nil, err + } + hdr.Size -= 8 + } + r.bytesLeft = hdr.Size + return hdr, nil +} + +// Read reads from the current backup stream. +func (r *BackupStreamReader) Read(b []byte) (int, error) { + if r.bytesLeft == 0 { + return 0, io.EOF + } + if int64(len(b)) > r.bytesLeft { + b = b[:r.bytesLeft] + } + n, err := r.r.Read(b) + r.bytesLeft -= int64(n) + if err == io.EOF { + err = io.ErrUnexpectedEOF + } else if r.bytesLeft == 0 && err == nil { + err = io.EOF + } + return n, err +} + +// BackupStreamWriter writes a stream compatible with the BackupWrite Win32 API. +type BackupStreamWriter struct { + w io.Writer + bytesLeft int64 +} + +// NewBackupStreamWriter produces a BackupStreamWriter on top of an io.Writer. +func NewBackupStreamWriter(w io.Writer) *BackupStreamWriter { + return &BackupStreamWriter{w, 0} +} + +// WriteHeader writes the next backup stream header and prepares for calls to Write(). +func (w *BackupStreamWriter) WriteHeader(hdr *BackupHeader) error { + if w.bytesLeft != 0 { + return fmt.Errorf("missing %d bytes", w.bytesLeft) + } + name := utf16.Encode([]rune(hdr.Name)) + wsi := win32StreamId{ + StreamId: hdr.Id, + Attributes: hdr.Attributes, + Size: uint64(hdr.Size), + NameSize: uint32(len(name) * 2), + } + if hdr.Id == BackupSparseBlock { + // Include space for the int64 block offset + wsi.Size += 8 + } + if err := binary.Write(w.w, binary.LittleEndian, &wsi); err != nil { + return err + } + if len(name) != 0 { + if err := binary.Write(w.w, binary.LittleEndian, name); err != nil { + return err + } + } + if hdr.Id == BackupSparseBlock { + if err := binary.Write(w.w, binary.LittleEndian, hdr.Offset); err != nil { + return err + } + } + w.bytesLeft = hdr.Size + return nil +} + +// Write writes to the current backup stream. +func (w *BackupStreamWriter) Write(b []byte) (int, error) { + if w.bytesLeft < int64(len(b)) { + return 0, fmt.Errorf("too many bytes by %d", int64(len(b))-w.bytesLeft) + } + n, err := w.w.Write(b) + w.bytesLeft -= int64(n) + return n, err +} + +// BackupFileReader provides an io.ReadCloser interface on top of the BackupRead Win32 API. +type BackupFileReader struct { + f *os.File + includeSecurity bool + ctx uintptr +} + +// NewBackupFileReader returns a new BackupFileReader from a file handle. If includeSecurity is true, +// Read will attempt to read the security descriptor of the file. +func NewBackupFileReader(f *os.File, includeSecurity bool) *BackupFileReader { + r := &BackupFileReader{f, includeSecurity, 0} + return r +} + +// Read reads a backup stream from the file by calling the Win32 API BackupRead(). +func (r *BackupFileReader) Read(b []byte) (int, error) { + var bytesRead uint32 + err := backupRead(syscall.Handle(r.f.Fd()), b, &bytesRead, false, r.includeSecurity, &r.ctx) + if err != nil { + return 0, &os.PathError{"BackupRead", r.f.Name(), err} + } + runtime.KeepAlive(r.f) + if bytesRead == 0 { + return 0, io.EOF + } + return int(bytesRead), nil +} + +// Close frees Win32 resources associated with the BackupFileReader. It does not close +// the underlying file. +func (r *BackupFileReader) Close() error { + if r.ctx != 0 { + backupRead(syscall.Handle(r.f.Fd()), nil, nil, true, false, &r.ctx) + runtime.KeepAlive(r.f) + r.ctx = 0 + } + return nil +} + +// BackupFileWriter provides an io.WriteCloser interface on top of the BackupWrite Win32 API. +type BackupFileWriter struct { + f *os.File + includeSecurity bool + ctx uintptr +} + +// NewBackupFileWriter returns a new BackupFileWriter from a file handle. If includeSecurity is true, +// Write() will attempt to restore the security descriptor from the stream. +func NewBackupFileWriter(f *os.File, includeSecurity bool) *BackupFileWriter { + w := &BackupFileWriter{f, includeSecurity, 0} + return w +} + +// Write restores a portion of the file using the provided backup stream. +func (w *BackupFileWriter) Write(b []byte) (int, error) { + var bytesWritten uint32 + err := backupWrite(syscall.Handle(w.f.Fd()), b, &bytesWritten, false, w.includeSecurity, &w.ctx) + if err != nil { + return 0, &os.PathError{"BackupWrite", w.f.Name(), err} + } + runtime.KeepAlive(w.f) + if int(bytesWritten) != len(b) { + return int(bytesWritten), errors.New("not all bytes could be written") + } + return len(b), nil +} + +// Close frees Win32 resources associated with the BackupFileWriter. It does not +// close the underlying file. +func (w *BackupFileWriter) Close() error { + if w.ctx != 0 { + backupWrite(syscall.Handle(w.f.Fd()), nil, nil, true, false, &w.ctx) + runtime.KeepAlive(w.f) + w.ctx = 0 + } + return nil +} + +// OpenForBackup opens a file or directory, potentially skipping access checks if the backup +// or restore privileges have been acquired. +// +// If the file opened was a directory, it cannot be used with Readdir(). +func OpenForBackup(path string, access uint32, share uint32, createmode uint32) (*os.File, error) { + winPath, err := syscall.UTF16FromString(path) + if err != nil { + return nil, err + } + h, err := syscall.CreateFile(&winPath[0], access, share, nil, createmode, syscall.FILE_FLAG_BACKUP_SEMANTICS|syscall.FILE_FLAG_OPEN_REPARSE_POINT, 0) + if err != nil { + err = &os.PathError{Op: "open", Path: path, Err: err} + return nil, err + } + return os.NewFile(uintptr(h), path), nil +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/backuptar/noop.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/backuptar/noop.go new file mode 100644 index 0000000000..d39eccf023 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/backuptar/noop.go @@ -0,0 +1,4 @@ +// +build !windows +// This file only exists to allow go get on non-Windows platforms. + +package backuptar diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/backuptar/tar.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/backuptar/tar.go new file mode 100644 index 0000000000..d6566dbf0c --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/backuptar/tar.go @@ -0,0 +1,439 @@ +// +build windows + +package backuptar + +import ( + "encoding/base64" + "errors" + "fmt" + "io" + "io/ioutil" + "path/filepath" + "strconv" + "strings" + "syscall" + "time" + + "github.com/Microsoft/go-winio" + "github.com/Microsoft/go-winio/archive/tar" // until archive/tar supports pax extensions in its interface +) + +const ( + c_ISUID = 04000 // Set uid + c_ISGID = 02000 // Set gid + c_ISVTX = 01000 // Save text (sticky bit) + c_ISDIR = 040000 // Directory + c_ISFIFO = 010000 // FIFO + c_ISREG = 0100000 // Regular file + c_ISLNK = 0120000 // Symbolic link + c_ISBLK = 060000 // Block special file + c_ISCHR = 020000 // Character special file + c_ISSOCK = 0140000 // Socket +) + +const ( + hdrFileAttributes = "fileattr" + hdrSecurityDescriptor = "sd" + hdrRawSecurityDescriptor = "rawsd" + hdrMountPoint = "mountpoint" + hdrEaPrefix = "xattr." +) + +func writeZeroes(w io.Writer, count int64) error { + buf := make([]byte, 8192) + c := len(buf) + for i := int64(0); i < count; i += int64(c) { + if int64(c) > count-i { + c = int(count - i) + } + _, err := w.Write(buf[:c]) + if err != nil { + return err + } + } + return nil +} + +func copySparse(t *tar.Writer, br *winio.BackupStreamReader) error { + curOffset := int64(0) + for { + bhdr, err := br.Next() + if err == io.EOF { + err = io.ErrUnexpectedEOF + } + if err != nil { + return err + } + if bhdr.Id != winio.BackupSparseBlock { + return fmt.Errorf("unexpected stream %d", bhdr.Id) + } + + // archive/tar does not support writing sparse files + // so just write zeroes to catch up to the current offset. + err = writeZeroes(t, bhdr.Offset-curOffset) + if bhdr.Size == 0 { + break + } + n, err := io.Copy(t, br) + if err != nil { + return err + } + curOffset = bhdr.Offset + n + } + return nil +} + +// BasicInfoHeader creates a tar header from basic file information. +func BasicInfoHeader(name string, size int64, fileInfo *winio.FileBasicInfo) *tar.Header { + hdr := &tar.Header{ + Name: filepath.ToSlash(name), + Size: size, + Typeflag: tar.TypeReg, + ModTime: time.Unix(0, fileInfo.LastWriteTime.Nanoseconds()), + ChangeTime: time.Unix(0, fileInfo.ChangeTime.Nanoseconds()), + AccessTime: time.Unix(0, fileInfo.LastAccessTime.Nanoseconds()), + CreationTime: time.Unix(0, fileInfo.CreationTime.Nanoseconds()), + Winheaders: make(map[string]string), + } + hdr.Winheaders[hdrFileAttributes] = fmt.Sprintf("%d", fileInfo.FileAttributes) + + if (fileInfo.FileAttributes & syscall.FILE_ATTRIBUTE_DIRECTORY) != 0 { + hdr.Mode |= c_ISDIR + hdr.Size = 0 + hdr.Typeflag = tar.TypeDir + } + return hdr +} + +// WriteTarFileFromBackupStream writes a file to a tar writer using data from a Win32 backup stream. +// +// This encodes Win32 metadata as tar pax vendor extensions starting with MSWINDOWS. +// +// The additional Win32 metadata is: +// +// MSWINDOWS.fileattr: The Win32 file attributes, as a decimal value +// +// MSWINDOWS.rawsd: The Win32 security descriptor, in raw binary format +// +// MSWINDOWS.mountpoint: If present, this is a mount point and not a symlink, even though the type is '2' (symlink) +func WriteTarFileFromBackupStream(t *tar.Writer, r io.Reader, name string, size int64, fileInfo *winio.FileBasicInfo) error { + name = filepath.ToSlash(name) + hdr := BasicInfoHeader(name, size, fileInfo) + + // If r can be seeked, then this function is two-pass: pass 1 collects the + // tar header data, and pass 2 copies the data stream. If r cannot be + // seeked, then some header data (in particular EAs) will be silently lost. + var ( + restartPos int64 + err error + ) + sr, readTwice := r.(io.Seeker) + if readTwice { + if restartPos, err = sr.Seek(0, io.SeekCurrent); err != nil { + readTwice = false + } + } + + br := winio.NewBackupStreamReader(r) + var dataHdr *winio.BackupHeader + for dataHdr == nil { + bhdr, err := br.Next() + if err == io.EOF { + break + } + if err != nil { + return err + } + switch bhdr.Id { + case winio.BackupData: + hdr.Mode |= c_ISREG + if !readTwice { + dataHdr = bhdr + } + case winio.BackupSecurity: + sd, err := ioutil.ReadAll(br) + if err != nil { + return err + } + hdr.Winheaders[hdrRawSecurityDescriptor] = base64.StdEncoding.EncodeToString(sd) + + case winio.BackupReparseData: + hdr.Mode |= c_ISLNK + hdr.Typeflag = tar.TypeSymlink + reparseBuffer, err := ioutil.ReadAll(br) + rp, err := winio.DecodeReparsePoint(reparseBuffer) + if err != nil { + return err + } + if rp.IsMountPoint { + hdr.Winheaders[hdrMountPoint] = "1" + } + hdr.Linkname = rp.Target + + case winio.BackupEaData: + eab, err := ioutil.ReadAll(br) + if err != nil { + return err + } + eas, err := winio.DecodeExtendedAttributes(eab) + if err != nil { + return err + } + for _, ea := range eas { + // Use base64 encoding for the binary value. Note that there + // is no way to encode the EA's flags, since their use doesn't + // make any sense for persisted EAs. + hdr.Winheaders[hdrEaPrefix+ea.Name] = base64.StdEncoding.EncodeToString(ea.Value) + } + + case winio.BackupAlternateData, winio.BackupLink, winio.BackupPropertyData, winio.BackupObjectId, winio.BackupTxfsData: + // ignore these streams + default: + return fmt.Errorf("%s: unknown stream ID %d", name, bhdr.Id) + } + } + + err = t.WriteHeader(hdr) + if err != nil { + return err + } + + if readTwice { + // Get back to the data stream. + if _, err = sr.Seek(restartPos, io.SeekStart); err != nil { + return err + } + for dataHdr == nil { + bhdr, err := br.Next() + if err == io.EOF { + break + } + if err != nil { + return err + } + if bhdr.Id == winio.BackupData { + dataHdr = bhdr + } + } + } + + if dataHdr != nil { + // A data stream was found. Copy the data. + if (dataHdr.Attributes & winio.StreamSparseAttributes) == 0 { + if size != dataHdr.Size { + return fmt.Errorf("%s: mismatch between file size %d and header size %d", name, size, dataHdr.Size) + } + _, err = io.Copy(t, br) + if err != nil { + return err + } + } else { + err = copySparse(t, br) + if err != nil { + return err + } + } + } + + // Look for streams after the data stream. The only ones we handle are alternate data streams. + // Other streams may have metadata that could be serialized, but the tar header has already + // been written. In practice, this means that we don't get EA or TXF metadata. + for { + bhdr, err := br.Next() + if err == io.EOF { + break + } + if err != nil { + return err + } + switch bhdr.Id { + case winio.BackupAlternateData: + altName := bhdr.Name + if strings.HasSuffix(altName, ":$DATA") { + altName = altName[:len(altName)-len(":$DATA")] + } + if (bhdr.Attributes & winio.StreamSparseAttributes) == 0 { + hdr = &tar.Header{ + Name: name + altName, + Mode: hdr.Mode, + Typeflag: tar.TypeReg, + Size: bhdr.Size, + ModTime: hdr.ModTime, + AccessTime: hdr.AccessTime, + ChangeTime: hdr.ChangeTime, + } + err = t.WriteHeader(hdr) + if err != nil { + return err + } + _, err = io.Copy(t, br) + if err != nil { + return err + } + + } else { + // Unsupported for now, since the size of the alternate stream is not present + // in the backup stream until after the data has been read. + return errors.New("tar of sparse alternate data streams is unsupported") + } + case winio.BackupEaData, winio.BackupLink, winio.BackupPropertyData, winio.BackupObjectId, winio.BackupTxfsData: + // ignore these streams + default: + return fmt.Errorf("%s: unknown stream ID %d after data", name, bhdr.Id) + } + } + return nil +} + +// FileInfoFromHeader retrieves basic Win32 file information from a tar header, using the additional metadata written by +// WriteTarFileFromBackupStream. +func FileInfoFromHeader(hdr *tar.Header) (name string, size int64, fileInfo *winio.FileBasicInfo, err error) { + name = hdr.Name + if hdr.Typeflag == tar.TypeReg || hdr.Typeflag == tar.TypeRegA { + size = hdr.Size + } + fileInfo = &winio.FileBasicInfo{ + LastAccessTime: syscall.NsecToFiletime(hdr.AccessTime.UnixNano()), + LastWriteTime: syscall.NsecToFiletime(hdr.ModTime.UnixNano()), + ChangeTime: syscall.NsecToFiletime(hdr.ChangeTime.UnixNano()), + CreationTime: syscall.NsecToFiletime(hdr.CreationTime.UnixNano()), + } + if attrStr, ok := hdr.Winheaders[hdrFileAttributes]; ok { + attr, err := strconv.ParseUint(attrStr, 10, 32) + if err != nil { + return "", 0, nil, err + } + fileInfo.FileAttributes = uint32(attr) + } else { + if hdr.Typeflag == tar.TypeDir { + fileInfo.FileAttributes |= syscall.FILE_ATTRIBUTE_DIRECTORY + } + } + return +} + +// WriteBackupStreamFromTarFile writes a Win32 backup stream from the current tar file. Since this function may process multiple +// tar file entries in order to collect all the alternate data streams for the file, it returns the next +// tar file that was not processed, or io.EOF is there are no more. +func WriteBackupStreamFromTarFile(w io.Writer, t *tar.Reader, hdr *tar.Header) (*tar.Header, error) { + bw := winio.NewBackupStreamWriter(w) + var sd []byte + var err error + // Maintaining old SDDL-based behavior for backward compatibility. All new tar headers written + // by this library will have raw binary for the security descriptor. + if sddl, ok := hdr.Winheaders[hdrSecurityDescriptor]; ok { + sd, err = winio.SddlToSecurityDescriptor(sddl) + if err != nil { + return nil, err + } + } + if sdraw, ok := hdr.Winheaders[hdrRawSecurityDescriptor]; ok { + sd, err = base64.StdEncoding.DecodeString(sdraw) + if err != nil { + return nil, err + } + } + if len(sd) != 0 { + bhdr := winio.BackupHeader{ + Id: winio.BackupSecurity, + Size: int64(len(sd)), + } + err := bw.WriteHeader(&bhdr) + if err != nil { + return nil, err + } + _, err = bw.Write(sd) + if err != nil { + return nil, err + } + } + var eas []winio.ExtendedAttribute + for k, v := range hdr.Winheaders { + if !strings.HasPrefix(k, hdrEaPrefix) { + continue + } + data, err := base64.StdEncoding.DecodeString(v) + if err != nil { + return nil, err + } + eas = append(eas, winio.ExtendedAttribute{ + Name: k[len(hdrEaPrefix):], + Value: data, + }) + } + if len(eas) != 0 { + eadata, err := winio.EncodeExtendedAttributes(eas) + if err != nil { + return nil, err + } + bhdr := winio.BackupHeader{ + Id: winio.BackupEaData, + Size: int64(len(eadata)), + } + err = bw.WriteHeader(&bhdr) + if err != nil { + return nil, err + } + _, err = bw.Write(eadata) + if err != nil { + return nil, err + } + } + if hdr.Typeflag == tar.TypeSymlink { + _, isMountPoint := hdr.Winheaders[hdrMountPoint] + rp := winio.ReparsePoint{ + Target: filepath.FromSlash(hdr.Linkname), + IsMountPoint: isMountPoint, + } + reparse := winio.EncodeReparsePoint(&rp) + bhdr := winio.BackupHeader{ + Id: winio.BackupReparseData, + Size: int64(len(reparse)), + } + err := bw.WriteHeader(&bhdr) + if err != nil { + return nil, err + } + _, err = bw.Write(reparse) + if err != nil { + return nil, err + } + } + if hdr.Typeflag == tar.TypeReg || hdr.Typeflag == tar.TypeRegA { + bhdr := winio.BackupHeader{ + Id: winio.BackupData, + Size: hdr.Size, + } + err := bw.WriteHeader(&bhdr) + if err != nil { + return nil, err + } + _, err = io.Copy(bw, t) + if err != nil { + return nil, err + } + } + // Copy all the alternate data streams and return the next non-ADS header. + for { + ahdr, err := t.Next() + if err != nil { + return nil, err + } + if ahdr.Typeflag != tar.TypeReg || !strings.HasPrefix(ahdr.Name, hdr.Name+":") { + return ahdr, nil + } + bhdr := winio.BackupHeader{ + Id: winio.BackupAlternateData, + Size: ahdr.Size, + Name: ahdr.Name[len(hdr.Name):] + ":$DATA", + } + err = bw.WriteHeader(&bhdr) + if err != nil { + return nil, err + } + _, err = io.Copy(bw, t) + if err != nil { + return nil, err + } + } +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/ea.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/ea.go new file mode 100644 index 0000000000..4051c1b33b --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/ea.go @@ -0,0 +1,137 @@ +package winio + +import ( + "bytes" + "encoding/binary" + "errors" +) + +type fileFullEaInformation struct { + NextEntryOffset uint32 + Flags uint8 + NameLength uint8 + ValueLength uint16 +} + +var ( + fileFullEaInformationSize = binary.Size(&fileFullEaInformation{}) + + errInvalidEaBuffer = errors.New("invalid extended attribute buffer") + errEaNameTooLarge = errors.New("extended attribute name too large") + errEaValueTooLarge = errors.New("extended attribute value too large") +) + +// ExtendedAttribute represents a single Windows EA. +type ExtendedAttribute struct { + Name string + Value []byte + Flags uint8 +} + +func parseEa(b []byte) (ea ExtendedAttribute, nb []byte, err error) { + var info fileFullEaInformation + err = binary.Read(bytes.NewReader(b), binary.LittleEndian, &info) + if err != nil { + err = errInvalidEaBuffer + return + } + + nameOffset := fileFullEaInformationSize + nameLen := int(info.NameLength) + valueOffset := nameOffset + int(info.NameLength) + 1 + valueLen := int(info.ValueLength) + nextOffset := int(info.NextEntryOffset) + if valueLen+valueOffset > len(b) || nextOffset < 0 || nextOffset > len(b) { + err = errInvalidEaBuffer + return + } + + ea.Name = string(b[nameOffset : nameOffset+nameLen]) + ea.Value = b[valueOffset : valueOffset+valueLen] + ea.Flags = info.Flags + if info.NextEntryOffset != 0 { + nb = b[info.NextEntryOffset:] + } + return +} + +// DecodeExtendedAttributes decodes a list of EAs from a FILE_FULL_EA_INFORMATION +// buffer retrieved from BackupRead, ZwQueryEaFile, etc. +func DecodeExtendedAttributes(b []byte) (eas []ExtendedAttribute, err error) { + for len(b) != 0 { + ea, nb, err := parseEa(b) + if err != nil { + return nil, err + } + + eas = append(eas, ea) + b = nb + } + return +} + +func writeEa(buf *bytes.Buffer, ea *ExtendedAttribute, last bool) error { + if int(uint8(len(ea.Name))) != len(ea.Name) { + return errEaNameTooLarge + } + if int(uint16(len(ea.Value))) != len(ea.Value) { + return errEaValueTooLarge + } + entrySize := uint32(fileFullEaInformationSize + len(ea.Name) + 1 + len(ea.Value)) + withPadding := (entrySize + 3) &^ 3 + nextOffset := uint32(0) + if !last { + nextOffset = withPadding + } + info := fileFullEaInformation{ + NextEntryOffset: nextOffset, + Flags: ea.Flags, + NameLength: uint8(len(ea.Name)), + ValueLength: uint16(len(ea.Value)), + } + + err := binary.Write(buf, binary.LittleEndian, &info) + if err != nil { + return err + } + + _, err = buf.Write([]byte(ea.Name)) + if err != nil { + return err + } + + err = buf.WriteByte(0) + if err != nil { + return err + } + + _, err = buf.Write(ea.Value) + if err != nil { + return err + } + + _, err = buf.Write([]byte{0, 0, 0}[0 : withPadding-entrySize]) + if err != nil { + return err + } + + return nil +} + +// EncodeExtendedAttributes encodes a list of EAs into a FILE_FULL_EA_INFORMATION +// buffer for use with BackupWrite, ZwSetEaFile, etc. +func EncodeExtendedAttributes(eas []ExtendedAttribute) ([]byte, error) { + var buf bytes.Buffer + for i := range eas { + last := false + if i == len(eas)-1 { + last = true + } + + err := writeEa(&buf, &eas[i], last) + if err != nil { + return nil, err + } + } + return buf.Bytes(), nil +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/file.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/file.go new file mode 100644 index 0000000000..4334ff1cbe --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/file.go @@ -0,0 +1,307 @@ +// +build windows + +package winio + +import ( + "errors" + "io" + "runtime" + "sync" + "sync/atomic" + "syscall" + "time" +) + +//sys cancelIoEx(file syscall.Handle, o *syscall.Overlapped) (err error) = CancelIoEx +//sys createIoCompletionPort(file syscall.Handle, port syscall.Handle, key uintptr, threadCount uint32) (newport syscall.Handle, err error) = CreateIoCompletionPort +//sys getQueuedCompletionStatus(port syscall.Handle, bytes *uint32, key *uintptr, o **ioOperation, timeout uint32) (err error) = GetQueuedCompletionStatus +//sys setFileCompletionNotificationModes(h syscall.Handle, flags uint8) (err error) = SetFileCompletionNotificationModes + +type atomicBool int32 + +func (b *atomicBool) isSet() bool { return atomic.LoadInt32((*int32)(b)) != 0 } +func (b *atomicBool) setFalse() { atomic.StoreInt32((*int32)(b), 0) } +func (b *atomicBool) setTrue() { atomic.StoreInt32((*int32)(b), 1) } +func (b *atomicBool) swap(new bool) bool { + var newInt int32 + if new { + newInt = 1 + } + return atomic.SwapInt32((*int32)(b), newInt) == 1 +} + +const ( + cFILE_SKIP_COMPLETION_PORT_ON_SUCCESS = 1 + cFILE_SKIP_SET_EVENT_ON_HANDLE = 2 +) + +var ( + ErrFileClosed = errors.New("file has already been closed") + ErrTimeout = &timeoutError{} +) + +type timeoutError struct{} + +func (e *timeoutError) Error() string { return "i/o timeout" } +func (e *timeoutError) Timeout() bool { return true } +func (e *timeoutError) Temporary() bool { return true } + +type timeoutChan chan struct{} + +var ioInitOnce sync.Once +var ioCompletionPort syscall.Handle + +// ioResult contains the result of an asynchronous IO operation +type ioResult struct { + bytes uint32 + err error +} + +// ioOperation represents an outstanding asynchronous Win32 IO +type ioOperation struct { + o syscall.Overlapped + ch chan ioResult +} + +func initIo() { + h, err := createIoCompletionPort(syscall.InvalidHandle, 0, 0, 0xffffffff) + if err != nil { + panic(err) + } + ioCompletionPort = h + go ioCompletionProcessor(h) +} + +// win32File implements Reader, Writer, and Closer on a Win32 handle without blocking in a syscall. +// It takes ownership of this handle and will close it if it is garbage collected. +type win32File struct { + handle syscall.Handle + wg sync.WaitGroup + wgLock sync.RWMutex + closing atomicBool + readDeadline deadlineHandler + writeDeadline deadlineHandler +} + +type deadlineHandler struct { + setLock sync.Mutex + channel timeoutChan + channelLock sync.RWMutex + timer *time.Timer + timedout atomicBool +} + +// makeWin32File makes a new win32File from an existing file handle +func makeWin32File(h syscall.Handle) (*win32File, error) { + f := &win32File{handle: h} + ioInitOnce.Do(initIo) + _, err := createIoCompletionPort(h, ioCompletionPort, 0, 0xffffffff) + if err != nil { + return nil, err + } + err = setFileCompletionNotificationModes(h, cFILE_SKIP_COMPLETION_PORT_ON_SUCCESS|cFILE_SKIP_SET_EVENT_ON_HANDLE) + if err != nil { + return nil, err + } + f.readDeadline.channel = make(timeoutChan) + f.writeDeadline.channel = make(timeoutChan) + return f, nil +} + +func MakeOpenFile(h syscall.Handle) (io.ReadWriteCloser, error) { + return makeWin32File(h) +} + +// closeHandle closes the resources associated with a Win32 handle +func (f *win32File) closeHandle() { + f.wgLock.Lock() + // Atomically set that we are closing, releasing the resources only once. + if !f.closing.swap(true) { + f.wgLock.Unlock() + // cancel all IO and wait for it to complete + cancelIoEx(f.handle, nil) + f.wg.Wait() + // at this point, no new IO can start + syscall.Close(f.handle) + f.handle = 0 + } else { + f.wgLock.Unlock() + } +} + +// Close closes a win32File. +func (f *win32File) Close() error { + f.closeHandle() + return nil +} + +// prepareIo prepares for a new IO operation. +// The caller must call f.wg.Done() when the IO is finished, prior to Close() returning. +func (f *win32File) prepareIo() (*ioOperation, error) { + f.wgLock.RLock() + if f.closing.isSet() { + f.wgLock.RUnlock() + return nil, ErrFileClosed + } + f.wg.Add(1) + f.wgLock.RUnlock() + c := &ioOperation{} + c.ch = make(chan ioResult) + return c, nil +} + +// ioCompletionProcessor processes completed async IOs forever +func ioCompletionProcessor(h syscall.Handle) { + for { + var bytes uint32 + var key uintptr + var op *ioOperation + err := getQueuedCompletionStatus(h, &bytes, &key, &op, syscall.INFINITE) + if op == nil { + panic(err) + } + op.ch <- ioResult{bytes, err} + } +} + +// asyncIo processes the return value from ReadFile or WriteFile, blocking until +// the operation has actually completed. +func (f *win32File) asyncIo(c *ioOperation, d *deadlineHandler, bytes uint32, err error) (int, error) { + if err != syscall.ERROR_IO_PENDING { + return int(bytes), err + } + + if f.closing.isSet() { + cancelIoEx(f.handle, &c.o) + } + + var timeout timeoutChan + if d != nil { + d.channelLock.Lock() + timeout = d.channel + d.channelLock.Unlock() + } + + var r ioResult + select { + case r = <-c.ch: + err = r.err + if err == syscall.ERROR_OPERATION_ABORTED { + if f.closing.isSet() { + err = ErrFileClosed + } + } + case <-timeout: + cancelIoEx(f.handle, &c.o) + r = <-c.ch + err = r.err + if err == syscall.ERROR_OPERATION_ABORTED { + err = ErrTimeout + } + } + + // runtime.KeepAlive is needed, as c is passed via native + // code to ioCompletionProcessor, c must remain alive + // until the channel read is complete. + runtime.KeepAlive(c) + return int(r.bytes), err +} + +// Read reads from a file handle. +func (f *win32File) Read(b []byte) (int, error) { + c, err := f.prepareIo() + if err != nil { + return 0, err + } + defer f.wg.Done() + + if f.readDeadline.timedout.isSet() { + return 0, ErrTimeout + } + + var bytes uint32 + err = syscall.ReadFile(f.handle, b, &bytes, &c.o) + n, err := f.asyncIo(c, &f.readDeadline, bytes, err) + runtime.KeepAlive(b) + + // Handle EOF conditions. + if err == nil && n == 0 && len(b) != 0 { + return 0, io.EOF + } else if err == syscall.ERROR_BROKEN_PIPE { + return 0, io.EOF + } else { + return n, err + } +} + +// Write writes to a file handle. +func (f *win32File) Write(b []byte) (int, error) { + c, err := f.prepareIo() + if err != nil { + return 0, err + } + defer f.wg.Done() + + if f.writeDeadline.timedout.isSet() { + return 0, ErrTimeout + } + + var bytes uint32 + err = syscall.WriteFile(f.handle, b, &bytes, &c.o) + n, err := f.asyncIo(c, &f.writeDeadline, bytes, err) + runtime.KeepAlive(b) + return n, err +} + +func (f *win32File) SetReadDeadline(deadline time.Time) error { + return f.readDeadline.set(deadline) +} + +func (f *win32File) SetWriteDeadline(deadline time.Time) error { + return f.writeDeadline.set(deadline) +} + +func (f *win32File) Flush() error { + return syscall.FlushFileBuffers(f.handle) +} + +func (d *deadlineHandler) set(deadline time.Time) error { + d.setLock.Lock() + defer d.setLock.Unlock() + + if d.timer != nil { + if !d.timer.Stop() { + <-d.channel + } + d.timer = nil + } + d.timedout.setFalse() + + select { + case <-d.channel: + d.channelLock.Lock() + d.channel = make(chan struct{}) + d.channelLock.Unlock() + default: + } + + if deadline.IsZero() { + return nil + } + + timeoutIO := func() { + d.timedout.setTrue() + close(d.channel) + } + + now := time.Now() + duration := deadline.Sub(now) + if deadline.After(now) { + // Deadline is in the future, set a timer to wait + d.timer = time.AfterFunc(duration, timeoutIO) + } else { + // Deadline is in the past. Cancel all pending IO now. + timeoutIO() + } + return nil +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/fileinfo.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/fileinfo.go new file mode 100644 index 0000000000..ada2fbab63 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/fileinfo.go @@ -0,0 +1,61 @@ +// +build windows + +package winio + +import ( + "os" + "runtime" + "syscall" + "unsafe" +) + +//sys getFileInformationByHandleEx(h syscall.Handle, class uint32, buffer *byte, size uint32) (err error) = GetFileInformationByHandleEx +//sys setFileInformationByHandle(h syscall.Handle, class uint32, buffer *byte, size uint32) (err error) = SetFileInformationByHandle + +const ( + fileBasicInfo = 0 + fileIDInfo = 0x12 +) + +// FileBasicInfo contains file access time and file attributes information. +type FileBasicInfo struct { + CreationTime, LastAccessTime, LastWriteTime, ChangeTime syscall.Filetime + FileAttributes uint32 + pad uint32 // padding +} + +// GetFileBasicInfo retrieves times and attributes for a file. +func GetFileBasicInfo(f *os.File) (*FileBasicInfo, error) { + bi := &FileBasicInfo{} + if err := getFileInformationByHandleEx(syscall.Handle(f.Fd()), fileBasicInfo, (*byte)(unsafe.Pointer(bi)), uint32(unsafe.Sizeof(*bi))); err != nil { + return nil, &os.PathError{Op: "GetFileInformationByHandleEx", Path: f.Name(), Err: err} + } + runtime.KeepAlive(f) + return bi, nil +} + +// SetFileBasicInfo sets times and attributes for a file. +func SetFileBasicInfo(f *os.File, bi *FileBasicInfo) error { + if err := setFileInformationByHandle(syscall.Handle(f.Fd()), fileBasicInfo, (*byte)(unsafe.Pointer(bi)), uint32(unsafe.Sizeof(*bi))); err != nil { + return &os.PathError{Op: "SetFileInformationByHandle", Path: f.Name(), Err: err} + } + runtime.KeepAlive(f) + return nil +} + +// FileIDInfo contains the volume serial number and file ID for a file. This pair should be +// unique on a system. +type FileIDInfo struct { + VolumeSerialNumber uint64 + FileID [16]byte +} + +// GetFileID retrieves the unique (volume, file ID) pair for a file. +func GetFileID(f *os.File) (*FileIDInfo, error) { + fileID := &FileIDInfo{} + if err := getFileInformationByHandleEx(syscall.Handle(f.Fd()), fileIDInfo, (*byte)(unsafe.Pointer(fileID)), uint32(unsafe.Sizeof(*fileID))); err != nil { + return nil, &os.PathError{Op: "GetFileInformationByHandleEx", Path: f.Name(), Err: err} + } + runtime.KeepAlive(f) + return fileID, nil +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/internal/etw/etw.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/internal/etw/etw.go new file mode 100644 index 0000000000..da905ec90a --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/internal/etw/etw.go @@ -0,0 +1,14 @@ +// Package etw provides support for TraceLogging-based ETW (Event Tracing +// for Windows). TraceLogging is a format of ETW events that are self-describing +// (the event contains information on its own schema). This allows them to be +// decoded without needing a separate manifest with event information. The +// implementation here is based on the information found in +// TraceLoggingProvider.h in the Windows SDK, which implements TraceLogging as a +// set of C macros. +package etw + +//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go etw.go + +//sys eventRegister(providerId *windows.GUID, callback uintptr, callbackContext uintptr, providerHandle *providerHandle) (win32err error) = advapi32.EventRegister +//sys eventUnregister(providerHandle providerHandle) (win32err error) = advapi32.EventUnregister +//sys eventWriteTransfer(providerHandle providerHandle, descriptor *EventDescriptor, activityID *windows.GUID, relatedActivityID *windows.GUID, dataDescriptorCount uint32, dataDescriptors *eventDataDescriptor) (win32err error) = advapi32.EventWriteTransfer diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/internal/etw/eventdata.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/internal/etw/eventdata.go new file mode 100644 index 0000000000..85307343cf --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/internal/etw/eventdata.go @@ -0,0 +1,65 @@ +package etw + +import ( + "bytes" + "encoding/binary" +) + +// EventData maintains a buffer which builds up the data for an ETW event. It +// needs to be paired with EventMetadata which describes the event. +type EventData struct { + buffer bytes.Buffer +} + +// Bytes returns the raw binary data containing the event data. The returned +// value is not copied from the internal buffer, so it can be mutated by the +// EventData object after it is returned. +func (ed *EventData) Bytes() []byte { + return ed.buffer.Bytes() +} + +// WriteString appends a string, including the null terminator, to the buffer. +func (ed *EventData) WriteString(data string) { + ed.buffer.WriteString(data) + ed.buffer.WriteByte(0) +} + +// WriteInt8 appends a int8 to the buffer. +func (ed *EventData) WriteInt8(value int8) { + ed.buffer.WriteByte(uint8(value)) +} + +// WriteInt16 appends a int16 to the buffer. +func (ed *EventData) WriteInt16(value int16) { + binary.Write(&ed.buffer, binary.LittleEndian, value) +} + +// WriteInt32 appends a int32 to the buffer. +func (ed *EventData) WriteInt32(value int32) { + binary.Write(&ed.buffer, binary.LittleEndian, value) +} + +// WriteInt64 appends a int64 to the buffer. +func (ed *EventData) WriteInt64(value int64) { + binary.Write(&ed.buffer, binary.LittleEndian, value) +} + +// WriteUint8 appends a uint8 to the buffer. +func (ed *EventData) WriteUint8(value uint8) { + ed.buffer.WriteByte(value) +} + +// WriteUint16 appends a uint16 to the buffer. +func (ed *EventData) WriteUint16(value uint16) { + binary.Write(&ed.buffer, binary.LittleEndian, value) +} + +// WriteUint32 appends a uint32 to the buffer. +func (ed *EventData) WriteUint32(value uint32) { + binary.Write(&ed.buffer, binary.LittleEndian, value) +} + +// WriteUint64 appends a uint64 to the buffer. +func (ed *EventData) WriteUint64(value uint64) { + binary.Write(&ed.buffer, binary.LittleEndian, value) +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/internal/etw/eventdatadescriptor.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/internal/etw/eventdatadescriptor.go new file mode 100644 index 0000000000..e7c53cf086 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/internal/etw/eventdatadescriptor.go @@ -0,0 +1,29 @@ +package etw + +import ( + "unsafe" +) + +type eventDataDescriptorType uint8 + +const ( + eventDataDescriptorTypeUserData eventDataDescriptorType = iota + eventDataDescriptorTypeEventMetadata + eventDataDescriptorTypeProviderMetadata +) + +type eventDataDescriptor struct { + ptr ptr64 + size uint32 + dataType eventDataDescriptorType + reserved1 uint8 + reserved2 uint16 +} + +func newEventDataDescriptor(dataType eventDataDescriptorType, buffer []byte) eventDataDescriptor { + return eventDataDescriptor{ + ptr: ptr64{ptr: unsafe.Pointer(&buffer[0])}, + size: uint32(len(buffer)), + dataType: dataType, + } +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/internal/etw/eventdescriptor.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/internal/etw/eventdescriptor.go new file mode 100644 index 0000000000..394676513e --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/internal/etw/eventdescriptor.go @@ -0,0 +1,67 @@ +package etw + +// Channel represents the ETW logging channel that is used. It can be used by +// event consumers to give an event special treatment. +type Channel uint8 + +const ( + // ChannelTraceLogging is the default channel for TraceLogging events. It is + // not required to be used for TraceLogging, but will prevent decoding + // issues for these events on older operating systems. + ChannelTraceLogging Channel = 11 +) + +// Level represents the ETW logging level. There are several predefined levels +// that are commonly used, but technically anything from 0-255 is allowed. +// Lower levels indicate more important events, and 0 indicates an event that +// will always be collected. +type Level uint8 + +// Predefined ETW log levels. +const ( + LevelAlways Level = iota + LevelCritical + LevelError + LevelWarning + LevelInfo + LevelVerbose +) + +// EventDescriptor represents various metadata for an ETW event. +type EventDescriptor struct { + id uint16 + version uint8 + Channel Channel + Level Level + Opcode uint8 + Task uint16 + Keyword uint64 +} + +// NewEventDescriptor returns an EventDescriptor initialized for use with +// TraceLogging. +func NewEventDescriptor() *EventDescriptor { + // Standard TraceLogging events default to the TraceLogging channel, and + // verbose level. + return &EventDescriptor{ + Channel: ChannelTraceLogging, + Level: LevelVerbose, + } +} + +// Identity returns the identity of the event. If the identity is not 0, it +// should uniquely identify the other event metadata (contained in +// EventDescriptor, and field metadata). Only the lower 24 bits of this value +// are relevant. +func (ed *EventDescriptor) Identity() uint32 { + return (uint32(ed.version) << 16) | uint32(ed.id) +} + +// SetIdentity sets the identity of the event. If the identity is not 0, it +// should uniquely identify the other event metadata (contained in +// EventDescriptor, and field metadata). Only the lower 24 bits of this value +// are relevant. +func (ed *EventDescriptor) SetIdentity(identity uint32) { + ed.id = uint16(identity) + ed.version = uint8(identity >> 16) +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/internal/etw/eventmetadata.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/internal/etw/eventmetadata.go new file mode 100644 index 0000000000..d294027fc1 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/internal/etw/eventmetadata.go @@ -0,0 +1,177 @@ +package etw + +import ( + "bytes" + "encoding/binary" +) + +// InType indicates the type of data contained in the ETW event. +type InType byte + +// Various InType definitions for TraceLogging. These must match the definitions +// found in TraceLoggingProvider.h in the Windows SDK. +const ( + InTypeNull InType = iota + InTypeUnicodeString + InTypeANSIString + InTypeInt8 + InTypeUint8 + InTypeInt16 + InTypeUint16 + InTypeInt32 + InTypeUint32 + InTypeInt64 + InTypeUint64 + InTypeFloat + InTypeDouble + InTypeBool32 + InTypeBinary + InTypeGUID + InTypePointerUnsupported + InTypeFileTime + InTypeSystemTime + InTypeSID + InTypeHexInt32 + InTypeHexInt64 + InTypeCountedString + InTypeCountedANSIString + InTypeStruct + InTypeCountedBinary + InTypeCountedArray InType = 32 + InTypeArray InType = 64 +) + +// OutType specifies a hint to the event decoder for how the value should be +// formatted. +type OutType byte + +// Various OutType definitions for TraceLogging. These must match the +// definitions found in TraceLoggingProvider.h in the Windows SDK. +const ( + // OutTypeDefault indicates that the default formatting for the InType will + // be used by the event decoder. + OutTypeDefault OutType = iota + OutTypeNoPrint + OutTypeString + OutTypeBoolean + OutTypeHex + OutTypePID + OutTypeTID + OutTypePort + OutTypeIPv4 + OutTypeIPv6 + OutTypeSocketAddress + OutTypeXML + OutTypeJSON + OutTypeWin32Error + OutTypeNTStatus + OutTypeHResult + OutTypeFileTime + OutTypeSigned + OutTypeUnsigned + OutTypeUTF8 OutType = 35 + OutTypePKCS7WithTypeInfo OutType = 36 + OutTypeCodePointer OutType = 37 + OutTypeDateTimeUTC OutType = 38 +) + +// EventMetadata maintains a buffer which builds up the metadata for an ETW +// event. It needs to be paired with EventData which describes the event. +type EventMetadata struct { + buffer bytes.Buffer +} + +// Bytes returns the raw binary data containing the event metadata. Before being +// returned, the current size of the buffer is written to the start of the +// buffer. The returned value is not copied from the internal buffer, so it can +// be mutated by the EventMetadata object after it is returned. +func (em *EventMetadata) Bytes() []byte { + // Finalize the event metadata buffer by filling in the buffer length at the + // beginning. + binary.LittleEndian.PutUint16(em.buffer.Bytes(), uint16(em.buffer.Len())) + return em.buffer.Bytes() +} + +// WriteEventHeader writes the metadata for the start of an event to the buffer. +// This specifies the event name and tags. +func (em *EventMetadata) WriteEventHeader(name string, tags uint32) { + binary.Write(&em.buffer, binary.LittleEndian, uint16(0)) // Length placeholder + em.writeTags(tags) + em.buffer.WriteString(name) + em.buffer.WriteByte(0) // Null terminator for name +} + +func (em *EventMetadata) writeField(name string, inType InType, outType OutType, tags uint32, arrSize uint16) { + em.buffer.WriteString(name) + em.buffer.WriteByte(0) // Null terminator for name + + if outType == OutTypeDefault && tags == 0 { + em.buffer.WriteByte(byte(inType)) + } else { + em.buffer.WriteByte(byte(inType | 128)) + if tags == 0 { + em.buffer.WriteByte(byte(outType)) + } else { + em.buffer.WriteByte(byte(outType | 128)) + em.writeTags(tags) + } + } + + if arrSize != 0 { + binary.Write(&em.buffer, binary.LittleEndian, arrSize) + } +} + +// writeTags writes out the tags value to the event metadata. Tags is a 28-bit +// value, interpreted as bit flags, which are only relevant to the event +// consumer. The event consumer may choose to attribute special meaning to tags +// (e.g. 0x4 could mean the field contains PII). Tags are written as a series of +// bytes, each containing 7 bits of tag value, with the high bit set if there is +// more tag data in the following byte. This allows for a more compact +// representation when not all of the tag bits are needed. +func (em *EventMetadata) writeTags(tags uint32) { + // Only use the top 28 bits of the tags value. + tags &= 0xfffffff + + for { + // Tags are written with the most significant bits (e.g. 21-27) first. + val := tags >> 21 + + if tags&0x1fffff == 0 { + // If there is no more data to write after this, write this value + // without the high bit set, and return. + em.buffer.WriteByte(byte(val & 0x7f)) + return + } + + em.buffer.WriteByte(byte(val | 0x80)) + + tags <<= 7 + } +} + +// WriteField writes the metadata for a simple field to the buffer. +func (em *EventMetadata) WriteField(name string, inType InType, outType OutType, tags uint32) { + em.writeField(name, inType, outType, tags, 0) +} + +// WriteArray writes the metadata for an array field to the buffer. The number +// of elements in the array must be written as a uint16 in the event data, +// immediately preceeding the event data. +func (em *EventMetadata) WriteArray(name string, inType InType, outType OutType, tags uint32) { + em.writeField(name, inType|InTypeArray, outType, tags, 0) +} + +// WriteCountedArray writes the metadata for an array field to the buffer. The +// size of a counted array is fixed, and the size is written into the metadata +// directly. +func (em *EventMetadata) WriteCountedArray(name string, count uint16, inType InType, outType OutType, tags uint32) { + em.writeField(name, inType|InTypeCountedArray, outType, tags, count) +} + +// WriteStruct writes the metadata for a nested struct to the buffer. The struct +// contains the next N fields in the metadata, where N is specified by the +// fieldCount argument. +func (em *EventMetadata) WriteStruct(name string, fieldCount uint8, tags uint32) { + em.writeField(name, InTypeStruct, OutType(fieldCount), tags, 0) +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/internal/etw/eventopt.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/internal/etw/eventopt.go new file mode 100644 index 0000000000..5c752dc046 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/internal/etw/eventopt.go @@ -0,0 +1,57 @@ +package etw + +import ( + "golang.org/x/sys/windows" +) + +type eventOptions struct { + descriptor *EventDescriptor + activityID *windows.GUID + relatedActivityID *windows.GUID + tags uint32 +} + +// EventOpt defines the option function type that can be passed to +// Provider.WriteEvent to specify general event options, such as level and +// keyword. +type EventOpt func(options *eventOptions) + +// WithEventOpts returns the variadic arguments as a single slice. +func WithEventOpts(opts ...EventOpt) []EventOpt { + return opts +} + +// WithLevel specifies the level of the event to be written. +func WithLevel(level Level) EventOpt { + return func(options *eventOptions) { + options.descriptor.Level = level + } +} + +// WithKeyword specifies the keywords of the event to be written. Multiple uses +// of this option are OR'd together. +func WithKeyword(keyword uint64) EventOpt { + return func(options *eventOptions) { + options.descriptor.Keyword |= keyword + } +} + +// WithTags specifies the tags of the event to be written. Tags is a 28-bit +// value (top 4 bits are ignored) which are interpreted by the event consumer. +func WithTags(newTags uint32) EventOpt { + return func(options *eventOptions) { + options.tags |= newTags + } +} + +func WithActivityID(activityID *windows.GUID) EventOpt { + return func(options *eventOptions) { + options.activityID = activityID + } +} + +func WithRelatedActivityID(activityID *windows.GUID) EventOpt { + return func(options *eventOptions) { + options.relatedActivityID = activityID + } +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/internal/etw/fieldopt.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/internal/etw/fieldopt.go new file mode 100644 index 0000000000..76f63bcb53 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/internal/etw/fieldopt.go @@ -0,0 +1,379 @@ +package etw + +import ( + "math" + "unsafe" +) + +// FieldOpt defines the option function type that can be passed to +// Provider.WriteEvent to add fields to the event. +type FieldOpt func(em *EventMetadata, ed *EventData) + +// WithFields returns the variadic arguments as a single slice. +func WithFields(opts ...FieldOpt) []FieldOpt { + return opts +} + +// BoolField adds a single bool field to the event. +func BoolField(name string, value bool) FieldOpt { + return func(em *EventMetadata, ed *EventData) { + em.WriteField(name, InTypeUint8, OutTypeBoolean, 0) + bool8 := uint8(0) + if value { + bool8 = uint8(1) + } + ed.WriteUint8(bool8) + } +} + +// BoolArray adds an array of bool to the event. +func BoolArray(name string, values []bool) FieldOpt { + return func(em *EventMetadata, ed *EventData) { + em.WriteArray(name, InTypeUint8, OutTypeBoolean, 0) + ed.WriteUint16(uint16(len(values))) + for _, v := range values { + bool8 := uint8(0) + if v { + bool8 = uint8(1) + } + ed.WriteUint8(bool8) + } + } +} + +// StringField adds a single string field to the event. +func StringField(name string, value string) FieldOpt { + return func(em *EventMetadata, ed *EventData) { + em.WriteField(name, InTypeANSIString, OutTypeUTF8, 0) + ed.WriteString(value) + } +} + +// StringArray adds an array of string to the event. +func StringArray(name string, values []string) FieldOpt { + return func(em *EventMetadata, ed *EventData) { + em.WriteArray(name, InTypeANSIString, OutTypeUTF8, 0) + ed.WriteUint16(uint16(len(values))) + for _, v := range values { + ed.WriteString(v) + } + } +} + +// IntField adds a single int field to the event. +func IntField(name string, value int) FieldOpt { + switch unsafe.Sizeof(value) { + case 4: + return Int32Field(name, int32(value)) + case 8: + return Int64Field(name, int64(value)) + default: + panic("Unsupported int size") + } +} + +// IntArray adds an array of int to the event. +func IntArray(name string, values []int) FieldOpt { + inType := InTypeNull + var writeItem func(*EventData, int) + switch unsafe.Sizeof(values[0]) { + case 4: + inType = InTypeInt32 + writeItem = func(ed *EventData, item int) { ed.WriteInt32(int32(item)) } + case 8: + inType = InTypeInt64 + writeItem = func(ed *EventData, item int) { ed.WriteInt64(int64(item)) } + default: + panic("Unsupported int size") + } + + return func(em *EventMetadata, ed *EventData) { + em.WriteArray(name, inType, OutTypeDefault, 0) + ed.WriteUint16(uint16(len(values))) + for _, v := range values { + writeItem(ed, v) + } + } +} + +// Int8Field adds a single int8 field to the event. +func Int8Field(name string, value int8) FieldOpt { + return func(em *EventMetadata, ed *EventData) { + em.WriteField(name, InTypeInt8, OutTypeDefault, 0) + ed.WriteInt8(value) + } +} + +// Int8Array adds an array of int8 to the event. +func Int8Array(name string, values []int8) FieldOpt { + return func(em *EventMetadata, ed *EventData) { + em.WriteArray(name, InTypeInt8, OutTypeDefault, 0) + ed.WriteUint16(uint16(len(values))) + for _, v := range values { + ed.WriteInt8(v) + } + } +} + +// Int16Field adds a single int16 field to the event. +func Int16Field(name string, value int16) FieldOpt { + return func(em *EventMetadata, ed *EventData) { + em.WriteField(name, InTypeInt16, OutTypeDefault, 0) + ed.WriteInt16(value) + } +} + +// Int16Array adds an array of int16 to the event. +func Int16Array(name string, values []int16) FieldOpt { + return func(em *EventMetadata, ed *EventData) { + em.WriteArray(name, InTypeInt16, OutTypeDefault, 0) + ed.WriteUint16(uint16(len(values))) + for _, v := range values { + ed.WriteInt16(v) + } + } +} + +// Int32Field adds a single int32 field to the event. +func Int32Field(name string, value int32) FieldOpt { + return func(em *EventMetadata, ed *EventData) { + em.WriteField(name, InTypeInt32, OutTypeDefault, 0) + ed.WriteInt32(value) + } +} + +// Int32Array adds an array of int32 to the event. +func Int32Array(name string, values []int32) FieldOpt { + return func(em *EventMetadata, ed *EventData) { + em.WriteArray(name, InTypeInt32, OutTypeDefault, 0) + ed.WriteUint16(uint16(len(values))) + for _, v := range values { + ed.WriteInt32(v) + } + } +} + +// Int64Field adds a single int64 field to the event. +func Int64Field(name string, value int64) FieldOpt { + return func(em *EventMetadata, ed *EventData) { + em.WriteField(name, InTypeInt64, OutTypeDefault, 0) + ed.WriteInt64(value) + } +} + +// Int64Array adds an array of int64 to the event. +func Int64Array(name string, values []int64) FieldOpt { + return func(em *EventMetadata, ed *EventData) { + em.WriteArray(name, InTypeInt64, OutTypeDefault, 0) + ed.WriteUint16(uint16(len(values))) + for _, v := range values { + ed.WriteInt64(v) + } + } +} + +// UintField adds a single uint field to the event. +func UintField(name string, value uint) FieldOpt { + switch unsafe.Sizeof(value) { + case 4: + return Uint32Field(name, uint32(value)) + case 8: + return Uint64Field(name, uint64(value)) + default: + panic("Unsupported uint size") + } +} + +// UintArray adds an array of uint to the event. +func UintArray(name string, values []uint) FieldOpt { + inType := InTypeNull + var writeItem func(*EventData, uint) + switch unsafe.Sizeof(values[0]) { + case 4: + inType = InTypeUint32 + writeItem = func(ed *EventData, item uint) { ed.WriteUint32(uint32(item)) } + case 8: + inType = InTypeUint64 + writeItem = func(ed *EventData, item uint) { ed.WriteUint64(uint64(item)) } + default: + panic("Unsupported uint size") + } + + return func(em *EventMetadata, ed *EventData) { + em.WriteArray(name, inType, OutTypeDefault, 0) + ed.WriteUint16(uint16(len(values))) + for _, v := range values { + writeItem(ed, v) + } + } +} + +// Uint8Field adds a single uint8 field to the event. +func Uint8Field(name string, value uint8) FieldOpt { + return func(em *EventMetadata, ed *EventData) { + em.WriteField(name, InTypeUint8, OutTypeDefault, 0) + ed.WriteUint8(value) + } +} + +// Uint8Array adds an array of uint8 to the event. +func Uint8Array(name string, values []uint8) FieldOpt { + return func(em *EventMetadata, ed *EventData) { + em.WriteArray(name, InTypeUint8, OutTypeDefault, 0) + ed.WriteUint16(uint16(len(values))) + for _, v := range values { + ed.WriteUint8(v) + } + } +} + +// Uint16Field adds a single uint16 field to the event. +func Uint16Field(name string, value uint16) FieldOpt { + return func(em *EventMetadata, ed *EventData) { + em.WriteField(name, InTypeUint16, OutTypeDefault, 0) + ed.WriteUint16(value) + } +} + +// Uint16Array adds an array of uint16 to the event. +func Uint16Array(name string, values []uint16) FieldOpt { + return func(em *EventMetadata, ed *EventData) { + em.WriteArray(name, InTypeUint16, OutTypeDefault, 0) + ed.WriteUint16(uint16(len(values))) + for _, v := range values { + ed.WriteUint16(v) + } + } +} + +// Uint32Field adds a single uint32 field to the event. +func Uint32Field(name string, value uint32) FieldOpt { + return func(em *EventMetadata, ed *EventData) { + em.WriteField(name, InTypeUint32, OutTypeDefault, 0) + ed.WriteUint32(value) + } +} + +// Uint32Array adds an array of uint32 to the event. +func Uint32Array(name string, values []uint32) FieldOpt { + return func(em *EventMetadata, ed *EventData) { + em.WriteArray(name, InTypeUint32, OutTypeDefault, 0) + ed.WriteUint16(uint16(len(values))) + for _, v := range values { + ed.WriteUint32(v) + } + } +} + +// Uint64Field adds a single uint64 field to the event. +func Uint64Field(name string, value uint64) FieldOpt { + return func(em *EventMetadata, ed *EventData) { + em.WriteField(name, InTypeUint64, OutTypeDefault, 0) + ed.WriteUint64(value) + } +} + +// Uint64Array adds an array of uint64 to the event. +func Uint64Array(name string, values []uint64) FieldOpt { + return func(em *EventMetadata, ed *EventData) { + em.WriteArray(name, InTypeUint64, OutTypeDefault, 0) + ed.WriteUint16(uint16(len(values))) + for _, v := range values { + ed.WriteUint64(v) + } + } +} + +// UintptrField adds a single uintptr field to the event. +func UintptrField(name string, value uintptr) FieldOpt { + inType := InTypeNull + var writeItem func(*EventData, uintptr) + switch unsafe.Sizeof(value) { + case 4: + inType = InTypeHexInt32 + writeItem = func(ed *EventData, item uintptr) { ed.WriteUint32(uint32(item)) } + case 8: + inType = InTypeHexInt64 + writeItem = func(ed *EventData, item uintptr) { ed.WriteUint64(uint64(item)) } + default: + panic("Unsupported uintptr size") + } + + return func(em *EventMetadata, ed *EventData) { + em.WriteField(name, inType, OutTypeDefault, 0) + writeItem(ed, value) + } +} + +// UintptrArray adds an array of uintptr to the event. +func UintptrArray(name string, values []uintptr) FieldOpt { + inType := InTypeNull + var writeItem func(*EventData, uintptr) + switch unsafe.Sizeof(values[0]) { + case 4: + inType = InTypeHexInt32 + writeItem = func(ed *EventData, item uintptr) { ed.WriteUint32(uint32(item)) } + case 8: + inType = InTypeHexInt64 + writeItem = func(ed *EventData, item uintptr) { ed.WriteUint64(uint64(item)) } + default: + panic("Unsupported uintptr size") + } + + return func(em *EventMetadata, ed *EventData) { + em.WriteArray(name, inType, OutTypeDefault, 0) + ed.WriteUint16(uint16(len(values))) + for _, v := range values { + writeItem(ed, v) + } + } +} + +// Float32Field adds a single float32 field to the event. +func Float32Field(name string, value float32) FieldOpt { + return func(em *EventMetadata, ed *EventData) { + em.WriteField(name, InTypeFloat, OutTypeDefault, 0) + ed.WriteUint32(math.Float32bits(value)) + } +} + +// Float32Array adds an array of float32 to the event. +func Float32Array(name string, values []float32) FieldOpt { + return func(em *EventMetadata, ed *EventData) { + em.WriteArray(name, InTypeFloat, OutTypeDefault, 0) + ed.WriteUint16(uint16(len(values))) + for _, v := range values { + ed.WriteUint32(math.Float32bits(v)) + } + } +} + +// Float64Field adds a single float64 field to the event. +func Float64Field(name string, value float64) FieldOpt { + return func(em *EventMetadata, ed *EventData) { + em.WriteField(name, InTypeDouble, OutTypeDefault, 0) + ed.WriteUint64(math.Float64bits(value)) + } +} + +// Float64Array adds an array of float64 to the event. +func Float64Array(name string, values []float64) FieldOpt { + return func(em *EventMetadata, ed *EventData) { + em.WriteArray(name, InTypeDouble, OutTypeDefault, 0) + ed.WriteUint16(uint16(len(values))) + for _, v := range values { + ed.WriteUint64(math.Float64bits(v)) + } + } +} + +// Struct adds a nested struct to the event, the FieldOpts in the opts argument +// are used to specify the fields of the struct. +func Struct(name string, opts ...FieldOpt) FieldOpt { + return func(em *EventMetadata, ed *EventData) { + em.WriteStruct(name, uint8(len(opts)), 0) + for _, opt := range opts { + opt(em, ed) + } + } +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/internal/etw/provider.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/internal/etw/provider.go new file mode 100644 index 0000000000..10c2fd6d18 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/internal/etw/provider.go @@ -0,0 +1,260 @@ +package etw + +import ( + "bytes" + "crypto/sha1" + "encoding/binary" + "encoding/hex" + "fmt" + "strings" + "unicode/utf16" + + "golang.org/x/sys/windows" +) + +// Provider represents an ETW event provider. It is identified by a provider +// name and ID (GUID), which should always have a 1:1 mapping to each other +// (e.g. don't use multiple provider names with the same ID, or vice versa). +type Provider struct { + ID *windows.GUID + handle providerHandle + metadata []byte + callback EnableCallback + index uint + enabled bool + level Level + keywordAny uint64 + keywordAll uint64 +} + +// String returns the `provider`.ID as a string +func (provider *Provider) String() string { + data1 := make([]byte, 4) + binary.BigEndian.PutUint32(data1, provider.ID.Data1) + data2 := make([]byte, 2) + binary.BigEndian.PutUint16(data2, provider.ID.Data2) + data3 := make([]byte, 2) + binary.BigEndian.PutUint16(data3, provider.ID.Data3) + return fmt.Sprintf( + "%s-%s-%s-%s-%s", + hex.EncodeToString(data1), + hex.EncodeToString(data2), + hex.EncodeToString(data3), + hex.EncodeToString(provider.ID.Data4[:2]), + hex.EncodeToString(provider.ID.Data4[2:])) +} + +type providerHandle windows.Handle + +// ProviderState informs the provider EnableCallback what action is being +// performed. +type ProviderState uint32 + +const ( + // ProviderStateDisable indicates the provider is being disabled. + ProviderStateDisable ProviderState = iota + // ProviderStateEnable indicates the provider is being enabled. + ProviderStateEnable + // ProviderStateCaptureState indicates the provider is having its current + // state snap-shotted. + ProviderStateCaptureState +) + +// EnableCallback is the form of the callback function that receives provider +// enable/disable notifications from ETW. +type EnableCallback func(*windows.GUID, ProviderState, Level, uint64, uint64, uintptr) + +func providerCallback(sourceID *windows.GUID, state ProviderState, level Level, matchAnyKeyword uint64, matchAllKeyword uint64, filterData uintptr, i uintptr) { + provider := providers.getProvider(uint(i)) + + switch state { + case ProviderStateDisable: + provider.enabled = false + case ProviderStateEnable: + provider.enabled = true + provider.level = level + provider.keywordAny = matchAnyKeyword + provider.keywordAll = matchAllKeyword + } + + if provider.callback != nil { + provider.callback(sourceID, state, level, matchAnyKeyword, matchAllKeyword, filterData) + } +} + +// providerCallbackAdapter acts as the first-level callback from the C/ETW side +// for provider notifications. Because Go has trouble with callback arguments of +// different size, it has only pointer-sized arguments, which are then cast to +// the appropriate types when calling providerCallback. +func providerCallbackAdapter(sourceID *windows.GUID, state uintptr, level uintptr, matchAnyKeyword uintptr, matchAllKeyword uintptr, filterData uintptr, i uintptr) uintptr { + providerCallback(sourceID, ProviderState(state), Level(level), uint64(matchAnyKeyword), uint64(matchAllKeyword), filterData, i) + return 0 +} + +// providerIDFromName generates a provider ID based on the provider name. It +// uses the same algorithm as used by .NET's EventSource class, which is based +// on RFC 4122. More information on the algorithm can be found here: +// https://blogs.msdn.microsoft.com/dcook/2015/09/08/etw-provider-names-and-guids/ +// The algorithm is roughly: +// Hash = Sha1(namespace + arg.ToUpper().ToUtf16be()) +// Guid = Hash[0..15], with Hash[7] tweaked according to RFC 4122 +func providerIDFromName(name string) *windows.GUID { + buffer := sha1.New() + + namespace := []byte{0x48, 0x2C, 0x2D, 0xB2, 0xC3, 0x90, 0x47, 0xC8, 0x87, 0xF8, 0x1A, 0x15, 0xBF, 0xC1, 0x30, 0xFB} + buffer.Write(namespace) + + binary.Write(buffer, binary.BigEndian, utf16.Encode([]rune(strings.ToUpper(name)))) + + sum := buffer.Sum(nil) + sum[7] = (sum[7] & 0xf) | 0x50 + + return &windows.GUID{ + Data1: binary.LittleEndian.Uint32(sum[0:4]), + Data2: binary.LittleEndian.Uint16(sum[4:6]), + Data3: binary.LittleEndian.Uint16(sum[6:8]), + Data4: [8]byte{sum[8], sum[9], sum[10], sum[11], sum[12], sum[13], sum[14], sum[15]}, + } +} + +// NewProvider creates and registers a new ETW provider. The provider ID is +// generated based on the provider name. +func NewProvider(name string, callback EnableCallback) (provider *Provider, err error) { + return NewProviderWithID(name, providerIDFromName(name), callback) +} + +// NewProviderWithID creates and registers a new ETW provider, allowing the +// provider ID to be manually specified. This is most useful when there is an +// existing provider ID that must be used to conform to existing diagnostic +// infrastructure. +func NewProviderWithID(name string, id *windows.GUID, callback EnableCallback) (provider *Provider, err error) { + providerCallbackOnce.Do(func() { + globalProviderCallback = windows.NewCallback(providerCallbackAdapter) + }) + + provider = providers.newProvider() + defer func() { + if err != nil { + providers.removeProvider(provider) + } + }() + provider.ID = id + provider.callback = callback + + if err := eventRegister(provider.ID, globalProviderCallback, uintptr(provider.index), &provider.handle); err != nil { + return nil, err + } + + metadata := &bytes.Buffer{} + binary.Write(metadata, binary.LittleEndian, uint16(0)) // Write empty size for buffer (to update later) + metadata.WriteString(name) + metadata.WriteByte(0) // Null terminator for name + binary.LittleEndian.PutUint16(metadata.Bytes(), uint16(metadata.Len())) // Update the size at the beginning of the buffer + provider.metadata = metadata.Bytes() + + return provider, nil +} + +// Close unregisters the provider. +func (provider *Provider) Close() error { + providers.removeProvider(provider) + return eventUnregister(provider.handle) +} + +// IsEnabled calls IsEnabledForLevelAndKeywords with LevelAlways and all +// keywords set. +func (provider *Provider) IsEnabled() bool { + return provider.IsEnabledForLevelAndKeywords(LevelAlways, ^uint64(0)) +} + +// IsEnabledForLevel calls IsEnabledForLevelAndKeywords with the specified level +// and all keywords set. +func (provider *Provider) IsEnabledForLevel(level Level) bool { + return provider.IsEnabledForLevelAndKeywords(level, ^uint64(0)) +} + +// IsEnabledForLevelAndKeywords allows event producer code to check if there are +// any event sessions that are interested in an event, based on the event level +// and keywords. Although this check happens automatically in the ETW +// infrastructure, it can be useful to check if an event will actually be +// consumed before doing expensive work to build the event data. +func (provider *Provider) IsEnabledForLevelAndKeywords(level Level, keywords uint64) bool { + if !provider.enabled { + return false + } + + // ETW automatically sets the level to 255 if it is specified as 0, so we + // don't need to worry about the level=0 (all events) case. + if level > provider.level { + return false + } + + if keywords != 0 && (keywords&provider.keywordAny == 0 || keywords&provider.keywordAll != provider.keywordAll) { + return false + } + + return true +} + +// WriteEvent writes a single ETW event from the provider. The event is +// constructed based on the EventOpt and FieldOpt values that are passed as +// opts. +func (provider *Provider) WriteEvent(name string, eventOpts []EventOpt, fieldOpts []FieldOpt) error { + options := eventOptions{descriptor: NewEventDescriptor()} + em := &EventMetadata{} + ed := &EventData{} + + // We need to evaluate the EventOpts first since they might change tags, and + // we write out the tags before evaluating FieldOpts. + for _, opt := range eventOpts { + opt(&options) + } + + if !provider.IsEnabledForLevelAndKeywords(options.descriptor.Level, options.descriptor.Keyword) { + return nil + } + + em.WriteEventHeader(name, options.tags) + + for _, opt := range fieldOpts { + opt(em, ed) + } + + // Don't pass a data blob if there is no event data. There will always be + // event metadata (e.g. for the name) so we don't need to do this check for + // the metadata. + dataBlobs := [][]byte{} + if len(ed.Bytes()) > 0 { + dataBlobs = [][]byte{ed.Bytes()} + } + + return provider.WriteEventRaw(options.descriptor, nil, nil, [][]byte{em.Bytes()}, dataBlobs) +} + +// WriteEventRaw writes a single ETW event from the provider. This function is +// less abstracted than WriteEvent, and presents a fairly direct interface to +// the event writing functionality. It expects a series of event metadata and +// event data blobs to be passed in, which must conform to the TraceLogging +// schema. The functions on EventMetadata and EventData can help with creating +// these blobs. The blobs of each type are effectively concatenated together by +// the ETW infrastructure. +func (provider *Provider) WriteEventRaw( + descriptor *EventDescriptor, + activityID *windows.GUID, + relatedActivityID *windows.GUID, + metadataBlobs [][]byte, + dataBlobs [][]byte) error { + + dataDescriptorCount := uint32(1 + len(metadataBlobs) + len(dataBlobs)) + dataDescriptors := make([]eventDataDescriptor, 0, dataDescriptorCount) + + dataDescriptors = append(dataDescriptors, newEventDataDescriptor(eventDataDescriptorTypeProviderMetadata, provider.metadata)) + for _, blob := range metadataBlobs { + dataDescriptors = append(dataDescriptors, newEventDataDescriptor(eventDataDescriptorTypeEventMetadata, blob)) + } + for _, blob := range dataBlobs { + dataDescriptors = append(dataDescriptors, newEventDataDescriptor(eventDataDescriptorTypeUserData, blob)) + } + + return eventWriteTransfer(provider.handle, descriptor, activityID, relatedActivityID, dataDescriptorCount, &dataDescriptors[0]) +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/internal/etw/providerglobal.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/internal/etw/providerglobal.go new file mode 100644 index 0000000000..28177a1fd5 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/internal/etw/providerglobal.go @@ -0,0 +1,52 @@ +package etw + +import ( + "sync" +) + +// Because the provider callback function needs to be able to access the +// provider data when it is invoked by ETW, we need to keep provider data stored +// in a global map based on an index. The index is passed as the callback +// context to ETW. +type providerMap struct { + m map[uint]*Provider + i uint + lock sync.Mutex + once sync.Once +} + +var providers = providerMap{ + m: make(map[uint]*Provider), +} + +func (p *providerMap) newProvider() *Provider { + p.lock.Lock() + defer p.lock.Unlock() + + i := p.i + p.i++ + + provider := &Provider{ + index: i, + } + + p.m[i] = provider + return provider +} + +func (p *providerMap) removeProvider(provider *Provider) { + p.lock.Lock() + defer p.lock.Unlock() + + delete(p.m, provider.index) +} + +func (p *providerMap) getProvider(index uint) *Provider { + p.lock.Lock() + defer p.lock.Unlock() + + return p.m[index] +} + +var providerCallbackOnce sync.Once +var globalProviderCallback uintptr diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/internal/etw/ptr64_32.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/internal/etw/ptr64_32.go new file mode 100644 index 0000000000..435ec3c01d --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/internal/etw/ptr64_32.go @@ -0,0 +1,16 @@ +// +build 386 arm + +package etw + +import ( + "unsafe" +) + +// byteptr64 defines a struct containing a pointer. The struct is guaranteed to +// be 64 bits, regardless of the actual size of a pointer on the platform. This +// is intended for use with certain Windows APIs that expect a pointer as a +// ULONGLONG. +type ptr64 struct { + ptr unsafe.Pointer + _ uint32 +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/internal/etw/ptr64_64.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/internal/etw/ptr64_64.go new file mode 100644 index 0000000000..903d3c0a7a --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/internal/etw/ptr64_64.go @@ -0,0 +1,15 @@ +// +build amd64 arm64 + +package etw + +import ( + "unsafe" +) + +// byteptr64 defines a struct containing a pointer. The struct is guaranteed to +// be 64 bits, regardless of the actual size of a pointer on the platform. This +// is intended for use with certain Windows APIs that expect a pointer as a +// ULONGLONG. +type ptr64 struct { + ptr unsafe.Pointer +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/internal/etw/zsyscall_windows.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/internal/etw/zsyscall_windows.go new file mode 100644 index 0000000000..5b044ca451 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/internal/etw/zsyscall_windows.go @@ -0,0 +1,69 @@ +// Code generated by 'go generate'; DO NOT EDIT. + +package etw + +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 ( + modadvapi32 = windows.NewLazySystemDLL("advapi32.dll") + + procEventRegister = modadvapi32.NewProc("EventRegister") + procEventUnregister = modadvapi32.NewProc("EventUnregister") + procEventWriteTransfer = modadvapi32.NewProc("EventWriteTransfer") +) + +func eventRegister(providerId *windows.GUID, callback uintptr, callbackContext uintptr, providerHandle *providerHandle) (win32err error) { + r0, _, _ := syscall.Syscall6(procEventRegister.Addr(), 4, uintptr(unsafe.Pointer(providerId)), uintptr(callback), uintptr(callbackContext), uintptr(unsafe.Pointer(providerHandle)), 0, 0) + if r0 != 0 { + win32err = syscall.Errno(r0) + } + return +} + +func eventUnregister(providerHandle providerHandle) (win32err error) { + r0, _, _ := syscall.Syscall(procEventUnregister.Addr(), 1, uintptr(providerHandle), 0, 0) + if r0 != 0 { + win32err = syscall.Errno(r0) + } + return +} + +func eventWriteTransfer(providerHandle providerHandle, descriptor *EventDescriptor, activityID *windows.GUID, relatedActivityID *windows.GUID, dataDescriptorCount uint32, dataDescriptors *eventDataDescriptor) (win32err error) { + r0, _, _ := syscall.Syscall6(procEventWriteTransfer.Addr(), 6, uintptr(providerHandle), uintptr(unsafe.Pointer(descriptor)), uintptr(unsafe.Pointer(activityID)), uintptr(unsafe.Pointer(relatedActivityID)), uintptr(dataDescriptorCount), uintptr(unsafe.Pointer(dataDescriptors))) + if r0 != 0 { + win32err = syscall.Errno(r0) + } + return +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/pipe.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/pipe.go new file mode 100644 index 0000000000..d99eedb648 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/pipe.go @@ -0,0 +1,421 @@ +// +build windows + +package winio + +import ( + "errors" + "io" + "net" + "os" + "syscall" + "time" + "unsafe" +) + +//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 + +const ( + cERROR_PIPE_BUSY = syscall.Errno(231) + cERROR_NO_DATA = syscall.Errno(232) + cERROR_PIPE_CONNECTED = syscall.Errno(535) + cERROR_SEM_TIMEOUT = syscall.Errno(121) + + cPIPE_ACCESS_DUPLEX = 0x3 + cFILE_FLAG_FIRST_PIPE_INSTANCE = 0x80000 + cSECURITY_SQOS_PRESENT = 0x100000 + cSECURITY_ANONYMOUS = 0 + + cPIPE_REJECT_REMOTE_CLIENTS = 0x8 + + cPIPE_UNLIMITED_INSTANCES = 255 + + cNMPWAIT_USE_DEFAULT_WAIT = 0 + cNMPWAIT_NOWAIT = 1 + + cPIPE_TYPE_MESSAGE = 4 + + cPIPE_READMODE_MESSAGE = 2 +) + +var ( + // ErrPipeListenerClosed is returned for pipe operations on listeners that have been closed. + // This error should match net.errClosing since docker takes a dependency on its text. + ErrPipeListenerClosed = errors.New("use of closed network connection") + + errPipeWriteClosed = errors.New("pipe has been closed for write") +) + +type win32Pipe struct { + *win32File + path string +} + +type win32MessageBytePipe struct { + win32Pipe + writeClosed bool + readEOF bool +} + +type pipeAddress string + +func (f *win32Pipe) LocalAddr() net.Addr { + return pipeAddress(f.path) +} + +func (f *win32Pipe) RemoteAddr() net.Addr { + return pipeAddress(f.path) +} + +func (f *win32Pipe) SetDeadline(t time.Time) error { + f.SetReadDeadline(t) + f.SetWriteDeadline(t) + return nil +} + +// CloseWrite closes the write side of a message pipe in byte mode. +func (f *win32MessageBytePipe) CloseWrite() error { + if f.writeClosed { + return errPipeWriteClosed + } + err := f.win32File.Flush() + if err != nil { + return err + } + _, err = f.win32File.Write(nil) + if err != nil { + return err + } + f.writeClosed = true + return nil +} + +// Write writes bytes to a message pipe in byte mode. Zero-byte writes are ignored, since +// they are used to implement CloseWrite(). +func (f *win32MessageBytePipe) Write(b []byte) (int, error) { + if f.writeClosed { + return 0, errPipeWriteClosed + } + if len(b) == 0 { + return 0, nil + } + return f.win32File.Write(b) +} + +// Read reads bytes from a message pipe in byte mode. A read of a zero-byte message on a message +// mode pipe will return io.EOF, as will all subsequent reads. +func (f *win32MessageBytePipe) Read(b []byte) (int, error) { + if f.readEOF { + return 0, io.EOF + } + n, err := f.win32File.Read(b) + if err == io.EOF { + // If this was the result of a zero-byte read, then + // it is possible that the read was due to a zero-size + // message. Since we are simulating CloseWrite with a + // zero-byte message, ensure that all future Read() calls + // also return EOF. + f.readEOF = true + } else if err == syscall.ERROR_MORE_DATA { + // ERROR_MORE_DATA indicates that the pipe's read mode is message mode + // and the message still has more bytes. Treat this as a success, since + // this package presents all named pipes as byte streams. + err = nil + } + return n, err +} + +func (s pipeAddress) Network() string { + return "pipe" +} + +func (s pipeAddress) String() string { + return string(s) +} + +// DialPipe connects to a named pipe by path, timing out if the connection +// takes longer than the specified duration. If timeout is nil, then we use +// a default timeout of 5 seconds. (We do not use WaitNamedPipe.) +func DialPipe(path string, timeout *time.Duration) (net.Conn, error) { + var absTimeout time.Time + if timeout != nil { + absTimeout = time.Now().Add(*timeout) + } else { + absTimeout = time.Now().Add(time.Second * 2) + } + var err error + var h syscall.Handle + for { + h, err = createFile(path, syscall.GENERIC_READ|syscall.GENERIC_WRITE, 0, nil, syscall.OPEN_EXISTING, syscall.FILE_FLAG_OVERLAPPED|cSECURITY_SQOS_PRESENT|cSECURITY_ANONYMOUS, 0) + if err != cERROR_PIPE_BUSY { + break + } + if time.Now().After(absTimeout) { + return nil, ErrTimeout + } + + // Wait 10 msec and try again. This is a rather simplistic + // view, as we always try each 10 milliseconds. + time.Sleep(time.Millisecond * 10) + } + if err != nil { + return nil, &os.PathError{Op: "open", Path: path, Err: err} + } + + var flags uint32 + err = getNamedPipeInfo(h, &flags, nil, nil, nil) + if err != nil { + return nil, err + } + + f, err := makeWin32File(h) + if err != nil { + syscall.Close(h) + return nil, err + } + + // If the pipe is in message mode, return a message byte pipe, which + // supports CloseWrite(). + if flags&cPIPE_TYPE_MESSAGE != 0 { + return &win32MessageBytePipe{ + win32Pipe: win32Pipe{win32File: f, path: path}, + }, nil + } + return &win32Pipe{win32File: f, path: path}, nil +} + +type acceptResponse struct { + f *win32File + err error +} + +type win32PipeListener struct { + firstHandle syscall.Handle + path string + securityDescriptor []byte + config PipeConfig + acceptCh chan (chan acceptResponse) + closeCh chan int + doneCh chan int +} + +func makeServerPipeHandle(path string, securityDescriptor []byte, c *PipeConfig, first bool) (syscall.Handle, error) { + var flags uint32 = cPIPE_ACCESS_DUPLEX | syscall.FILE_FLAG_OVERLAPPED + if first { + flags |= cFILE_FLAG_FIRST_PIPE_INSTANCE + } + + var mode uint32 = cPIPE_REJECT_REMOTE_CLIENTS + if c.MessageMode { + mode |= cPIPE_TYPE_MESSAGE + } + + sa := &syscall.SecurityAttributes{} + sa.Length = uint32(unsafe.Sizeof(*sa)) + if securityDescriptor != nil { + len := uint32(len(securityDescriptor)) + sa.SecurityDescriptor = localAlloc(0, len) + defer localFree(sa.SecurityDescriptor) + copy((*[0xffff]byte)(unsafe.Pointer(sa.SecurityDescriptor))[:], securityDescriptor) + } + h, err := createNamedPipe(path, flags, mode, cPIPE_UNLIMITED_INSTANCES, uint32(c.OutputBufferSize), uint32(c.InputBufferSize), 0, sa) + if err != nil { + return 0, &os.PathError{Op: "open", Path: path, Err: err} + } + return h, nil +} + +func (l *win32PipeListener) makeServerPipe() (*win32File, error) { + h, err := makeServerPipeHandle(l.path, l.securityDescriptor, &l.config, false) + if err != nil { + return nil, err + } + f, err := makeWin32File(h) + if err != nil { + syscall.Close(h) + return nil, err + } + return f, nil +} + +func (l *win32PipeListener) makeConnectedServerPipe() (*win32File, error) { + p, err := l.makeServerPipe() + if err != nil { + return nil, err + } + + // Wait for the client to connect. + ch := make(chan error) + go func(p *win32File) { + ch <- connectPipe(p) + }(p) + + select { + case err = <-ch: + if err != nil { + p.Close() + p = nil + } + case <-l.closeCh: + // Abort the connect request by closing the handle. + p.Close() + p = nil + err = <-ch + if err == nil || err == ErrFileClosed { + err = ErrPipeListenerClosed + } + } + return p, err +} + +func (l *win32PipeListener) listenerRoutine() { + closed := false + for !closed { + select { + case <-l.closeCh: + closed = true + case responseCh := <-l.acceptCh: + var ( + p *win32File + err error + ) + for { + p, err = l.makeConnectedServerPipe() + // If the connection was immediately closed by the client, try + // again. + if err != cERROR_NO_DATA { + break + } + } + responseCh <- acceptResponse{p, err} + closed = err == ErrPipeListenerClosed + } + } + syscall.Close(l.firstHandle) + l.firstHandle = 0 + // Notify Close() and Accept() callers that the handle has been closed. + close(l.doneCh) +} + +// PipeConfig contain configuration for the pipe listener. +type PipeConfig struct { + // SecurityDescriptor contains a Windows security descriptor in SDDL format. + SecurityDescriptor string + + // MessageMode determines whether the pipe is in byte or message mode. In either + // case the pipe is read in byte mode by default. The only practical difference in + // this implementation is that CloseWrite() is only supported for message mode pipes; + // CloseWrite() is implemented as a zero-byte write, but zero-byte writes are only + // transferred to the reader (and returned as io.EOF in this implementation) + // when the pipe is in message mode. + MessageMode bool + + // InputBufferSize specifies the size the input buffer, in bytes. + InputBufferSize int32 + + // OutputBufferSize specifies the size the input buffer, in bytes. + OutputBufferSize int32 +} + +// ListenPipe creates a listener on a Windows named pipe path, e.g. \\.\pipe\mypipe. +// The pipe must not already exist. +func ListenPipe(path string, c *PipeConfig) (net.Listener, error) { + var ( + sd []byte + err error + ) + if c == nil { + c = &PipeConfig{} + } + if c.SecurityDescriptor != "" { + sd, err = SddlToSecurityDescriptor(c.SecurityDescriptor) + if err != nil { + return nil, err + } + } + h, err := makeServerPipeHandle(path, sd, c, true) + if err != nil { + return nil, err + } + // Create a client handle and connect it. This results in the pipe + // instance always existing, so that clients see ERROR_PIPE_BUSY + // rather than ERROR_FILE_NOT_FOUND. This ties the first instance + // up so that no other instances can be used. This would have been + // cleaner if the Win32 API matched CreateFile with ConnectNamedPipe + // instead of CreateNamedPipe. (Apparently created named pipes are + // considered to be in listening state regardless of whether any + // active calls to ConnectNamedPipe are outstanding.) + h2, err := createFile(path, 0, 0, nil, syscall.OPEN_EXISTING, cSECURITY_SQOS_PRESENT|cSECURITY_ANONYMOUS, 0) + if err != nil { + syscall.Close(h) + return nil, err + } + // Close the client handle. The server side of the instance will + // still be busy, leading to ERROR_PIPE_BUSY instead of + // ERROR_NOT_FOUND, as long as we don't close the server handle, + // or disconnect the client with DisconnectNamedPipe. + syscall.Close(h2) + l := &win32PipeListener{ + firstHandle: h, + path: path, + securityDescriptor: sd, + config: *c, + acceptCh: make(chan (chan acceptResponse)), + closeCh: make(chan int), + doneCh: make(chan int), + } + go l.listenerRoutine() + return l, nil +} + +func connectPipe(p *win32File) error { + c, err := p.prepareIo() + if err != nil { + return err + } + defer p.wg.Done() + + err = connectNamedPipe(p.handle, &c.o) + _, err = p.asyncIo(c, nil, 0, err) + if err != nil && err != cERROR_PIPE_CONNECTED { + return err + } + return nil +} + +func (l *win32PipeListener) Accept() (net.Conn, error) { + ch := make(chan acceptResponse) + select { + case l.acceptCh <- ch: + response := <-ch + err := response.err + if err != nil { + return nil, err + } + if l.config.MessageMode { + return &win32MessageBytePipe{ + win32Pipe: win32Pipe{win32File: response.f, path: l.path}, + }, nil + } + return &win32Pipe{win32File: response.f, path: l.path}, nil + case <-l.doneCh: + return nil, ErrPipeListenerClosed + } +} + +func (l *win32PipeListener) Close() error { + select { + case l.closeCh <- 1: + <-l.doneCh + case <-l.doneCh: + } + return nil +} + +func (l *win32PipeListener) Addr() net.Addr { + return pipeAddress(l.path) +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/pkg/etwlogrus/hook.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/pkg/etwlogrus/hook.go new file mode 100644 index 0000000000..d3d5713b8e --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/pkg/etwlogrus/hook.go @@ -0,0 +1,192 @@ +package etwlogrus + +import ( + "fmt" + "reflect" + + "github.com/Microsoft/go-winio/internal/etw" + "github.com/sirupsen/logrus" +) + +// Hook is a Logrus hook which logs received events to ETW. +type Hook struct { + provider *etw.Provider +} + +// NewHook registers a new ETW provider and returns a hook to log from it. +func NewHook(providerName string) (*Hook, error) { + hook := Hook{} + + provider, err := etw.NewProvider(providerName, nil) + if err != nil { + return nil, err + } + hook.provider = provider + + return &hook, nil +} + +// Levels returns the set of levels that this hook wants to receive log entries +// for. +func (h *Hook) Levels() []logrus.Level { + return []logrus.Level{ + logrus.TraceLevel, + logrus.DebugLevel, + logrus.InfoLevel, + logrus.WarnLevel, + logrus.ErrorLevel, + logrus.FatalLevel, + logrus.PanicLevel, + } +} + +// Fire receives each Logrus entry as it is logged, and logs it to ETW. +func (h *Hook) Fire(e *logrus.Entry) error { + level := etw.Level(e.Level) + if !h.provider.IsEnabledForLevel(level) { + return nil + } + + // Reserve extra space for the message field. + fields := make([]etw.FieldOpt, 0, len(e.Data)+1) + + fields = append(fields, etw.StringField("Message", e.Message)) + + for k, v := range e.Data { + fields = append(fields, getFieldOpt(k, v)) + } + + // We could try to map Logrus levels to ETW levels, but we would lose some + // fidelity as there are fewer ETW levels. So instead we use the level + // directly. + return h.provider.WriteEvent( + "LogrusEntry", + etw.WithEventOpts(etw.WithLevel(level)), + fields) +} + +// Currently, we support logging basic builtin types (int, string, etc), slices +// of basic builtin types, error, types derived from the basic types (e.g. "type +// foo int"), and structs (recursively logging their fields). We do not support +// slices of derived types (e.g. "[]foo"). +// +// For types that we don't support, the value is formatted via fmt.Sprint, and +// we also log a message that the type is unsupported along with the formatted +// type. The intent of this is to make it easier to see which types are not +// supported in traces, so we can evaluate adding support for more types in the +// future. +func getFieldOpt(k string, v interface{}) etw.FieldOpt { + switch v := v.(type) { + case bool: + return etw.BoolField(k, v) + case []bool: + return etw.BoolArray(k, v) + case string: + return etw.StringField(k, v) + case []string: + return etw.StringArray(k, v) + case int: + return etw.IntField(k, v) + case []int: + return etw.IntArray(k, v) + case int8: + return etw.Int8Field(k, v) + case []int8: + return etw.Int8Array(k, v) + case int16: + return etw.Int16Field(k, v) + case []int16: + return etw.Int16Array(k, v) + case int32: + return etw.Int32Field(k, v) + case []int32: + return etw.Int32Array(k, v) + case int64: + return etw.Int64Field(k, v) + case []int64: + return etw.Int64Array(k, v) + case uint: + return etw.UintField(k, v) + case []uint: + return etw.UintArray(k, v) + case uint8: + return etw.Uint8Field(k, v) + case []uint8: + return etw.Uint8Array(k, v) + case uint16: + return etw.Uint16Field(k, v) + case []uint16: + return etw.Uint16Array(k, v) + case uint32: + return etw.Uint32Field(k, v) + case []uint32: + return etw.Uint32Array(k, v) + case uint64: + return etw.Uint64Field(k, v) + case []uint64: + return etw.Uint64Array(k, v) + case uintptr: + return etw.UintptrField(k, v) + case []uintptr: + return etw.UintptrArray(k, v) + case float32: + return etw.Float32Field(k, v) + case []float32: + return etw.Float32Array(k, v) + case float64: + return etw.Float64Field(k, v) + case []float64: + return etw.Float64Array(k, v) + case error: + return etw.StringField(k, v.Error()) + default: + switch rv := reflect.ValueOf(v); rv.Kind() { + case reflect.Bool: + return getFieldOpt(k, rv.Bool()) + case reflect.Int: + return getFieldOpt(k, int(rv.Int())) + case reflect.Int8: + return getFieldOpt(k, int8(rv.Int())) + case reflect.Int16: + return getFieldOpt(k, int16(rv.Int())) + case reflect.Int32: + return getFieldOpt(k, int32(rv.Int())) + case reflect.Int64: + return getFieldOpt(k, int64(rv.Int())) + case reflect.Uint: + return getFieldOpt(k, uint(rv.Uint())) + case reflect.Uint8: + return getFieldOpt(k, uint8(rv.Uint())) + case reflect.Uint16: + return getFieldOpt(k, uint16(rv.Uint())) + case reflect.Uint32: + return getFieldOpt(k, uint32(rv.Uint())) + case reflect.Uint64: + return getFieldOpt(k, uint64(rv.Uint())) + case reflect.Uintptr: + return getFieldOpt(k, uintptr(rv.Uint())) + case reflect.Float32: + return getFieldOpt(k, float32(rv.Float())) + case reflect.Float64: + return getFieldOpt(k, float64(rv.Float())) + case reflect.String: + return getFieldOpt(k, rv.String()) + case reflect.Struct: + fields := make([]etw.FieldOpt, 0, rv.NumField()) + for i := 0; i < rv.NumField(); i++ { + field := rv.Field(i) + if field.CanInterface() { + fields = append(fields, getFieldOpt(k, field.Interface())) + } + } + return etw.Struct(k, fields...) + } + } + + return etw.StringField(k, fmt.Sprintf("(Unsupported: %T) %v", v, v)) +} + +// Close cleans up the hook and closes the ETW provider. +func (h *Hook) Close() error { + return h.provider.Close() +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/privilege.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/privilege.go new file mode 100644 index 0000000000..9c83d36fe5 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/privilege.go @@ -0,0 +1,202 @@ +// +build windows + +package winio + +import ( + "bytes" + "encoding/binary" + "fmt" + "runtime" + "sync" + "syscall" + "unicode/utf16" + + "golang.org/x/sys/windows" +) + +//sys adjustTokenPrivileges(token windows.Token, releaseAll bool, input *byte, outputSize uint32, output *byte, requiredSize *uint32) (success bool, err error) [true] = advapi32.AdjustTokenPrivileges +//sys impersonateSelf(level uint32) (err error) = advapi32.ImpersonateSelf +//sys revertToSelf() (err error) = advapi32.RevertToSelf +//sys openThreadToken(thread syscall.Handle, accessMask uint32, openAsSelf bool, token *windows.Token) (err error) = advapi32.OpenThreadToken +//sys getCurrentThread() (h syscall.Handle) = GetCurrentThread +//sys lookupPrivilegeValue(systemName string, name string, luid *uint64) (err error) = advapi32.LookupPrivilegeValueW +//sys lookupPrivilegeName(systemName string, luid *uint64, buffer *uint16, size *uint32) (err error) = advapi32.LookupPrivilegeNameW +//sys lookupPrivilegeDisplayName(systemName string, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) = advapi32.LookupPrivilegeDisplayNameW + +const ( + SE_PRIVILEGE_ENABLED = 2 + + ERROR_NOT_ALL_ASSIGNED syscall.Errno = 1300 + + SeBackupPrivilege = "SeBackupPrivilege" + SeRestorePrivilege = "SeRestorePrivilege" +) + +const ( + securityAnonymous = iota + securityIdentification + securityImpersonation + securityDelegation +) + +var ( + privNames = make(map[string]uint64) + privNameMutex sync.Mutex +) + +// PrivilegeError represents an error enabling privileges. +type PrivilegeError struct { + privileges []uint64 +} + +func (e *PrivilegeError) Error() string { + s := "" + if len(e.privileges) > 1 { + s = "Could not enable privileges " + } else { + s = "Could not enable privilege " + } + for i, p := range e.privileges { + if i != 0 { + s += ", " + } + s += `"` + s += getPrivilegeName(p) + s += `"` + } + return s +} + +// RunWithPrivilege enables a single privilege for a function call. +func RunWithPrivilege(name string, fn func() error) error { + return RunWithPrivileges([]string{name}, fn) +} + +// RunWithPrivileges enables privileges for a function call. +func RunWithPrivileges(names []string, fn func() error) error { + privileges, err := mapPrivileges(names) + if err != nil { + return err + } + runtime.LockOSThread() + defer runtime.UnlockOSThread() + token, err := newThreadToken() + if err != nil { + return err + } + defer releaseThreadToken(token) + err = adjustPrivileges(token, privileges, SE_PRIVILEGE_ENABLED) + if err != nil { + return err + } + return fn() +} + +func mapPrivileges(names []string) ([]uint64, error) { + var privileges []uint64 + privNameMutex.Lock() + defer privNameMutex.Unlock() + for _, name := range names { + p, ok := privNames[name] + if !ok { + err := lookupPrivilegeValue("", name, &p) + if err != nil { + return nil, err + } + privNames[name] = p + } + privileges = append(privileges, p) + } + return privileges, nil +} + +// EnableProcessPrivileges enables privileges globally for the process. +func EnableProcessPrivileges(names []string) error { + return enableDisableProcessPrivilege(names, SE_PRIVILEGE_ENABLED) +} + +// DisableProcessPrivileges disables privileges globally for the process. +func DisableProcessPrivileges(names []string) error { + return enableDisableProcessPrivilege(names, 0) +} + +func enableDisableProcessPrivilege(names []string, action uint32) error { + privileges, err := mapPrivileges(names) + if err != nil { + return err + } + + p, _ := windows.GetCurrentProcess() + var token windows.Token + err = windows.OpenProcessToken(p, windows.TOKEN_ADJUST_PRIVILEGES|windows.TOKEN_QUERY, &token) + if err != nil { + return err + } + + defer token.Close() + return adjustPrivileges(token, privileges, action) +} + +func adjustPrivileges(token windows.Token, privileges []uint64, action uint32) error { + var b bytes.Buffer + binary.Write(&b, binary.LittleEndian, uint32(len(privileges))) + for _, p := range privileges { + binary.Write(&b, binary.LittleEndian, p) + binary.Write(&b, binary.LittleEndian, action) + } + prevState := make([]byte, b.Len()) + reqSize := uint32(0) + success, err := adjustTokenPrivileges(token, false, &b.Bytes()[0], uint32(len(prevState)), &prevState[0], &reqSize) + if !success { + return err + } + if err == ERROR_NOT_ALL_ASSIGNED { + return &PrivilegeError{privileges} + } + return nil +} + +func getPrivilegeName(luid uint64) string { + var nameBuffer [256]uint16 + bufSize := uint32(len(nameBuffer)) + err := lookupPrivilegeName("", &luid, &nameBuffer[0], &bufSize) + if err != nil { + return fmt.Sprintf("", luid) + } + + var displayNameBuffer [256]uint16 + displayBufSize := uint32(len(displayNameBuffer)) + var langID uint32 + err = lookupPrivilegeDisplayName("", &nameBuffer[0], &displayNameBuffer[0], &displayBufSize, &langID) + if err != nil { + return fmt.Sprintf("", string(utf16.Decode(nameBuffer[:bufSize]))) + } + + return string(utf16.Decode(displayNameBuffer[:displayBufSize])) +} + +func newThreadToken() (windows.Token, error) { + err := impersonateSelf(securityImpersonation) + if err != nil { + return 0, err + } + + var token windows.Token + err = openThreadToken(getCurrentThread(), syscall.TOKEN_ADJUST_PRIVILEGES|syscall.TOKEN_QUERY, false, &token) + if err != nil { + rerr := revertToSelf() + if rerr != nil { + panic(rerr) + } + return 0, err + } + return token, nil +} + +func releaseThreadToken(h windows.Token) { + err := revertToSelf() + if err != nil { + panic(err) + } + h.Close() +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/reparse.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/reparse.go new file mode 100644 index 0000000000..fc1ee4d3a3 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/reparse.go @@ -0,0 +1,128 @@ +package winio + +import ( + "bytes" + "encoding/binary" + "fmt" + "strings" + "unicode/utf16" + "unsafe" +) + +const ( + reparseTagMountPoint = 0xA0000003 + reparseTagSymlink = 0xA000000C +) + +type reparseDataBuffer struct { + ReparseTag uint32 + ReparseDataLength uint16 + Reserved uint16 + SubstituteNameOffset uint16 + SubstituteNameLength uint16 + PrintNameOffset uint16 + PrintNameLength uint16 +} + +// ReparsePoint describes a Win32 symlink or mount point. +type ReparsePoint struct { + Target string + IsMountPoint bool +} + +// UnsupportedReparsePointError is returned when trying to decode a non-symlink or +// mount point reparse point. +type UnsupportedReparsePointError struct { + Tag uint32 +} + +func (e *UnsupportedReparsePointError) Error() string { + return fmt.Sprintf("unsupported reparse point %x", e.Tag) +} + +// DecodeReparsePoint decodes a Win32 REPARSE_DATA_BUFFER structure containing either a symlink +// or a mount point. +func DecodeReparsePoint(b []byte) (*ReparsePoint, error) { + tag := binary.LittleEndian.Uint32(b[0:4]) + return DecodeReparsePointData(tag, b[8:]) +} + +func DecodeReparsePointData(tag uint32, b []byte) (*ReparsePoint, error) { + isMountPoint := false + switch tag { + case reparseTagMountPoint: + isMountPoint = true + case reparseTagSymlink: + default: + return nil, &UnsupportedReparsePointError{tag} + } + nameOffset := 8 + binary.LittleEndian.Uint16(b[4:6]) + if !isMountPoint { + nameOffset += 4 + } + nameLength := binary.LittleEndian.Uint16(b[6:8]) + name := make([]uint16, nameLength/2) + err := binary.Read(bytes.NewReader(b[nameOffset:nameOffset+nameLength]), binary.LittleEndian, &name) + if err != nil { + return nil, err + } + return &ReparsePoint{string(utf16.Decode(name)), isMountPoint}, nil +} + +func isDriveLetter(c byte) bool { + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') +} + +// EncodeReparsePoint encodes a Win32 REPARSE_DATA_BUFFER structure describing a symlink or +// mount point. +func EncodeReparsePoint(rp *ReparsePoint) []byte { + // Generate an NT path and determine if this is a relative path. + var ntTarget string + relative := false + if strings.HasPrefix(rp.Target, `\\?\`) { + ntTarget = `\??\` + rp.Target[4:] + } else if strings.HasPrefix(rp.Target, `\\`) { + ntTarget = `\??\UNC\` + rp.Target[2:] + } else if len(rp.Target) >= 2 && isDriveLetter(rp.Target[0]) && rp.Target[1] == ':' { + ntTarget = `\??\` + rp.Target + } else { + ntTarget = rp.Target + relative = true + } + + // The paths must be NUL-terminated even though they are counted strings. + target16 := utf16.Encode([]rune(rp.Target + "\x00")) + ntTarget16 := utf16.Encode([]rune(ntTarget + "\x00")) + + size := int(unsafe.Sizeof(reparseDataBuffer{})) - 8 + size += len(ntTarget16)*2 + len(target16)*2 + + tag := uint32(reparseTagMountPoint) + if !rp.IsMountPoint { + tag = reparseTagSymlink + size += 4 // Add room for symlink flags + } + + data := reparseDataBuffer{ + ReparseTag: tag, + ReparseDataLength: uint16(size), + SubstituteNameOffset: 0, + SubstituteNameLength: uint16((len(ntTarget16) - 1) * 2), + PrintNameOffset: uint16(len(ntTarget16) * 2), + PrintNameLength: uint16((len(target16) - 1) * 2), + } + + var b bytes.Buffer + binary.Write(&b, binary.LittleEndian, &data) + if !rp.IsMountPoint { + flags := uint32(0) + if relative { + flags |= 1 + } + binary.Write(&b, binary.LittleEndian, flags) + } + + binary.Write(&b, binary.LittleEndian, ntTarget16) + binary.Write(&b, binary.LittleEndian, target16) + return b.Bytes() +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/sd.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/sd.go new file mode 100644 index 0000000000..db1b370a1b --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/sd.go @@ -0,0 +1,98 @@ +// +build windows + +package winio + +import ( + "syscall" + "unsafe" +) + +//sys lookupAccountName(systemName *uint16, accountName string, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) = advapi32.LookupAccountNameW +//sys convertSidToStringSid(sid *byte, str **uint16) (err error) = advapi32.ConvertSidToStringSidW +//sys convertStringSecurityDescriptorToSecurityDescriptor(str string, revision uint32, sd *uintptr, size *uint32) (err error) = advapi32.ConvertStringSecurityDescriptorToSecurityDescriptorW +//sys convertSecurityDescriptorToStringSecurityDescriptor(sd *byte, revision uint32, secInfo uint32, sddl **uint16, sddlSize *uint32) (err error) = advapi32.ConvertSecurityDescriptorToStringSecurityDescriptorW +//sys localFree(mem uintptr) = LocalFree +//sys getSecurityDescriptorLength(sd uintptr) (len uint32) = advapi32.GetSecurityDescriptorLength + +const ( + cERROR_NONE_MAPPED = syscall.Errno(1332) +) + +type AccountLookupError struct { + Name string + Err error +} + +func (e *AccountLookupError) Error() string { + if e.Name == "" { + return "lookup account: empty account name specified" + } + var s string + switch e.Err { + case cERROR_NONE_MAPPED: + s = "not found" + default: + s = e.Err.Error() + } + return "lookup account " + e.Name + ": " + s +} + +type SddlConversionError struct { + Sddl string + Err error +} + +func (e *SddlConversionError) Error() string { + return "convert " + e.Sddl + ": " + e.Err.Error() +} + +// LookupSidByName looks up the SID of an account by name +func LookupSidByName(name string) (sid string, err error) { + if name == "" { + return "", &AccountLookupError{name, cERROR_NONE_MAPPED} + } + + var sidSize, sidNameUse, refDomainSize uint32 + err = lookupAccountName(nil, name, nil, &sidSize, nil, &refDomainSize, &sidNameUse) + if err != nil && err != syscall.ERROR_INSUFFICIENT_BUFFER { + return "", &AccountLookupError{name, err} + } + sidBuffer := make([]byte, sidSize) + refDomainBuffer := make([]uint16, refDomainSize) + err = lookupAccountName(nil, name, &sidBuffer[0], &sidSize, &refDomainBuffer[0], &refDomainSize, &sidNameUse) + if err != nil { + return "", &AccountLookupError{name, err} + } + var strBuffer *uint16 + err = convertSidToStringSid(&sidBuffer[0], &strBuffer) + if err != nil { + return "", &AccountLookupError{name, err} + } + sid = syscall.UTF16ToString((*[0xffff]uint16)(unsafe.Pointer(strBuffer))[:]) + localFree(uintptr(unsafe.Pointer(strBuffer))) + return sid, nil +} + +func SddlToSecurityDescriptor(sddl string) ([]byte, error) { + var sdBuffer uintptr + err := convertStringSecurityDescriptorToSecurityDescriptor(sddl, 1, &sdBuffer, nil) + if err != nil { + return nil, &SddlConversionError{sddl, err} + } + defer localFree(sdBuffer) + sd := make([]byte, getSecurityDescriptorLength(sdBuffer)) + copy(sd, (*[0xffff]byte)(unsafe.Pointer(sdBuffer))[:len(sd)]) + return sd, nil +} + +func SecurityDescriptorToSddl(sd []byte) (string, error) { + var sddl *uint16 + // The returned string length seems to including an aribtrary number of terminating NULs. + // Don't use it. + err := convertSecurityDescriptorToStringSecurityDescriptor(&sd[0], 1, 0xff, &sddl, nil) + if err != nil { + return "", err + } + defer localFree(uintptr(unsafe.Pointer(sddl))) + return syscall.UTF16ToString((*[0xffff]uint16)(unsafe.Pointer(sddl))[:]), nil +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/syscall.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/syscall.go new file mode 100644 index 0000000000..20d64cf41d --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/syscall.go @@ -0,0 +1,3 @@ +package winio + +//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go file.go pipe.go sd.go fileinfo.go privilege.go backup.go diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/vhd/vhd.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/vhd/vhd.go new file mode 100644 index 0000000000..8fa90e917c --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/vhd/vhd.go @@ -0,0 +1,108 @@ +// +build windows + +package vhd + +import "syscall" + +//go:generate go run mksyscall_windows.go -output zvhd.go vhd.go + +//sys createVirtualDisk(virtualStorageType *virtualStorageType, path string, virtualDiskAccessMask uint32, securityDescriptor *uintptr, flags uint32, providerSpecificFlags uint32, parameters *createVirtualDiskParameters, o *syscall.Overlapped, handle *syscall.Handle) (err error) [failretval != 0] = VirtDisk.CreateVirtualDisk +//sys openVirtualDisk(virtualStorageType *virtualStorageType, path string, virtualDiskAccessMask uint32, flags uint32, parameters *uintptr, handle *syscall.Handle) (err error) [failretval != 0] = VirtDisk.OpenVirtualDisk +//sys detachVirtualDisk(handle syscall.Handle, flags uint32, providerSpecificFlags uint32) (err error) [failretval != 0] = VirtDisk.DetachVirtualDisk + +type virtualStorageType struct { + DeviceID uint32 + VendorID [16]byte +} + +const virtualDiskAccessNONE uint32 = 0 +const virtualDiskAccessATTACHRO uint32 = 65536 +const virtualDiskAccessATTACHRW uint32 = 131072 +const virtualDiskAccessDETACH uint32 = 262144 +const virtualDiskAccessGETINFO uint32 = 524288 +const virtualDiskAccessCREATE uint32 = 1048576 +const virtualDiskAccessMETAOPS uint32 = 2097152 +const virtualDiskAccessREAD uint32 = 851968 +const virtualDiskAccessALL uint32 = 4128768 +const virtualDiskAccessWRITABLE uint32 = 3276800 + +const createVirtualDiskFlagNone uint32 = 0 +const createVirtualDiskFlagFullPhysicalAllocation uint32 = 1 +const createVirtualDiskFlagPreventWritesToSourceDisk uint32 = 2 +const createVirtualDiskFlagDoNotCopyMetadataFromParent uint32 = 4 + +type version2 struct { + UniqueID [16]byte // GUID + MaximumSize uint64 + BlockSizeInBytes uint32 + SectorSizeInBytes uint32 + ParentPath *uint16 // string + SourcePath *uint16 // string + OpenFlags uint32 + ParentVirtualStorageType virtualStorageType + SourceVirtualStorageType virtualStorageType + ResiliencyGUID [16]byte // GUID +} + +type createVirtualDiskParameters struct { + Version uint32 // Must always be set to 2 + Version2 version2 +} + +// CreateVhdx will create a simple vhdx file at the given path using default values. +func CreateVhdx(path string, maxSizeInGb, blockSizeInMb uint32) error { + var defaultType virtualStorageType + + parameters := createVirtualDiskParameters{ + Version: 2, + Version2: version2{ + MaximumSize: uint64(maxSizeInGb) * 1024 * 1024 * 1024, + BlockSizeInBytes: blockSizeInMb * 1024 * 1024, + }, + } + + var handle syscall.Handle + + if err := createVirtualDisk( + &defaultType, + path, + virtualDiskAccessNONE, + nil, + createVirtualDiskFlagNone, + 0, + ¶meters, + nil, + &handle); err != nil { + return err + } + + if err := syscall.CloseHandle(handle); err != nil { + return err + } + + return nil +} + +// DetachVhd detaches a VHD attached at the given path. +func DetachVhd(path string) error { + var ( + defaultType virtualStorageType + handle syscall.Handle + ) + + if err := openVirtualDisk( + &defaultType, + path, + virtualDiskAccessDETACH, + 0, + nil, + &handle); err != nil { + return err + } + defer syscall.CloseHandle(handle) + + if err := detachVirtualDisk(handle, 0, 0); err != nil { + return err + } + return nil +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/vhd/zvhd.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/vhd/zvhd.go new file mode 100644 index 0000000000..73f52596ed --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/vhd/zvhd.go @@ -0,0 +1,99 @@ +// MACHINE GENERATED BY 'go generate' COMMAND; 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) +) + +// 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 ( + modVirtDisk = windows.NewLazySystemDLL("VirtDisk.dll") + + procCreateVirtualDisk = modVirtDisk.NewProc("CreateVirtualDisk") + procOpenVirtualDisk = modVirtDisk.NewProc("OpenVirtualDisk") + procDetachVirtualDisk = modVirtDisk.NewProc("DetachVirtualDisk") +) + +func createVirtualDisk(virtualStorageType *virtualStorageType, path string, virtualDiskAccessMask uint32, securityDescriptor *uintptr, flags uint32, providerSpecificFlags uint32, parameters *createVirtualDiskParameters, o *syscall.Overlapped, handle *syscall.Handle) (err error) { + var _p0 *uint16 + _p0, err = syscall.UTF16PtrFromString(path) + if err != nil { + return + } + return _createVirtualDisk(virtualStorageType, _p0, virtualDiskAccessMask, securityDescriptor, flags, providerSpecificFlags, parameters, o, handle) +} + +func _createVirtualDisk(virtualStorageType *virtualStorageType, path *uint16, virtualDiskAccessMask uint32, securityDescriptor *uintptr, flags uint32, providerSpecificFlags uint32, parameters *createVirtualDiskParameters, o *syscall.Overlapped, handle *syscall.Handle) (err error) { + r1, _, e1 := syscall.Syscall9(procCreateVirtualDisk.Addr(), 9, uintptr(unsafe.Pointer(virtualStorageType)), uintptr(unsafe.Pointer(path)), uintptr(virtualDiskAccessMask), uintptr(unsafe.Pointer(securityDescriptor)), uintptr(flags), uintptr(providerSpecificFlags), uintptr(unsafe.Pointer(parameters)), uintptr(unsafe.Pointer(o)), uintptr(unsafe.Pointer(handle))) + if r1 != 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func openVirtualDisk(virtualStorageType *virtualStorageType, path string, virtualDiskAccessMask uint32, flags uint32, parameters *uintptr, handle *syscall.Handle) (err error) { + var _p0 *uint16 + _p0, err = syscall.UTF16PtrFromString(path) + if err != nil { + return + } + return _openVirtualDisk(virtualStorageType, _p0, virtualDiskAccessMask, flags, parameters, handle) +} + +func _openVirtualDisk(virtualStorageType *virtualStorageType, path *uint16, virtualDiskAccessMask uint32, flags uint32, parameters *uintptr, handle *syscall.Handle) (err error) { + r1, _, e1 := syscall.Syscall6(procOpenVirtualDisk.Addr(), 6, uintptr(unsafe.Pointer(virtualStorageType)), uintptr(unsafe.Pointer(path)), uintptr(virtualDiskAccessMask), uintptr(flags), uintptr(unsafe.Pointer(parameters)), uintptr(unsafe.Pointer(handle))) + if r1 != 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func detachVirtualDisk(handle syscall.Handle, flags uint32, providerSpecificFlags uint32) (err error) { + r1, _, e1 := syscall.Syscall(procDetachVirtualDisk.Addr(), 3, uintptr(handle), uintptr(flags), uintptr(providerSpecificFlags)) + if r1 != 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/zsyscall_windows.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/zsyscall_windows.go new file mode 100644 index 0000000000..3f527639a4 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/go-winio/zsyscall_windows.go @@ -0,0 +1,520 @@ +// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT + +package winio + +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 ( + modkernel32 = windows.NewLazySystemDLL("kernel32.dll") + modadvapi32 = windows.NewLazySystemDLL("advapi32.dll") + + procCancelIoEx = modkernel32.NewProc("CancelIoEx") + procCreateIoCompletionPort = modkernel32.NewProc("CreateIoCompletionPort") + procGetQueuedCompletionStatus = modkernel32.NewProc("GetQueuedCompletionStatus") + procSetFileCompletionNotificationModes = modkernel32.NewProc("SetFileCompletionNotificationModes") + procConnectNamedPipe = modkernel32.NewProc("ConnectNamedPipe") + procCreateNamedPipeW = modkernel32.NewProc("CreateNamedPipeW") + procCreateFileW = modkernel32.NewProc("CreateFileW") + procWaitNamedPipeW = modkernel32.NewProc("WaitNamedPipeW") + procGetNamedPipeInfo = modkernel32.NewProc("GetNamedPipeInfo") + procGetNamedPipeHandleStateW = modkernel32.NewProc("GetNamedPipeHandleStateW") + procLocalAlloc = modkernel32.NewProc("LocalAlloc") + procLookupAccountNameW = modadvapi32.NewProc("LookupAccountNameW") + procConvertSidToStringSidW = modadvapi32.NewProc("ConvertSidToStringSidW") + procConvertStringSecurityDescriptorToSecurityDescriptorW = modadvapi32.NewProc("ConvertStringSecurityDescriptorToSecurityDescriptorW") + procConvertSecurityDescriptorToStringSecurityDescriptorW = modadvapi32.NewProc("ConvertSecurityDescriptorToStringSecurityDescriptorW") + procLocalFree = modkernel32.NewProc("LocalFree") + procGetSecurityDescriptorLength = modadvapi32.NewProc("GetSecurityDescriptorLength") + procGetFileInformationByHandleEx = modkernel32.NewProc("GetFileInformationByHandleEx") + procSetFileInformationByHandle = modkernel32.NewProc("SetFileInformationByHandle") + procAdjustTokenPrivileges = modadvapi32.NewProc("AdjustTokenPrivileges") + procImpersonateSelf = modadvapi32.NewProc("ImpersonateSelf") + procRevertToSelf = modadvapi32.NewProc("RevertToSelf") + procOpenThreadToken = modadvapi32.NewProc("OpenThreadToken") + procGetCurrentThread = modkernel32.NewProc("GetCurrentThread") + procLookupPrivilegeValueW = modadvapi32.NewProc("LookupPrivilegeValueW") + procLookupPrivilegeNameW = modadvapi32.NewProc("LookupPrivilegeNameW") + procLookupPrivilegeDisplayNameW = modadvapi32.NewProc("LookupPrivilegeDisplayNameW") + procBackupRead = modkernel32.NewProc("BackupRead") + procBackupWrite = modkernel32.NewProc("BackupWrite") +) + +func cancelIoEx(file syscall.Handle, o *syscall.Overlapped) (err error) { + r1, _, e1 := syscall.Syscall(procCancelIoEx.Addr(), 2, uintptr(file), uintptr(unsafe.Pointer(o)), 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + 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) + if newport == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func getQueuedCompletionStatus(port syscall.Handle, bytes *uint32, key *uintptr, o **ioOperation, timeout uint32) (err error) { + r1, _, e1 := syscall.Syscall6(procGetQueuedCompletionStatus.Addr(), 5, uintptr(port), uintptr(unsafe.Pointer(bytes)), uintptr(unsafe.Pointer(key)), uintptr(unsafe.Pointer(o)), uintptr(timeout), 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func setFileCompletionNotificationModes(h syscall.Handle, flags uint8) (err error) { + r1, _, e1 := syscall.Syscall(procSetFileCompletionNotificationModes.Addr(), 2, uintptr(h), uintptr(flags), 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func connectNamedPipe(pipe syscall.Handle, o *syscall.Overlapped) (err error) { + r1, _, e1 := syscall.Syscall(procConnectNamedPipe.Addr(), 2, uintptr(pipe), uintptr(unsafe.Pointer(o)), 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func createNamedPipe(name string, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *syscall.SecurityAttributes) (handle syscall.Handle, err error) { + var _p0 *uint16 + _p0, err = syscall.UTF16PtrFromString(name) + if err != nil { + return + } + return _createNamedPipe(_p0, flags, pipeMode, maxInstances, outSize, inSize, defaultTimeout, sa) +} + +func _createNamedPipe(name *uint16, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *syscall.SecurityAttributes) (handle syscall.Handle, err error) { + r0, _, e1 := syscall.Syscall9(procCreateNamedPipeW.Addr(), 8, uintptr(unsafe.Pointer(name)), uintptr(flags), uintptr(pipeMode), uintptr(maxInstances), uintptr(outSize), uintptr(inSize), uintptr(defaultTimeout), uintptr(unsafe.Pointer(sa)), 0) + handle = syscall.Handle(r0) + if handle == syscall.InvalidHandle { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + 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 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func waitNamedPipe(name string, timeout uint32) (err error) { + var _p0 *uint16 + _p0, err = syscall.UTF16PtrFromString(name) + if err != nil { + return + } + return _waitNamedPipe(_p0, timeout) +} + +func _waitNamedPipe(name *uint16, timeout uint32) (err error) { + r1, _, e1 := syscall.Syscall(procWaitNamedPipeW.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(timeout), 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func getNamedPipeInfo(pipe syscall.Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error) { + r1, _, e1 := syscall.Syscall6(procGetNamedPipeInfo.Addr(), 5, uintptr(pipe), uintptr(unsafe.Pointer(flags)), uintptr(unsafe.Pointer(outSize)), uintptr(unsafe.Pointer(inSize)), uintptr(unsafe.Pointer(maxInstances)), 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func getNamedPipeHandleState(pipe syscall.Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) { + r1, _, e1 := syscall.Syscall9(procGetNamedPipeHandleStateW.Addr(), 7, uintptr(pipe), uintptr(unsafe.Pointer(state)), uintptr(unsafe.Pointer(curInstances)), uintptr(unsafe.Pointer(maxCollectionCount)), uintptr(unsafe.Pointer(collectDataTimeout)), uintptr(unsafe.Pointer(userName)), uintptr(maxUserNameSize), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func localAlloc(uFlags uint32, length uint32) (ptr uintptr) { + r0, _, _ := syscall.Syscall(procLocalAlloc.Addr(), 2, uintptr(uFlags), uintptr(length), 0) + ptr = uintptr(r0) + return +} + +func lookupAccountName(systemName *uint16, accountName string, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) { + var _p0 *uint16 + _p0, err = syscall.UTF16PtrFromString(accountName) + if err != nil { + return + } + return _lookupAccountName(systemName, _p0, sid, sidSize, refDomain, refDomainSize, sidNameUse) +} + +func _lookupAccountName(systemName *uint16, accountName *uint16, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) { + r1, _, e1 := syscall.Syscall9(procLookupAccountNameW.Addr(), 7, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(accountName)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(sidSize)), uintptr(unsafe.Pointer(refDomain)), uintptr(unsafe.Pointer(refDomainSize)), uintptr(unsafe.Pointer(sidNameUse)), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func convertSidToStringSid(sid *byte, str **uint16) (err error) { + r1, _, e1 := syscall.Syscall(procConvertSidToStringSidW.Addr(), 2, uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(str)), 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func convertStringSecurityDescriptorToSecurityDescriptor(str string, revision uint32, sd *uintptr, size *uint32) (err error) { + var _p0 *uint16 + _p0, err = syscall.UTF16PtrFromString(str) + if err != nil { + return + } + return _convertStringSecurityDescriptorToSecurityDescriptor(_p0, revision, sd, size) +} + +func _convertStringSecurityDescriptorToSecurityDescriptor(str *uint16, revision uint32, sd *uintptr, size *uint32) (err error) { + r1, _, e1 := syscall.Syscall6(procConvertStringSecurityDescriptorToSecurityDescriptorW.Addr(), 4, uintptr(unsafe.Pointer(str)), uintptr(revision), uintptr(unsafe.Pointer(sd)), uintptr(unsafe.Pointer(size)), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func convertSecurityDescriptorToStringSecurityDescriptor(sd *byte, revision uint32, secInfo uint32, sddl **uint16, sddlSize *uint32) (err error) { + r1, _, e1 := syscall.Syscall6(procConvertSecurityDescriptorToStringSecurityDescriptorW.Addr(), 5, uintptr(unsafe.Pointer(sd)), uintptr(revision), uintptr(secInfo), uintptr(unsafe.Pointer(sddl)), uintptr(unsafe.Pointer(sddlSize)), 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func localFree(mem uintptr) { + syscall.Syscall(procLocalFree.Addr(), 1, uintptr(mem), 0, 0) + return +} + +func getSecurityDescriptorLength(sd uintptr) (len uint32) { + r0, _, _ := syscall.Syscall(procGetSecurityDescriptorLength.Addr(), 1, uintptr(sd), 0, 0) + len = uint32(r0) + return +} + +func getFileInformationByHandleEx(h syscall.Handle, class uint32, buffer *byte, size uint32) (err error) { + r1, _, e1 := syscall.Syscall6(procGetFileInformationByHandleEx.Addr(), 4, uintptr(h), uintptr(class), uintptr(unsafe.Pointer(buffer)), uintptr(size), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func setFileInformationByHandle(h syscall.Handle, class uint32, buffer *byte, size uint32) (err error) { + r1, _, e1 := syscall.Syscall6(procSetFileInformationByHandle.Addr(), 4, uintptr(h), uintptr(class), uintptr(unsafe.Pointer(buffer)), uintptr(size), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func adjustTokenPrivileges(token windows.Token, releaseAll bool, input *byte, outputSize uint32, output *byte, requiredSize *uint32) (success bool, err error) { + var _p0 uint32 + if releaseAll { + _p0 = 1 + } else { + _p0 = 0 + } + r0, _, e1 := syscall.Syscall6(procAdjustTokenPrivileges.Addr(), 6, uintptr(token), uintptr(_p0), uintptr(unsafe.Pointer(input)), uintptr(outputSize), uintptr(unsafe.Pointer(output)), uintptr(unsafe.Pointer(requiredSize))) + success = r0 != 0 + if true { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func impersonateSelf(level uint32) (err error) { + r1, _, e1 := syscall.Syscall(procImpersonateSelf.Addr(), 1, uintptr(level), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func revertToSelf() (err error) { + r1, _, e1 := syscall.Syscall(procRevertToSelf.Addr(), 0, 0, 0, 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func openThreadToken(thread syscall.Handle, accessMask uint32, openAsSelf bool, token *windows.Token) (err error) { + var _p0 uint32 + if openAsSelf { + _p0 = 1 + } else { + _p0 = 0 + } + r1, _, e1 := syscall.Syscall6(procOpenThreadToken.Addr(), 4, uintptr(thread), uintptr(accessMask), uintptr(_p0), uintptr(unsafe.Pointer(token)), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func getCurrentThread() (h syscall.Handle) { + r0, _, _ := syscall.Syscall(procGetCurrentThread.Addr(), 0, 0, 0, 0) + h = syscall.Handle(r0) + return +} + +func lookupPrivilegeValue(systemName string, name string, luid *uint64) (err error) { + var _p0 *uint16 + _p0, err = syscall.UTF16PtrFromString(systemName) + if err != nil { + return + } + var _p1 *uint16 + _p1, err = syscall.UTF16PtrFromString(name) + if err != nil { + return + } + return _lookupPrivilegeValue(_p0, _p1, luid) +} + +func _lookupPrivilegeValue(systemName *uint16, name *uint16, luid *uint64) (err error) { + r1, _, e1 := syscall.Syscall(procLookupPrivilegeValueW.Addr(), 3, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(luid))) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func lookupPrivilegeName(systemName string, luid *uint64, buffer *uint16, size *uint32) (err error) { + var _p0 *uint16 + _p0, err = syscall.UTF16PtrFromString(systemName) + if err != nil { + return + } + return _lookupPrivilegeName(_p0, luid, buffer, size) +} + +func _lookupPrivilegeName(systemName *uint16, luid *uint64, buffer *uint16, size *uint32) (err error) { + r1, _, e1 := syscall.Syscall6(procLookupPrivilegeNameW.Addr(), 4, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(luid)), uintptr(unsafe.Pointer(buffer)), uintptr(unsafe.Pointer(size)), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func lookupPrivilegeDisplayName(systemName string, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) { + var _p0 *uint16 + _p0, err = syscall.UTF16PtrFromString(systemName) + if err != nil { + return + } + return _lookupPrivilegeDisplayName(_p0, name, buffer, size, languageId) +} + +func _lookupPrivilegeDisplayName(systemName *uint16, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) { + r1, _, e1 := syscall.Syscall6(procLookupPrivilegeDisplayNameW.Addr(), 5, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(buffer)), uintptr(unsafe.Pointer(size)), uintptr(unsafe.Pointer(languageId)), 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func backupRead(h syscall.Handle, b []byte, bytesRead *uint32, abort bool, processSecurity bool, context *uintptr) (err error) { + var _p0 *byte + if len(b) > 0 { + _p0 = &b[0] + } + var _p1 uint32 + if abort { + _p1 = 1 + } else { + _p1 = 0 + } + var _p2 uint32 + if processSecurity { + _p2 = 1 + } else { + _p2 = 0 + } + r1, _, e1 := syscall.Syscall9(procBackupRead.Addr(), 7, uintptr(h), uintptr(unsafe.Pointer(_p0)), uintptr(len(b)), uintptr(unsafe.Pointer(bytesRead)), uintptr(_p1), uintptr(_p2), uintptr(unsafe.Pointer(context)), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func backupWrite(h syscall.Handle, b []byte, bytesWritten *uint32, abort bool, processSecurity bool, context *uintptr) (err error) { + var _p0 *byte + if len(b) > 0 { + _p0 = &b[0] + } + var _p1 uint32 + if abort { + _p1 = 1 + } else { + _p1 = 0 + } + var _p2 uint32 + if processSecurity { + _p2 = 1 + } else { + _p2 = 0 + } + r1, _, e1 := syscall.Syscall9(procBackupWrite.Addr(), 7, uintptr(h), uintptr(unsafe.Pointer(_p0)), uintptr(len(b)), uintptr(unsafe.Pointer(bytesWritten)), uintptr(_p1), uintptr(_p2), uintptr(unsafe.Pointer(context)), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/opengcs/LICENSE b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/opengcs/LICENSE new file mode 100644 index 0000000000..4b1ad51b2f --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/opengcs/LICENSE @@ -0,0 +1,21 @@ + MIT License + + Copyright (c) Microsoft Corporation. All rights reserved. + + 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 diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/opengcs/README.md b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/opengcs/README.md new file mode 100644 index 0000000000..e931fde8f3 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/opengcs/README.md @@ -0,0 +1,14 @@ + +# Open Guest Compute Service (opengcs) [![Build Status](https://travis-ci.org/Microsoft/opengcs.svg?branch=master)](https://travis-ci.org/Microsoft/opengcs) + +Open Guest Compute Service is a Linux open source project to further the development of a production quality implementation of Linux Hyper-V container on Windows (LCOW). It's designed to run inside a custom Linux OS for supporting Linux container payload. + +# Getting Started + + [How to build GCS binaries](./docs/gcsbuildinstructions.md/) + + [How to build custom Linux OS images](./docs/customosbuildinstructions.md/) + +# Contributing + +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. diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/opengcs/client/config.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/opengcs/client/config.go new file mode 100644 index 0000000000..c2f6b21631 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/opengcs/client/config.go @@ -0,0 +1,274 @@ +// +build windows + +package client + +import ( + "encoding/json" + "fmt" + "os" + "path/filepath" + "strconv" + "strings" + + "github.com/Microsoft/hcsshim" + "github.com/sirupsen/logrus" +) + +// Mode is the operational mode, both requested, and actual after verification +type Mode uint + +const ( + // Constants for the actual mode after validation + + // ModeActualError means an error has occurred during validation + ModeActualError = iota + // ModeActualVhdx means that we are going to use VHDX boot after validation + ModeActualVhdx + // ModeActualKernelInitrd means that we are going to use kernel+initrd for boot after validation + ModeActualKernelInitrd + + // Constants for the requested mode + + // ModeRequestAuto means auto-select the boot mode for a utility VM + ModeRequestAuto = iota // VHDX will be priority over kernel+initrd + // ModeRequestVhdx means request VHDX boot if possible + ModeRequestVhdx + // ModeRequestKernelInitrd means request Kernel+initrd boot if possible + ModeRequestKernelInitrd + + // defaultUvmTimeoutSeconds is the default time to wait for utility VM operations + defaultUvmTimeoutSeconds = 5 * 60 + + // DefaultVhdxSizeGB is the size of the default sandbox & scratch in GB + DefaultVhdxSizeGB = 20 + + // defaultVhdxBlockSizeMB is the block-size for the sandbox/scratch VHDx's this package can create. + defaultVhdxBlockSizeMB = 1 +) + +// Config is the structure used to configuring a utility VM. There are two ways +// of starting. Either supply a VHD, or a Kernel+Initrd. For the latter, both +// must be supplied, and both must be in the same directory. +// +// VHD is the priority. +type Config struct { + Options // Configuration options + Name string // Name of the utility VM + RequestedMode Mode // What mode is preferred when validating + ActualMode Mode // What mode was obtained during validation + UvmTimeoutSeconds int // How long to wait for the utility VM to respond in seconds + Uvm hcsshim.Container // The actual container + MappedVirtualDisks []hcsshim.MappedVirtualDisk // Data-disks to be attached +} + +// Options is the structure used by a client to define configurable options for a utility VM. +type Options struct { + KirdPath string // Path to where kernel/initrd are found (defaults to %PROGRAMFILES%\Linux Containers) + KernelFile string // Kernel for Utility VM (embedded in a UEFI bootloader) - does NOT include full path, just filename + InitrdFile string // Initrd image for Utility VM - does NOT include full path, just filename + Vhdx string // VHD for booting the utility VM - is a full path + TimeoutSeconds int // Requested time for the utility VM to respond in seconds (may be over-ridden by environment) + BootParameters string // Additional boot parameters for initrd booting (not VHDx) +} + +// ParseOptions parses a set of K-V pairs into options used by opengcs. Note +// for consistency with the LCOW graphdriver in docker, we keep the same +// convention of an `lcow.` prefix. +func ParseOptions(options []string) (Options, error) { + rOpts := Options{TimeoutSeconds: 0} + for _, v := range options { + opt := strings.SplitN(v, "=", 2) + if len(opt) == 2 { + switch strings.ToLower(opt[0]) { + case "lcow.kirdpath": + rOpts.KirdPath = opt[1] + case "lcow.kernel": + rOpts.KernelFile = opt[1] + case "lcow.initrd": + rOpts.InitrdFile = opt[1] + case "lcow.vhdx": + rOpts.Vhdx = opt[1] + case "lcow.bootparameters": + rOpts.BootParameters = opt[1] + case "lcow.timeout": + var err error + if rOpts.TimeoutSeconds, err = strconv.Atoi(opt[1]); err != nil { + return rOpts, fmt.Errorf("lcow.timeout option could not be interpreted as an integer") + } + if rOpts.TimeoutSeconds < 0 { + return rOpts, fmt.Errorf("lcow.timeout option cannot be negative") + } + } + } + } + + // Set default values if not supplied + if rOpts.KirdPath == "" { + rOpts.KirdPath = filepath.Join(os.Getenv("ProgramFiles"), "Linux Containers") + } + if rOpts.Vhdx == "" { + rOpts.Vhdx = filepath.Join(rOpts.KirdPath, `uvm.vhdx`) + } + if rOpts.KernelFile == "" { + rOpts.KernelFile = `kernel` + } + if rOpts.InitrdFile == "" { + rOpts.InitrdFile = `initrd.img` + } + + return rOpts, nil +} + +// GenerateDefault generates a default config from a set of options +// If baseDir is not supplied, defaults to $env:ProgramFiles\Linux Containers +func (config *Config) GenerateDefault(options []string) error { + // Parse the options that the user supplied. + var err error + config.Options, err = ParseOptions(options) + if err != nil { + return err + } + + // Get the timeout from the environment + envTimeoutSeconds := 0 + envTimeout := os.Getenv("OPENGCS_UVM_TIMEOUT_SECONDS") + if len(envTimeout) > 0 { + var err error + if envTimeoutSeconds, err = strconv.Atoi(envTimeout); err != nil { + return fmt.Errorf("OPENGCS_UVM_TIMEOUT_SECONDS could not be interpreted as an integer") + } + if envTimeoutSeconds < 0 { + return fmt.Errorf("OPENGCS_UVM_TIMEOUT_SECONDS cannot be negative") + } + } + + // Priority to the requested timeout from the options. + if config.TimeoutSeconds != 0 { + config.UvmTimeoutSeconds = config.TimeoutSeconds + return nil + } + + // Next priority, the environment + if envTimeoutSeconds != 0 { + config.UvmTimeoutSeconds = envTimeoutSeconds + return nil + } + + // Last priority is the default timeout + config.UvmTimeoutSeconds = defaultUvmTimeoutSeconds + + // Set the default requested mode + config.RequestedMode = ModeRequestAuto + + return nil +} + +// Validate validates a Config structure for starting a utility VM. +func (config *Config) Validate() error { + config.ActualMode = ModeActualError + + if config.RequestedMode == ModeRequestVhdx && config.Vhdx == "" { + return fmt.Errorf("VHDx mode must supply a VHDx") + } + if config.RequestedMode == ModeRequestKernelInitrd && (config.KernelFile == "" || config.InitrdFile == "") { + return fmt.Errorf("kernel+initrd mode must supply both kernel and initrd") + } + + // Validate that if VHDX requested or auto, it exists. + if config.RequestedMode == ModeRequestAuto || config.RequestedMode == ModeRequestVhdx { + if _, err := os.Stat(config.Vhdx); os.IsNotExist(err) { + if config.RequestedMode == ModeRequestVhdx { + return fmt.Errorf("VHDx '%s' not found", config.Vhdx) + } + } else { + config.ActualMode = ModeActualVhdx + + // Can't specify boot parameters with VHDx + if config.BootParameters != "" { + return fmt.Errorf("Boot parameters cannot be specified in VHDx mode") + } + return nil + } + } + + // So must be kernel+initrd, or auto where we fallback as the VHDX doesn't exist + if config.InitrdFile == "" || config.KernelFile == "" { + if config.RequestedMode == ModeRequestKernelInitrd { + return fmt.Errorf("initrd and kernel options must be supplied") + } + return fmt.Errorf("opengcs: configuration is invalid") + } + + if _, err := os.Stat(filepath.Join(config.KirdPath, config.KernelFile)); os.IsNotExist(err) { + return fmt.Errorf("kernel '%s' not found", filepath.Join(config.KirdPath, config.KernelFile)) + } + if _, err := os.Stat(filepath.Join(config.KirdPath, config.InitrdFile)); os.IsNotExist(err) { + return fmt.Errorf("initrd '%s' not found", filepath.Join(config.KirdPath, config.InitrdFile)) + } + + config.ActualMode = ModeActualKernelInitrd + + // Ensure all the MappedVirtualDisks exist on the host + for _, mvd := range config.MappedVirtualDisks { + if _, err := os.Stat(mvd.HostPath); err != nil { + return fmt.Errorf("mapped virtual disk '%s' not found", mvd.HostPath) + } + if mvd.ContainerPath == "" { + return fmt.Errorf("mapped virtual disk '%s' requested without a container path", mvd.HostPath) + } + } + + return nil +} + +// StartUtilityVM creates and starts a utility VM from a configuration. +func (config *Config) StartUtilityVM() error { + logrus.Debugf("opengcs: StartUtilityVM: %+v", config) + + if err := config.Validate(); err != nil { + return err + } + + configuration := &hcsshim.ContainerConfig{ + HvPartition: true, + Name: config.Name, + SystemType: "container", + ContainerType: "linux", + TerminateOnLastHandleClosed: true, + MappedVirtualDisks: config.MappedVirtualDisks, + } + + if config.ActualMode == ModeActualVhdx { + configuration.HvRuntime = &hcsshim.HvRuntime{ + ImagePath: config.Vhdx, + BootSource: "Vhd", + WritableBootSource: false, + } + } else { + configuration.HvRuntime = &hcsshim.HvRuntime{ + ImagePath: config.KirdPath, + LinuxInitrdFile: config.InitrdFile, + LinuxKernelFile: config.KernelFile, + LinuxBootParameters: config.BootParameters, + } + } + + configurationS, _ := json.Marshal(configuration) + logrus.Debugf("opengcs: StartUtilityVM: calling HCS with '%s'", string(configurationS)) + uvm, err := hcsshim.CreateContainer(config.Name, configuration) + if err != nil { + return err + } + logrus.Debugf("opengcs: StartUtilityVM: uvm created, starting...") + err = uvm.Start() + if err != nil { + logrus.Debugf("opengcs: StartUtilityVM: uvm failed to start: %s", err) + // Make sure we don't leave it laying around as it's been created in HCS + uvm.Terminate() + return err + } + + config.Uvm = uvm + logrus.Debugf("opengcs StartUtilityVM: uvm %s is running", config.Name) + return nil +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/opengcs/client/createext4vhdx.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/opengcs/client/createext4vhdx.go new file mode 100644 index 0000000000..8fb7520b41 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/opengcs/client/createext4vhdx.go @@ -0,0 +1,167 @@ +// +build windows + +package client + +import ( + "bytes" + "fmt" + "os" + "strings" + "time" + + winio "github.com/Microsoft/go-winio/vhd" + // "github.com/Microsoft/hcsshim" + "github.com/sirupsen/logrus" +) + +// dismount is a simple utility function wrapping a conditional HotRemove. It would +// have been easier if you could cancel a deferred function, but this works just +// as well. +func (config *Config) dismount(file string) error { + logrus.Debugf("opengcs: CreateExt4Vhdx: hot-remove of %s", file) + err := config.HotRemoveVhd(file) + if err != nil { + logrus.Warnf("failed to hot-remove: %s", err) + } + return err +} + +// CreateExt4Vhdx does what it says on the tin. It is the responsibility of the caller to synchronise +// simultaneous attempts to create the cache file. +func (config *Config) CreateExt4Vhdx(destFile string, sizeGB uint32, cacheFile string) error { + // Smallest we can accept is the default sandbox size as we can't size down, only expand. + if sizeGB < DefaultVhdxSizeGB { + sizeGB = DefaultVhdxSizeGB + } + + logrus.Debugf("opengcs: CreateExt4Vhdx: %s size:%dGB cache:%s", destFile, sizeGB, cacheFile) + + // Retrieve from cache if the default size and already on disk + if cacheFile != "" && sizeGB == DefaultVhdxSizeGB { + if _, err := os.Stat(cacheFile); err == nil { + if err := CopyFile(cacheFile, destFile, false); err != nil { + return fmt.Errorf("failed to copy cached file '%s' to '%s': %s", cacheFile, destFile, err) + } + logrus.Debugf("opengcs: CreateExt4Vhdx: %s fulfilled from cache", destFile) + return nil + } + } + + // Must have a utility VM to operate on + if config.Uvm == nil { + return fmt.Errorf("no utility VM") + } + + // Create the VHDX + if err := winio.CreateVhdx(destFile, sizeGB, defaultVhdxBlockSizeMB); err != nil { + return fmt.Errorf("failed to create VHDx %s: %s", destFile, err) + } + + defer config.DebugGCS() + + // Attach it to the utility VM, but don't mount it (as there's no filesystem on it) + if err := config.HotAddVhd(destFile, "", false, false); err != nil { + return fmt.Errorf("opengcs: CreateExt4Vhdx: failed to hot-add %s to utility VM: %s", cacheFile, err) + } + + // Get the list of mapped virtual disks to find the controller and LUN IDs + logrus.Debugf("opengcs: CreateExt4Vhdx: %s querying mapped virtual disks", destFile) + mvdControllers, err := config.Uvm.MappedVirtualDisks() + if err != nil { + return fmt.Errorf("failed to get mapped virtual disks: %s", err) + } + + // Find our mapped disk from the list of all currently added. + controller := -1 + lun := -1 + for controllerNumber, controllerElement := range mvdControllers { + for diskNumber, diskElement := range controllerElement.MappedVirtualDisks { + if diskElement.HostPath == destFile { + controller = controllerNumber + lun = diskNumber + break + } + } + } + if controller == -1 || lun == -1 { + config.dismount(destFile) + return fmt.Errorf("failed to find %s in mapped virtual disks after hot-adding", destFile) + } + logrus.Debugf("opengcs: CreateExt4Vhdx: %s at C=%d L=%d", destFile, controller, lun) + + // Validate /sys/bus/scsi/devices/C:0:0:L exists as a directory + testdCommand := fmt.Sprintf(`test -d /sys/bus/scsi/devices/%d:0:0:%d`, controller, lun) + testdProc, err := config.RunProcess(testdCommand, nil, nil, nil) + if err != nil { + config.dismount(destFile) + return fmt.Errorf("failed to `%s` following hot-add %s to utility VM: %s", testdCommand, destFile, err) + } + defer testdProc.Close() + testdProc.WaitTimeout(time.Second * time.Duration(config.UvmTimeoutSeconds)) + testdExitCode, err := testdProc.ExitCode() + if err != nil { + config.dismount(destFile) + return fmt.Errorf("failed to get exit code from `%s` following hot-add %s to utility VM: %s", testdCommand, destFile, err) + } + if testdExitCode != 0 { + config.dismount(destFile) + return fmt.Errorf("`%s` return non-zero exit code (%d) following hot-add %s to utility VM", testdCommand, testdExitCode, destFile) + } + + // Get the device from under the block subdirectory by doing a simple ls. This will come back as (eg) `sda` + lsCommand := fmt.Sprintf(`ls /sys/bus/scsi/devices/%d:0:0:%d/block`, controller, lun) + var lsOutput bytes.Buffer + lsProc, err := config.RunProcess(lsCommand, nil, &lsOutput, nil) + if err != nil { + config.dismount(destFile) + return fmt.Errorf("failed to `%s` following hot-add %s to utility VM: %s", lsCommand, destFile, err) + } + defer lsProc.Close() + lsProc.WaitTimeout(time.Second * time.Duration(config.UvmTimeoutSeconds)) + lsExitCode, err := lsProc.ExitCode() + if err != nil { + config.dismount(destFile) + return fmt.Errorf("failed to get exit code from `%s` following hot-add %s to utility VM: %s", lsCommand, destFile, err) + } + if lsExitCode != 0 { + config.dismount(destFile) + return fmt.Errorf("`%s` return non-zero exit code (%d) following hot-add %s to utility VM", lsCommand, lsExitCode, destFile) + } + device := fmt.Sprintf(`/dev/%s`, strings.TrimSpace(lsOutput.String())) + logrus.Debugf("opengcs: CreateExt4Vhdx: %s: device at %s", destFile, device) + + // Format it ext4 + mkfsCommand := fmt.Sprintf(`mkfs.ext4 -q -E lazy_itable_init=1 -O ^has_journal,sparse_super2,uninit_bg,^resize_inode %s`, device) + var mkfsStderr bytes.Buffer + mkfsProc, err := config.RunProcess(mkfsCommand, nil, nil, &mkfsStderr) + if err != nil { + config.dismount(destFile) + return fmt.Errorf("failed to RunProcess %q following hot-add %s to utility VM: %s", destFile, mkfsCommand, err) + } + defer mkfsProc.Close() + mkfsProc.WaitTimeout(time.Second * time.Duration(config.UvmTimeoutSeconds)) + mkfsExitCode, err := mkfsProc.ExitCode() + if err != nil { + config.dismount(destFile) + return fmt.Errorf("failed to get exit code from `%s` following hot-add %s to utility VM: %s", mkfsCommand, destFile, err) + } + if mkfsExitCode != 0 { + config.dismount(destFile) + return fmt.Errorf("`%s` return non-zero exit code (%d) following hot-add %s to utility VM: %s", mkfsCommand, mkfsExitCode, destFile, strings.TrimSpace(mkfsStderr.String())) + } + + // Dismount before we copy it + if err := config.dismount(destFile); err != nil { + return fmt.Errorf("failed to hot-remove: %s", err) + } + + // Populate the cache. + if cacheFile != "" && (sizeGB == DefaultVhdxSizeGB) { + if err := CopyFile(destFile, cacheFile, true); err != nil { + return fmt.Errorf("failed to seed cache '%s' from '%s': %s", destFile, cacheFile, err) + } + } + + logrus.Debugf("opengcs: CreateExt4Vhdx: %s created (non-cache)", destFile) + return nil +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/opengcs/client/hotaddvhd.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/opengcs/client/hotaddvhd.go new file mode 100644 index 0000000000..ef1e51fd65 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/opengcs/client/hotaddvhd.go @@ -0,0 +1,42 @@ +// +build windows + +package client + +import ( + "fmt" + + "github.com/Microsoft/hcsshim" + "github.com/sirupsen/logrus" +) + +// HotAddVhd hot-adds a VHD to a utility VM. This is used in the global one-utility-VM- +// service-VM per host scenario. In order to do a graphdriver `Diff`, we hot-add the +// sandbox to /mnt/ so that we can run `exportSandbox` inside the utility VM to +// get a tar-stream of the sandboxes contents back to the daemon. +func (config *Config) HotAddVhd(hostPath string, containerPath string, readOnly bool, mount bool) error { + logrus.Debugf("opengcs: HotAddVhd: %s: %s", hostPath, containerPath) + + if config.Uvm == nil { + return fmt.Errorf("cannot hot-add VHD as no utility VM is in configuration") + } + + defer config.DebugGCS() + + modification := &hcsshim.ResourceModificationRequestResponse{ + Resource: "MappedVirtualDisk", + Data: hcsshim.MappedVirtualDisk{ + HostPath: hostPath, + ContainerPath: containerPath, + CreateInUtilityVM: true, + ReadOnly: readOnly, + AttachOnly: !mount, + }, + Request: "Add", + } + + if err := config.Uvm.Modify(modification); err != nil { + return fmt.Errorf("failed to modify utility VM configuration for hot-add: %s", err) + } + logrus.Debugf("opengcs: HotAddVhd: %s added successfully", hostPath) + return nil +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/opengcs/client/hotremovevhd.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/opengcs/client/hotremovevhd.go new file mode 100644 index 0000000000..be63189173 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/opengcs/client/hotremovevhd.go @@ -0,0 +1,36 @@ +// +build windows + +package client + +import ( + "fmt" + + "github.com/Microsoft/hcsshim" + "github.com/sirupsen/logrus" +) + +// HotRemoveVhd hot-removes a VHD from a utility VM. This is used in the global one-utility-VM- +// service-VM per host scenario. +func (config *Config) HotRemoveVhd(hostPath string) error { + logrus.Debugf("opengcs: HotRemoveVhd: %s", hostPath) + + if config.Uvm == nil { + return fmt.Errorf("cannot hot-add VHD as no utility VM is in configuration") + } + + defer config.DebugGCS() + + modification := &hcsshim.ResourceModificationRequestResponse{ + Resource: "MappedVirtualDisk", + Data: hcsshim.MappedVirtualDisk{ + HostPath: hostPath, + CreateInUtilityVM: true, + }, + Request: "Remove", + } + if err := config.Uvm.Modify(modification); err != nil { + return fmt.Errorf("failed modifying utility VM for hot-remove %s: %s", hostPath, err) + } + logrus.Debugf("opengcs: HotRemoveVhd: %s removed successfully", hostPath) + return nil +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/opengcs/client/init.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/opengcs/client/init.go new file mode 100644 index 0000000000..246ac185e9 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/opengcs/client/init.go @@ -0,0 +1,24 @@ +// +build windows + +package client + +import ( + "os" + "strconv" +) + +var ( + logDataFromUVM int64 +) + +func init() { + bytes := os.Getenv("OPENGCS_LOG_DATA_FROM_UVM") + if len(bytes) == 0 { + return + } + u, err := strconv.ParseUint(bytes, 10, 32) + if err != nil { + return + } + logDataFromUVM = int64(u) +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/opengcs/client/layervhddetails.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/opengcs/client/layervhddetails.go new file mode 100644 index 0000000000..010780069a --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/opengcs/client/layervhddetails.go @@ -0,0 +1,31 @@ +// +build windows + +package client + +import ( + "fmt" + "os" + "path/filepath" +) + +// LayerVhdDetails is a utility for getting a file name, size and indication of +// sandbox for a VHD(x) in a folder. A read-only layer will be layer.vhd. A +// read-write layer will be sandbox.vhdx. +func LayerVhdDetails(folder string) (string, int64, bool, error) { + var fileInfo os.FileInfo + isSandbox := false + filename := filepath.Join(folder, "layer.vhd") + var err error + + if fileInfo, err = os.Stat(filename); err != nil { + filename = filepath.Join(folder, "sandbox.vhdx") + if fileInfo, err = os.Stat(filename); err != nil { + if os.IsNotExist(err) { + return "", 0, isSandbox, fmt.Errorf("could not find layer or sandbox in %s", folder) + } + return "", 0, isSandbox, fmt.Errorf("error locating layer or sandbox in %s: %s", folder, err) + } + isSandbox = true + } + return filename, fileInfo.Size(), isSandbox, nil +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/opengcs/client/process.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/opengcs/client/process.go new file mode 100644 index 0000000000..a8ffdf98e6 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/opengcs/client/process.go @@ -0,0 +1,164 @@ +// +build windows + +package client + +import ( + "bytes" + "fmt" + "io" + "os" + "strings" + "time" + + "github.com/Microsoft/hcsshim" + "github.com/sirupsen/logrus" +) + +// Process is the structure pertaining to a process running in a utility VM. +type process struct { + Process hcsshim.Process + Stdin io.WriteCloser + Stdout io.ReadCloser + Stderr io.ReadCloser +} + +// createUtilsProcess is a convenient wrapper for hcsshim.createUtilsProcess to use when +// communicating with a utility VM. +func (config *Config) createUtilsProcess(commandLine string) (process, error) { + logrus.Debugf("opengcs: createUtilsProcess") + + if config.Uvm == nil { + return process{}, fmt.Errorf("cannot create utils process as no utility VM is in configuration") + } + + var ( + err error + proc process + ) + + env := make(map[string]string) + env["PATH"] = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:" + processConfig := &hcsshim.ProcessConfig{ + EmulateConsole: false, + CreateStdInPipe: true, + CreateStdOutPipe: true, + CreateStdErrPipe: true, + CreateInUtilityVm: true, + WorkingDirectory: "/bin", + Environment: env, + CommandLine: commandLine, + } + proc.Process, err = config.Uvm.CreateProcess(processConfig) + if err != nil { + return process{}, fmt.Errorf("failed to create process (%+v) in utility VM: %s", config, err) + } + + if proc.Stdin, proc.Stdout, proc.Stderr, err = proc.Process.Stdio(); err != nil { + proc.Process.Kill() // Should this have a timeout? + proc.Process.Close() + return process{}, fmt.Errorf("failed to get stdio pipes for process %+v: %s", config, err) + } + + logrus.Debugf("opengcs: createUtilsProcess success: pid %d", proc.Process.Pid()) + return proc, nil +} + +// RunProcess runs the given command line program in the utilityVM. It takes in +// an input to the reader to feed into stdin and returns stdout to output. +// IMPORTANT: It is the responsibility of the caller to call Close() on the returned process. +func (config *Config) RunProcess(commandLine string, stdin io.Reader, stdout io.Writer, stderr io.Writer) (hcsshim.Process, error) { + logrus.Debugf("opengcs: RunProcess: %s", commandLine) + process, err := config.createUtilsProcess(commandLine) + if err != nil { + return nil, err + } + + // Send the data into the process's stdin + if stdin != nil { + if _, err = copyWithTimeout(process.Stdin, + stdin, + 0, + config.UvmTimeoutSeconds, + fmt.Sprintf("send to stdin of %s", commandLine)); err != nil { + return nil, err + } + + // Don't need stdin now we've sent everything. This signals GCS that we are finished sending data. + if err := process.Process.CloseStdin(); err != nil && !hcsshim.IsNotExist(err) && !hcsshim.IsAlreadyClosed(err) { + // This error will occur if the compute system is currently shutting down + if perr, ok := err.(*hcsshim.ProcessError); ok && perr.Err != hcsshim.ErrVmcomputeOperationInvalidState { + return nil, err + } + } + } + + if stdout != nil { + // Copy the data over to the writer. + if _, err := copyWithTimeout(stdout, + process.Stdout, + 0, + config.UvmTimeoutSeconds, + fmt.Sprintf("RunProcess: copy back from %s", commandLine)); err != nil { + return nil, err + } + } + + if stderr != nil { + // Copy the data over to the writer. + if _, err := copyWithTimeout(stderr, + process.Stderr, + 0, + config.UvmTimeoutSeconds, + fmt.Sprintf("RunProcess: copy back from %s", commandLine)); err != nil { + return nil, err + } + } + + logrus.Debugf("opengcs: runProcess success: %s", commandLine) + return process.Process, nil +} + +func debugCommand(s string) string { + return fmt.Sprintf(`echo -e 'DEBUG COMMAND: %s\\n--------------\\n';%s;echo -e '\\n\\n';`, s, s) +} + +// DebugGCS extracts logs from the GCS. It's a useful hack for debugging, +// but not necessarily optimal, but all that is available to us in RS3. +func (config *Config) DebugGCS() { + if logrus.GetLevel() < logrus.DebugLevel || len(os.Getenv("OPENGCS_DEBUG_ENABLE")) == 0 { + return + } + + var out bytes.Buffer + cmd := os.Getenv("OPENGCS_DEBUG_COMMAND") + if cmd == "" { + cmd = `sh -c "` + cmd += debugCommand("kill -10 `pidof gcs`") // SIGUSR1 for stackdump + cmd += debugCommand("ls -l /tmp") + cmd += debugCommand("cat /tmp/gcs.log") + cmd += debugCommand("cat /tmp/gcs/gcs-stacks*") + cmd += debugCommand("cat /tmp/gcs/paniclog*") + cmd += debugCommand("ls -l /tmp/gcs") + cmd += debugCommand("ls -l /tmp/gcs/*") + cmd += debugCommand("cat /tmp/gcs/*/config.json") + cmd += debugCommand("ls -lR /var/run/gcsrunc") + cmd += debugCommand("cat /tmp/gcs/global-runc.log") + cmd += debugCommand("cat /tmp/gcs/*/runc.log") + cmd += debugCommand("ps -ef") + cmd += `"` + } + proc, err := config.RunProcess(cmd, nil, &out, nil) + defer func() { + if proc != nil { + proc.Kill() + proc.Close() + } + }() + if err != nil { + logrus.Debugln("benign failure getting gcs logs: ", err) + } + if proc != nil { + proc.WaitTimeout(time.Second * 30) + } + logrus.Debugf("GCS Debugging:\n%s\n\nEnd GCS Debugging", strings.TrimSpace(out.String())) +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/opengcs/client/tartovhd.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/opengcs/client/tartovhd.go new file mode 100644 index 0000000000..29ee48957a --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/opengcs/client/tartovhd.go @@ -0,0 +1,46 @@ +// +build windows + +package client + +import ( + "fmt" + "io" + + "github.com/sirupsen/logrus" +) + +// TarToVhd streams a tarstream contained in an io.Reader to a fixed vhd file +func (config *Config) TarToVhd(targetVHDFile string, reader io.Reader) (int64, error) { + logrus.Debugf("opengcs: TarToVhd: %s", targetVHDFile) + + if config.Uvm == nil { + return 0, fmt.Errorf("cannot Tar2Vhd as no utility VM is in configuration") + } + + defer config.DebugGCS() + + process, err := config.createUtilsProcess("tar2vhd") + if err != nil { + return 0, fmt.Errorf("failed to start tar2vhd for %s: %s", targetVHDFile, err) + } + defer process.Process.Close() + + // Send the tarstream into the `tar2vhd`s stdin + if _, err = copyWithTimeout(process.Stdin, reader, 0, config.UvmTimeoutSeconds, fmt.Sprintf("stdin of tar2vhd for generating %s", targetVHDFile)); err != nil { + return 0, fmt.Errorf("failed sending to tar2vhd for %s: %s", targetVHDFile, err) + } + + // Don't need stdin now we've sent everything. This signals GCS that we are finished sending data. + if err := process.Process.CloseStdin(); err != nil { + return 0, fmt.Errorf("failed closing stdin handle for %s: %s", targetVHDFile, err) + } + + // Write stdout contents of `tar2vhd` to the VHD file + payloadSize, err := writeFileFromReader(targetVHDFile, process.Stdout, config.UvmTimeoutSeconds, fmt.Sprintf("stdout of tar2vhd to %s", targetVHDFile)) + if err != nil { + return 0, fmt.Errorf("failed to write %s during tar2vhd: %s", targetVHDFile, err) + } + + logrus.Debugf("opengcs: TarToVhd: %s created, %d bytes", targetVHDFile, payloadSize) + return payloadSize, err +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/opengcs/client/unsupported.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/opengcs/client/unsupported.go new file mode 100644 index 0000000000..63b7067dce --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/opengcs/client/unsupported.go @@ -0,0 +1,3 @@ +// +build !windows + +package client diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/opengcs/client/utilities.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/opengcs/client/utilities.go new file mode 100644 index 0000000000..8441d960f4 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/opengcs/client/utilities.go @@ -0,0 +1,122 @@ +// +build windows + +package client + +import ( + "bytes" + "encoding/hex" + "fmt" + "io" + "os" + "syscall" + "time" + "unsafe" + + "github.com/sirupsen/logrus" +) + +var ( + modkernel32 = syscall.NewLazyDLL("kernel32.dll") + procCopyFileW = modkernel32.NewProc("CopyFileW") +) + +// writeFileFromReader writes an output file from an io.Reader +func writeFileFromReader(path string, reader io.Reader, timeoutSeconds int, context string) (int64, error) { + outFile, err := os.Create(path) + if err != nil { + return 0, fmt.Errorf("opengcs: writeFileFromReader: failed to create %s: %s", path, err) + } + defer outFile.Close() + return copyWithTimeout(outFile, reader, 0, timeoutSeconds, context) +} + +// copyWithTimeout is a wrapper for io.Copy using a timeout duration +func copyWithTimeout(dst io.Writer, src io.Reader, size int64, timeoutSeconds int, context string) (int64, error) { + logrus.Debugf("opengcs: copywithtimeout: size %d: timeout %d: (%s)", size, timeoutSeconds, context) + + type resultType struct { + err error + bytes int64 + } + + done := make(chan resultType, 1) + go func() { + result := resultType{} + if logrus.GetLevel() < logrus.DebugLevel || logDataFromUVM == 0 { + result.bytes, result.err = io.Copy(dst, src) + } else { + // In advanced debug mode where we log (hexdump format) what is copied + // up to the number of bytes defined by environment variable + // OPENGCS_LOG_DATA_FROM_UVM + var buf bytes.Buffer + tee := io.TeeReader(src, &buf) + result.bytes, result.err = io.Copy(dst, tee) + if result.err == nil { + size := result.bytes + if size > logDataFromUVM { + size = logDataFromUVM + } + if size > 0 { + bytes := make([]byte, size) + if _, err := buf.Read(bytes); err == nil { + logrus.Debugf(fmt.Sprintf("opengcs: copyWithTimeout\n%s", hex.Dump(bytes))) + } + } + } + } + done <- result + }() + + var result resultType + timedout := time.After(time.Duration(timeoutSeconds) * time.Second) + + select { + case <-timedout: + return 0, fmt.Errorf("opengcs: copyWithTimeout: timed out (%s)", context) + case result = <-done: + if result.err != nil && result.err != io.EOF { + // See https://github.com/golang/go/blob/f3f29d1dea525f48995c1693c609f5e67c046893/src/os/exec/exec_windows.go for a clue as to why we are doing this :) + if se, ok := result.err.(syscall.Errno); ok { + const ( + errNoData = syscall.Errno(232) + errBrokenPipe = syscall.Errno(109) + ) + if se == errNoData || se == errBrokenPipe { + logrus.Debugf("opengcs: copyWithTimeout: hit NoData or BrokenPipe: %d: %s", se, context) + return result.bytes, nil + } + } + return 0, fmt.Errorf("opengcs: copyWithTimeout: error reading: '%s' after %d bytes (%s)", result.err, result.bytes, context) + } + } + logrus.Debugf("opengcs: copyWithTimeout: success - copied %d bytes (%s)", result.bytes, context) + return result.bytes, nil +} + +// CopyFile is a utility for copying a file - used for the sandbox cache. +// Uses CopyFileW win32 API for performance +func CopyFile(srcFile, destFile string, overwrite bool) error { + var bFailIfExists uint32 = 1 + if overwrite { + bFailIfExists = 0 + } + + lpExistingFileName, err := syscall.UTF16PtrFromString(srcFile) + if err != nil { + return err + } + lpNewFileName, err := syscall.UTF16PtrFromString(destFile) + if err != nil { + return err + } + r1, _, err := syscall.Syscall( + procCopyFileW.Addr(), + 3, + uintptr(unsafe.Pointer(lpExistingFileName)), + uintptr(unsafe.Pointer(lpNewFileName)), + uintptr(bFailIfExists)) + if r1 == 0 { + return fmt.Errorf("failed CopyFileW Win32 call from '%s' to '%s': %s", srcFile, destFile, err) + } + return nil +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/opengcs/client/vhdtotar.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/opengcs/client/vhdtotar.go new file mode 100644 index 0000000000..72e9a24ff9 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/opengcs/client/vhdtotar.go @@ -0,0 +1,69 @@ +// +build windows + +package client + +import ( + "fmt" + "io" + "os" + + "github.com/sirupsen/logrus" +) + +// VhdToTar does what is says - it exports a VHD in a specified +// folder (either a read-only layer.vhd, or a read-write sandbox.vhd) to a +// ReadCloser containing a tar-stream of the layers contents. +func (config *Config) VhdToTar(vhdFile string, uvmMountPath string, isSandbox bool, vhdSize int64) (io.ReadCloser, error) { + logrus.Debugf("opengcs: VhdToTar: %s isSandbox: %t", vhdFile, isSandbox) + + if config.Uvm == nil { + return nil, fmt.Errorf("cannot VhdToTar as no utility VM is in configuration") + } + + defer config.DebugGCS() + + vhdHandle, err := os.Open(vhdFile) + if err != nil { + return nil, fmt.Errorf("opengcs: VhdToTar: failed to open %s: %s", vhdFile, err) + } + defer vhdHandle.Close() + logrus.Debugf("opengcs: VhdToTar: exporting %s, size %d, isSandbox %t", vhdHandle.Name(), vhdSize, isSandbox) + + // Different binary depending on whether a RO layer or a RW sandbox + command := "vhd2tar" + if isSandbox { + command = fmt.Sprintf("exportSandbox -path %s", uvmMountPath) + } + + // Start the binary in the utility VM + process, err := config.createUtilsProcess(command) + if err != nil { + return nil, fmt.Errorf("opengcs: VhdToTar: %s: failed to create utils process %s: %s", vhdHandle.Name(), command, err) + } + + if !isSandbox { + // Send the VHD contents to the utility VM processes stdin handle if not a sandbox + logrus.Debugf("opengcs: VhdToTar: copying the layer VHD into the utility VM") + if _, err = copyWithTimeout(process.Stdin, vhdHandle, vhdSize, config.UvmTimeoutSeconds, fmt.Sprintf("vhdtotarstream: sending %s to %s", vhdHandle.Name(), command)); err != nil { + process.Process.Close() + return nil, fmt.Errorf("opengcs: VhdToTar: %s: failed to copyWithTimeout on the stdin pipe (to utility VM): %s", vhdHandle.Name(), err) + } + } + + // Start a goroutine which copies the stdout (ie the tar stream) + reader, writer := io.Pipe() + go func() { + defer writer.Close() + defer process.Process.Close() + logrus.Debugf("opengcs: VhdToTar: copying tar stream back from the utility VM") + bytes, err := copyWithTimeout(writer, process.Stdout, vhdSize, config.UvmTimeoutSeconds, fmt.Sprintf("vhdtotarstream: copy tarstream from %s", command)) + if err != nil { + logrus.Errorf("opengcs: VhdToTar: %s: copyWithTimeout on the stdout pipe (from utility VM) failed: %s", vhdHandle.Name(), err) + } + logrus.Debugf("opengcs: VhdToTar: copied %d bytes of the tarstream of %s from the utility VM", bytes, vhdHandle.Name()) + }() + + // Return the read-side of the pipe connected to the goroutine which is reading from the stdout of the process in the utility VM + return reader, nil + +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/opengcs/vsockexec/vsockexec.c b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/opengcs/vsockexec/vsockexec.c new file mode 100644 index 0000000000..7a26d4c0da --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/Microsoft/opengcs/vsockexec/vsockexec.c @@ -0,0 +1,129 @@ +// vsockexec opens vsock connections for the specified stdio descriptors and +// then execs the specified process. + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef USE_TCP +static const int tcpmode = 1; +#else +static const int tcpmode; +#endif + +static int openvsock(unsigned int cid, unsigned int port) +{ + int s = socket(AF_VSOCK, SOCK_STREAM, 0); + if (s < 0) { + perror("socket: AF_VSOCK"); + return -1; + } + + struct sockaddr_vm addr = {0}; + addr.svm_family = AF_VSOCK; + addr.svm_port = port; + addr.svm_cid = cid; + if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + fprintf(stderr, "connect: port %u: %s", port, strerror(errno)); + return -1; + } + + return s; +} + +static int opentcp(unsigned short port) +{ + int s = socket(AF_INET, SOCK_STREAM, 0); + if (s < 0) { + perror("socket: AF_INET"); + return -1; + } + + struct sockaddr_in addr = {0}; + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + fprintf(stderr, "connect: port %u: %s\n", port, strerror(errno)); + return -1; + } + + return s; +} + +_Noreturn static void usage(const char *argv0) +{ + fprintf(stderr, "%s [-i port] [-o port] [-e port] -- program [args...]\n", argv0); + exit(1); +} + +int main(int argc, char **argv) +{ + unsigned int ports[3] = {0}; + int sockets[3] = {-1, -1, -1}; + int c; + while ((c = getopt(argc, argv, "+i:o:e:")) != -1) { + switch (c) { + case 'i': + ports[0] = strtoul(optarg, NULL, 10); + break; + + case 'o': + ports[1] = strtoul(optarg, NULL, 10); + break; + + case 'e': + ports[2] = strtoul(optarg, NULL, 10); + break; + + default: + usage(argv[0]); + } + } + + if (optind == argc) { + fprintf(stderr, "%s: missing program argument\n", argv[0]); + usage(argv[0]); + } + + for (int i = 0; i < 3; i++) { + if (ports[i] != 0) { + int j; + for (j = 0; j < i; j++) { + if (ports[i] == ports[j]) { + int s = dup(sockets[j]); + if (s < 0) { + perror("dup"); + return 1; + } + sockets[i] = s; + break; + } + } + + if (j == i) { + int s = tcpmode ? opentcp(ports[i]) : openvsock(VMADDR_CID_HOST, ports[i]); + if (s < 0) { + return 1; + } + sockets[i] = s; + } + } + } + + for (int i = 0; i < 3; i++) { + if (sockets[i] >= 0) { + dup2(sockets[i], i); + close(sockets[i]); + } + } + + execvp(argv[optind], argv + optind); + fprintf(stderr, "execvp: %s: %s\n", argv[optind], strerror(errno)); + return 1; +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/blang/semver/LICENSE b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/blang/semver/LICENSE new file mode 100644 index 0000000000..5ba5c86fcb --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/blang/semver/LICENSE @@ -0,0 +1,22 @@ +The MIT License + +Copyright (c) 2014 Benedikt Lang + +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. + diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/blang/semver/README.md b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/blang/semver/README.md new file mode 100644 index 0000000000..4399639e23 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/blang/semver/README.md @@ -0,0 +1,191 @@ +semver for golang [![Build Status](https://drone.io/github.com/blang/semver/status.png)](https://drone.io/github.com/blang/semver/latest) [![GoDoc](https://godoc.org/github.com/blang/semver?status.png)](https://godoc.org/github.com/blang/semver) [![Coverage Status](https://img.shields.io/coveralls/blang/semver.svg)](https://coveralls.io/r/blang/semver?branch=master) +====== + +semver is a [Semantic Versioning](http://semver.org/) library written in golang. It fully covers spec version `2.0.0`. + +Usage +----- +```bash +$ go get github.com/blang/semver +``` +Note: Always vendor your dependencies or fix on a specific version tag. + +```go +import github.com/blang/semver +v1, err := semver.Make("1.0.0-beta") +v2, err := semver.Make("2.0.0-beta") +v1.Compare(v2) +``` + +Also check the [GoDocs](http://godoc.org/github.com/blang/semver). + +Why should I use this lib? +----- + +- Fully spec compatible +- No reflection +- No regex +- Fully tested (Coverage >99%) +- Readable parsing/validation errors +- Fast (See [Benchmarks](#benchmarks)) +- Only Stdlib +- Uses values instead of pointers +- Many features, see below + + +Features +----- + +- Parsing and validation at all levels +- Comparator-like comparisons +- Compare Helper Methods +- InPlace manipulation +- Ranges `>=1.0.0 <2.0.0 || >=3.0.0 !3.0.1-beta.1` +- Sortable (implements sort.Interface) +- database/sql compatible (sql.Scanner/Valuer) +- encoding/json compatible (json.Marshaler/Unmarshaler) + +Ranges +------ + +A `Range` is a set of conditions which specify which versions satisfy the range. + +A condition is composed of an operator and a version. The supported operators are: + +- `<1.0.0` Less than `1.0.0` +- `<=1.0.0` Less than or equal to `1.0.0` +- `>1.0.0` Greater than `1.0.0` +- `>=1.0.0` Greater than or equal to `1.0.0` +- `1.0.0`, `=1.0.0`, `==1.0.0` Equal to `1.0.0` +- `!1.0.0`, `!=1.0.0` Not equal to `1.0.0`. Excludes version `1.0.0`. + +A `Range` can link multiple `Ranges` separated by space: + +Ranges can be linked by logical AND: + + - `>1.0.0 <2.0.0` would match between both ranges, so `1.1.1` and `1.8.7` but not `1.0.0` or `2.0.0` + - `>1.0.0 <3.0.0 !2.0.3-beta.2` would match every version between `1.0.0` and `3.0.0` except `2.0.3-beta.2` + +Ranges can also be linked by logical OR: + + - `<2.0.0 || >=3.0.0` would match `1.x.x` and `3.x.x` but not `2.x.x` + +AND has a higher precedence than OR. It's not possible to use brackets. + +Ranges can be combined by both AND and OR + + - `>1.0.0 <2.0.0 || >3.0.0 !4.2.1` would match `1.2.3`, `1.9.9`, `3.1.1`, but not `4.2.1`, `2.1.1` + +Range usage: + +``` +v, err := semver.Parse("1.2.3") +range, err := semver.ParseRange(">1.0.0 <2.0.0 || >=3.0.0") +if range(v) { + //valid +} + +``` + +Example +----- + +Have a look at full examples in [examples/main.go](examples/main.go) + +```go +import github.com/blang/semver + +v, err := semver.Make("0.0.1-alpha.preview+123.github") +fmt.Printf("Major: %d\n", v.Major) +fmt.Printf("Minor: %d\n", v.Minor) +fmt.Printf("Patch: %d\n", v.Patch) +fmt.Printf("Pre: %s\n", v.Pre) +fmt.Printf("Build: %s\n", v.Build) + +// Prerelease versions array +if len(v.Pre) > 0 { + fmt.Println("Prerelease versions:") + for i, pre := range v.Pre { + fmt.Printf("%d: %q\n", i, pre) + } +} + +// Build meta data array +if len(v.Build) > 0 { + fmt.Println("Build meta data:") + for i, build := range v.Build { + fmt.Printf("%d: %q\n", i, build) + } +} + +v001, err := semver.Make("0.0.1") +// Compare using helpers: v.GT(v2), v.LT, v.GTE, v.LTE +v001.GT(v) == true +v.LT(v001) == true +v.GTE(v) == true +v.LTE(v) == true + +// Or use v.Compare(v2) for comparisons (-1, 0, 1): +v001.Compare(v) == 1 +v.Compare(v001) == -1 +v.Compare(v) == 0 + +// Manipulate Version in place: +v.Pre[0], err = semver.NewPRVersion("beta") +if err != nil { + fmt.Printf("Error parsing pre release version: %q", err) +} + +fmt.Println("\nValidate versions:") +v.Build[0] = "?" + +err = v.Validate() +if err != nil { + fmt.Printf("Validation failed: %s\n", err) +} +``` + + +Benchmarks +----- + + BenchmarkParseSimple-4 5000000 390 ns/op 48 B/op 1 allocs/op + BenchmarkParseComplex-4 1000000 1813 ns/op 256 B/op 7 allocs/op + BenchmarkParseAverage-4 1000000 1171 ns/op 163 B/op 4 allocs/op + BenchmarkStringSimple-4 20000000 119 ns/op 16 B/op 1 allocs/op + BenchmarkStringLarger-4 10000000 206 ns/op 32 B/op 2 allocs/op + BenchmarkStringComplex-4 5000000 324 ns/op 80 B/op 3 allocs/op + BenchmarkStringAverage-4 5000000 273 ns/op 53 B/op 2 allocs/op + BenchmarkValidateSimple-4 200000000 9.33 ns/op 0 B/op 0 allocs/op + BenchmarkValidateComplex-4 3000000 469 ns/op 0 B/op 0 allocs/op + BenchmarkValidateAverage-4 5000000 256 ns/op 0 B/op 0 allocs/op + BenchmarkCompareSimple-4 100000000 11.8 ns/op 0 B/op 0 allocs/op + BenchmarkCompareComplex-4 50000000 30.8 ns/op 0 B/op 0 allocs/op + BenchmarkCompareAverage-4 30000000 41.5 ns/op 0 B/op 0 allocs/op + BenchmarkSort-4 3000000 419 ns/op 256 B/op 2 allocs/op + BenchmarkRangeParseSimple-4 2000000 850 ns/op 192 B/op 5 allocs/op + BenchmarkRangeParseAverage-4 1000000 1677 ns/op 400 B/op 10 allocs/op + BenchmarkRangeParseComplex-4 300000 5214 ns/op 1440 B/op 30 allocs/op + BenchmarkRangeMatchSimple-4 50000000 25.6 ns/op 0 B/op 0 allocs/op + BenchmarkRangeMatchAverage-4 30000000 56.4 ns/op 0 B/op 0 allocs/op + BenchmarkRangeMatchComplex-4 10000000 153 ns/op 0 B/op 0 allocs/op + +See benchmark cases at [semver_test.go](semver_test.go) + + +Motivation +----- + +I simply couldn't find any lib supporting the full spec. Others were just wrong or used reflection and regex which i don't like. + + +Contribution +----- + +Feel free to make a pull request. For bigger changes create a issue first to discuss about it. + + +License +----- + +See [LICENSE](LICENSE) file. diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/blang/semver/json.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/blang/semver/json.go new file mode 100644 index 0000000000..a74bf7c449 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/blang/semver/json.go @@ -0,0 +1,23 @@ +package semver + +import ( + "encoding/json" +) + +// MarshalJSON implements the encoding/json.Marshaler interface. +func (v Version) MarshalJSON() ([]byte, error) { + return json.Marshal(v.String()) +} + +// UnmarshalJSON implements the encoding/json.Unmarshaler interface. +func (v *Version) UnmarshalJSON(data []byte) (err error) { + var versionString string + + if err = json.Unmarshal(data, &versionString); err != nil { + return + } + + *v, err = Parse(versionString) + + return +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/blang/semver/range.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/blang/semver/range.go new file mode 100644 index 0000000000..0a8eaa1c9b --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/blang/semver/range.go @@ -0,0 +1,224 @@ +package semver + +import ( + "fmt" + "strings" + "unicode" +) + +type comparator func(Version, Version) bool + +var ( + compEQ comparator = func(v1 Version, v2 Version) bool { + return v1.Compare(v2) == 0 + } + compNE = func(v1 Version, v2 Version) bool { + return v1.Compare(v2) != 0 + } + compGT = func(v1 Version, v2 Version) bool { + return v1.Compare(v2) == 1 + } + compGE = func(v1 Version, v2 Version) bool { + return v1.Compare(v2) >= 0 + } + compLT = func(v1 Version, v2 Version) bool { + return v1.Compare(v2) == -1 + } + compLE = func(v1 Version, v2 Version) bool { + return v1.Compare(v2) <= 0 + } +) + +type versionRange struct { + v Version + c comparator +} + +// rangeFunc creates a Range from the given versionRange. +func (vr *versionRange) rangeFunc() Range { + return Range(func(v Version) bool { + return vr.c(v, vr.v) + }) +} + +// Range represents a range of versions. +// A Range can be used to check if a Version satisfies it: +// +// range, err := semver.ParseRange(">1.0.0 <2.0.0") +// range(semver.MustParse("1.1.1") // returns true +type Range func(Version) bool + +// OR combines the existing Range with another Range using logical OR. +func (rf Range) OR(f Range) Range { + return Range(func(v Version) bool { + return rf(v) || f(v) + }) +} + +// AND combines the existing Range with another Range using logical AND. +func (rf Range) AND(f Range) Range { + return Range(func(v Version) bool { + return rf(v) && f(v) + }) +} + +// ParseRange parses a range and returns a Range. +// If the range could not be parsed an error is returned. +// +// Valid ranges are: +// - "<1.0.0" +// - "<=1.0.0" +// - ">1.0.0" +// - ">=1.0.0" +// - "1.0.0", "=1.0.0", "==1.0.0" +// - "!1.0.0", "!=1.0.0" +// +// A Range can consist of multiple ranges separated by space: +// Ranges can be linked by logical AND: +// - ">1.0.0 <2.0.0" would match between both ranges, so "1.1.1" and "1.8.7" but not "1.0.0" or "2.0.0" +// - ">1.0.0 <3.0.0 !2.0.3-beta.2" would match every version between 1.0.0 and 3.0.0 except 2.0.3-beta.2 +// +// Ranges can also be linked by logical OR: +// - "<2.0.0 || >=3.0.0" would match "1.x.x" and "3.x.x" but not "2.x.x" +// +// AND has a higher precedence than OR. It's not possible to use brackets. +// +// Ranges can be combined by both AND and OR +// +// - `>1.0.0 <2.0.0 || >3.0.0 !4.2.1` would match `1.2.3`, `1.9.9`, `3.1.1`, but not `4.2.1`, `2.1.1` +func ParseRange(s string) (Range, error) { + parts := splitAndTrim(s) + orParts, err := splitORParts(parts) + if err != nil { + return nil, err + } + var orFn Range + for _, p := range orParts { + var andFn Range + for _, ap := range p { + opStr, vStr, err := splitComparatorVersion(ap) + if err != nil { + return nil, err + } + vr, err := buildVersionRange(opStr, vStr) + if err != nil { + return nil, fmt.Errorf("Could not parse Range %q: %s", ap, err) + } + rf := vr.rangeFunc() + + // Set function + if andFn == nil { + andFn = rf + } else { // Combine with existing function + andFn = andFn.AND(rf) + } + } + if orFn == nil { + orFn = andFn + } else { + orFn = orFn.OR(andFn) + } + + } + return orFn, nil +} + +// splitORParts splits the already cleaned parts by '||'. +// Checks for invalid positions of the operator and returns an +// error if found. +func splitORParts(parts []string) ([][]string, error) { + var ORparts [][]string + last := 0 + for i, p := range parts { + if p == "||" { + if i == 0 { + return nil, fmt.Errorf("First element in range is '||'") + } + ORparts = append(ORparts, parts[last:i]) + last = i + 1 + } + } + if last == len(parts) { + return nil, fmt.Errorf("Last element in range is '||'") + } + ORparts = append(ORparts, parts[last:]) + return ORparts, nil +} + +// buildVersionRange takes a slice of 2: operator and version +// and builds a versionRange, otherwise an error. +func buildVersionRange(opStr, vStr string) (*versionRange, error) { + c := parseComparator(opStr) + if c == nil { + return nil, fmt.Errorf("Could not parse comparator %q in %q", opStr, strings.Join([]string{opStr, vStr}, "")) + } + v, err := Parse(vStr) + if err != nil { + return nil, fmt.Errorf("Could not parse version %q in %q: %s", vStr, strings.Join([]string{opStr, vStr}, ""), err) + } + + return &versionRange{ + v: v, + c: c, + }, nil + +} + +// splitAndTrim splits a range string by spaces and cleans leading and trailing spaces +func splitAndTrim(s string) (result []string) { + last := 0 + for i := 0; i < len(s); i++ { + if s[i] == ' ' { + if last < i-1 { + result = append(result, s[last:i]) + } + last = i + 1 + } + } + if last < len(s)-1 { + result = append(result, s[last:]) + } + // parts := strings.Split(s, " ") + // for _, x := range parts { + // if s := strings.TrimSpace(x); len(s) != 0 { + // result = append(result, s) + // } + // } + return +} + +// splitComparatorVersion splits the comparator from the version. +// Spaces between the comparator and the version are not allowed. +// Input must be free of leading or trailing spaces. +func splitComparatorVersion(s string) (string, string, error) { + i := strings.IndexFunc(s, unicode.IsDigit) + if i == -1 { + return "", "", fmt.Errorf("Could not get version from string: %q", s) + } + return strings.TrimSpace(s[0:i]), s[i:], nil +} + +func parseComparator(s string) comparator { + switch s { + case "==": + fallthrough + case "": + fallthrough + case "=": + return compEQ + case ">": + return compGT + case ">=": + return compGE + case "<": + return compLT + case "<=": + return compLE + case "!": + fallthrough + case "!=": + return compNE + } + + return nil +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/blang/semver/semver.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/blang/semver/semver.go new file mode 100644 index 0000000000..bbf85ce972 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/blang/semver/semver.go @@ -0,0 +1,395 @@ +package semver + +import ( + "errors" + "fmt" + "strconv" + "strings" +) + +const ( + numbers string = "0123456789" + alphas = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-" + alphanum = alphas + numbers +) + +// SpecVersion is the latest fully supported spec version of semver +var SpecVersion = Version{ + Major: 2, + Minor: 0, + Patch: 0, +} + +// Version represents a semver compatible version +type Version struct { + Major uint64 + Minor uint64 + Patch uint64 + Pre []PRVersion + Build []string //No Precendence +} + +// Version to string +func (v Version) String() string { + b := make([]byte, 0, 5) + b = strconv.AppendUint(b, v.Major, 10) + b = append(b, '.') + b = strconv.AppendUint(b, v.Minor, 10) + b = append(b, '.') + b = strconv.AppendUint(b, v.Patch, 10) + + if len(v.Pre) > 0 { + b = append(b, '-') + b = append(b, v.Pre[0].String()...) + + for _, pre := range v.Pre[1:] { + b = append(b, '.') + b = append(b, pre.String()...) + } + } + + if len(v.Build) > 0 { + b = append(b, '+') + b = append(b, v.Build[0]...) + + for _, build := range v.Build[1:] { + b = append(b, '.') + b = append(b, build...) + } + } + + return string(b) +} + +// Equals checks if v is equal to o. +func (v Version) Equals(o Version) bool { + return (v.Compare(o) == 0) +} + +// EQ checks if v is equal to o. +func (v Version) EQ(o Version) bool { + return (v.Compare(o) == 0) +} + +// NE checks if v is not equal to o. +func (v Version) NE(o Version) bool { + return (v.Compare(o) != 0) +} + +// GT checks if v is greater than o. +func (v Version) GT(o Version) bool { + return (v.Compare(o) == 1) +} + +// GTE checks if v is greater than or equal to o. +func (v Version) GTE(o Version) bool { + return (v.Compare(o) >= 0) +} + +// GE checks if v is greater than or equal to o. +func (v Version) GE(o Version) bool { + return (v.Compare(o) >= 0) +} + +// LT checks if v is less than o. +func (v Version) LT(o Version) bool { + return (v.Compare(o) == -1) +} + +// LTE checks if v is less than or equal to o. +func (v Version) LTE(o Version) bool { + return (v.Compare(o) <= 0) +} + +// LE checks if v is less than or equal to o. +func (v Version) LE(o Version) bool { + return (v.Compare(o) <= 0) +} + +// Compare compares Versions v to o: +// -1 == v is less than o +// 0 == v is equal to o +// 1 == v is greater than o +func (v Version) Compare(o Version) int { + if v.Major != o.Major { + if v.Major > o.Major { + return 1 + } + return -1 + } + if v.Minor != o.Minor { + if v.Minor > o.Minor { + return 1 + } + return -1 + } + if v.Patch != o.Patch { + if v.Patch > o.Patch { + return 1 + } + return -1 + } + + // Quick comparison if a version has no prerelease versions + if len(v.Pre) == 0 && len(o.Pre) == 0 { + return 0 + } else if len(v.Pre) == 0 && len(o.Pre) > 0 { + return 1 + } else if len(v.Pre) > 0 && len(o.Pre) == 0 { + return -1 + } + + i := 0 + for ; i < len(v.Pre) && i < len(o.Pre); i++ { + if comp := v.Pre[i].Compare(o.Pre[i]); comp == 0 { + continue + } else if comp == 1 { + return 1 + } else { + return -1 + } + } + + // If all pr versions are the equal but one has further prversion, this one greater + if i == len(v.Pre) && i == len(o.Pre) { + return 0 + } else if i == len(v.Pre) && i < len(o.Pre) { + return -1 + } else { + return 1 + } + +} + +// Validate validates v and returns error in case +func (v Version) Validate() error { + // Major, Minor, Patch already validated using uint64 + + for _, pre := range v.Pre { + if !pre.IsNum { //Numeric prerelease versions already uint64 + if len(pre.VersionStr) == 0 { + return fmt.Errorf("Prerelease can not be empty %q", pre.VersionStr) + } + if !containsOnly(pre.VersionStr, alphanum) { + return fmt.Errorf("Invalid character(s) found in prerelease %q", pre.VersionStr) + } + } + } + + for _, build := range v.Build { + if len(build) == 0 { + return fmt.Errorf("Build meta data can not be empty %q", build) + } + if !containsOnly(build, alphanum) { + return fmt.Errorf("Invalid character(s) found in build meta data %q", build) + } + } + + return nil +} + +// New is an alias for Parse and returns a pointer, parses version string and returns a validated Version or error +func New(s string) (vp *Version, err error) { + v, err := Parse(s) + vp = &v + return +} + +// Make is an alias for Parse, parses version string and returns a validated Version or error +func Make(s string) (Version, error) { + return Parse(s) +} + +// Parse parses version string and returns a validated Version or error +func Parse(s string) (Version, error) { + if len(s) == 0 { + return Version{}, errors.New("Version string empty") + } + + // Split into major.minor.(patch+pr+meta) + parts := strings.SplitN(s, ".", 3) + if len(parts) != 3 { + return Version{}, errors.New("No Major.Minor.Patch elements found") + } + + // Major + if !containsOnly(parts[0], numbers) { + return Version{}, fmt.Errorf("Invalid character(s) found in major number %q", parts[0]) + } + if hasLeadingZeroes(parts[0]) { + return Version{}, fmt.Errorf("Major number must not contain leading zeroes %q", parts[0]) + } + major, err := strconv.ParseUint(parts[0], 10, 64) + if err != nil { + return Version{}, err + } + + // Minor + if !containsOnly(parts[1], numbers) { + return Version{}, fmt.Errorf("Invalid character(s) found in minor number %q", parts[1]) + } + if hasLeadingZeroes(parts[1]) { + return Version{}, fmt.Errorf("Minor number must not contain leading zeroes %q", parts[1]) + } + minor, err := strconv.ParseUint(parts[1], 10, 64) + if err != nil { + return Version{}, err + } + + v := Version{} + v.Major = major + v.Minor = minor + + var build, prerelease []string + patchStr := parts[2] + + if buildIndex := strings.IndexRune(patchStr, '+'); buildIndex != -1 { + build = strings.Split(patchStr[buildIndex+1:], ".") + patchStr = patchStr[:buildIndex] + } + + if preIndex := strings.IndexRune(patchStr, '-'); preIndex != -1 { + prerelease = strings.Split(patchStr[preIndex+1:], ".") + patchStr = patchStr[:preIndex] + } + + if !containsOnly(patchStr, numbers) { + return Version{}, fmt.Errorf("Invalid character(s) found in patch number %q", patchStr) + } + if hasLeadingZeroes(patchStr) { + return Version{}, fmt.Errorf("Patch number must not contain leading zeroes %q", patchStr) + } + patch, err := strconv.ParseUint(patchStr, 10, 64) + if err != nil { + return Version{}, err + } + + v.Patch = patch + + // Prerelease + for _, prstr := range prerelease { + parsedPR, err := NewPRVersion(prstr) + if err != nil { + return Version{}, err + } + v.Pre = append(v.Pre, parsedPR) + } + + // Build meta data + for _, str := range build { + if len(str) == 0 { + return Version{}, errors.New("Build meta data is empty") + } + if !containsOnly(str, alphanum) { + return Version{}, fmt.Errorf("Invalid character(s) found in build meta data %q", str) + } + v.Build = append(v.Build, str) + } + + return v, nil +} + +// MustParse is like Parse but panics if the version cannot be parsed. +func MustParse(s string) Version { + v, err := Parse(s) + if err != nil { + panic(`semver: Parse(` + s + `): ` + err.Error()) + } + return v +} + +// PRVersion represents a PreRelease Version +type PRVersion struct { + VersionStr string + VersionNum uint64 + IsNum bool +} + +// NewPRVersion creates a new valid prerelease version +func NewPRVersion(s string) (PRVersion, error) { + if len(s) == 0 { + return PRVersion{}, errors.New("Prerelease is empty") + } + v := PRVersion{} + if containsOnly(s, numbers) { + if hasLeadingZeroes(s) { + return PRVersion{}, fmt.Errorf("Numeric PreRelease version must not contain leading zeroes %q", s) + } + num, err := strconv.ParseUint(s, 10, 64) + + // Might never be hit, but just in case + if err != nil { + return PRVersion{}, err + } + v.VersionNum = num + v.IsNum = true + } else if containsOnly(s, alphanum) { + v.VersionStr = s + v.IsNum = false + } else { + return PRVersion{}, fmt.Errorf("Invalid character(s) found in prerelease %q", s) + } + return v, nil +} + +// IsNumeric checks if prerelease-version is numeric +func (v PRVersion) IsNumeric() bool { + return v.IsNum +} + +// Compare compares two PreRelease Versions v and o: +// -1 == v is less than o +// 0 == v is equal to o +// 1 == v is greater than o +func (v PRVersion) Compare(o PRVersion) int { + if v.IsNum && !o.IsNum { + return -1 + } else if !v.IsNum && o.IsNum { + return 1 + } else if v.IsNum && o.IsNum { + if v.VersionNum == o.VersionNum { + return 0 + } else if v.VersionNum > o.VersionNum { + return 1 + } else { + return -1 + } + } else { // both are Alphas + if v.VersionStr == o.VersionStr { + return 0 + } else if v.VersionStr > o.VersionStr { + return 1 + } else { + return -1 + } + } +} + +// PreRelease version to string +func (v PRVersion) String() string { + if v.IsNum { + return strconv.FormatUint(v.VersionNum, 10) + } + return v.VersionStr +} + +func containsOnly(s string, set string) bool { + return strings.IndexFunc(s, func(r rune) bool { + return !strings.ContainsRune(set, r) + }) == -1 +} + +func hasLeadingZeroes(s string) bool { + return len(s) > 1 && s[0] == '0' +} + +// NewBuildVersion creates a new valid build version +func NewBuildVersion(s string) (string, error) { + if len(s) == 0 { + return "", errors.New("Buildversion is empty") + } + if !containsOnly(s, alphanum) { + return "", fmt.Errorf("Invalid character(s) found in build meta data %q", s) + } + return s, nil +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/blang/semver/sort.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/blang/semver/sort.go new file mode 100644 index 0000000000..e18f880826 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/blang/semver/sort.go @@ -0,0 +1,28 @@ +package semver + +import ( + "sort" +) + +// Versions represents multiple versions. +type Versions []Version + +// Len returns length of version collection +func (s Versions) Len() int { + return len(s) +} + +// Swap swaps two versions inside the collection by its indices +func (s Versions) Swap(i, j int) { + s[i], s[j] = s[j], s[i] +} + +// Less checks if version at index i is less than version at index j +func (s Versions) Less(i, j int) bool { + return s[i].LT(s[j]) +} + +// Sort sorts a slice of versions +func Sort(versions []Version) { + sort.Sort(Versions(versions)) +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/blang/semver/sql.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/blang/semver/sql.go new file mode 100644 index 0000000000..eb4d802666 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/blang/semver/sql.go @@ -0,0 +1,30 @@ +package semver + +import ( + "database/sql/driver" + "fmt" +) + +// Scan implements the database/sql.Scanner interface. +func (v *Version) Scan(src interface{}) (err error) { + var str string + switch src := src.(type) { + case string: + str = src + case []byte: + str = string(src) + default: + return fmt.Errorf("Version.Scan: cannot convert %T to string.", src) + } + + if t, err := Parse(str); err == nil { + *v = t + } + + return +} + +// Value implements the database/sql/driver.Valuer interface. +func (v Version) Value() (driver.Value, error) { + return v.String(), nil +} diff --git a/vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/LICENSE b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/console/LICENSE similarity index 100% rename from vendor/github.com/Microsoft/hcsshim/cmd/go-runhcs/LICENSE rename to vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/console/LICENSE diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/console/README.md b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/console/README.md new file mode 100644 index 0000000000..4c56d9d134 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/console/README.md @@ -0,0 +1,17 @@ +# console + +[![Build Status](https://travis-ci.org/containerd/console.svg?branch=master)](https://travis-ci.org/containerd/console) + +Golang package for dealing with consoles. Light on deps and a simple API. + +## Modifying the current process + +```go +current := console.Current() +defer current.Reset() + +if err := current.SetRaw(); err != nil { +} +ws, err := current.Size() +current.Resize(ws) +``` diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/console/console.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/console/console.go new file mode 100644 index 0000000000..c187a9b412 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/console/console.go @@ -0,0 +1,78 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package console + +import ( + "errors" + "io" + "os" +) + +var ErrNotAConsole = errors.New("provided file is not a console") + +type Console interface { + io.Reader + io.Writer + io.Closer + + // Resize resizes the console to the provided window size + Resize(WinSize) error + // ResizeFrom resizes the calling console to the size of the + // provided console + ResizeFrom(Console) error + // SetRaw sets the console in raw mode + SetRaw() error + // DisableEcho disables echo on the console + DisableEcho() error + // Reset restores the console to its orignal state + Reset() error + // Size returns the window size of the console + Size() (WinSize, error) + // Fd returns the console's file descriptor + Fd() uintptr + // Name returns the console's file name + Name() string +} + +// WinSize specifies the window size of the console +type WinSize struct { + // Height of the console + Height uint16 + // Width of the console + Width uint16 + x uint16 + y uint16 +} + +// Current returns the current processes console +func Current() Console { + c, err := ConsoleFromFile(os.Stdin) + if err != nil { + // stdin should always be a console for the design + // of this function + panic(err) + } + return c +} + +// ConsoleFromFile returns a console using the provided file +func ConsoleFromFile(f *os.File) (Console, error) { + if err := checkConsole(f); err != nil { + return nil, err + } + return newMaster(f) +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/console/console_linux.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/console/console_linux.go new file mode 100644 index 0000000000..42274e100e --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/console/console_linux.go @@ -0,0 +1,275 @@ +// +build linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package console + +import ( + "io" + "os" + "sync" + + "golang.org/x/sys/unix" +) + +const ( + maxEvents = 128 +) + +// Epoller manages multiple epoll consoles using edge-triggered epoll api so we +// dont have to deal with repeated wake-up of EPOLLER or EPOLLHUP. +// For more details, see: +// - https://github.com/systemd/systemd/pull/4262 +// - https://github.com/moby/moby/issues/27202 +// +// Example usage of Epoller and EpollConsole can be as follow: +// +// epoller, _ := NewEpoller() +// epollConsole, _ := epoller.Add(console) +// go epoller.Wait() +// var ( +// b bytes.Buffer +// wg sync.WaitGroup +// ) +// wg.Add(1) +// go func() { +// io.Copy(&b, epollConsole) +// wg.Done() +// }() +// // perform I/O on the console +// epollConsole.Shutdown(epoller.CloseConsole) +// wg.Wait() +// epollConsole.Close() +type Epoller struct { + efd int + mu sync.Mutex + fdMapping map[int]*EpollConsole +} + +// NewEpoller returns an instance of epoller with a valid epoll fd. +func NewEpoller() (*Epoller, error) { + efd, err := unix.EpollCreate1(unix.EPOLL_CLOEXEC) + if err != nil { + return nil, err + } + return &Epoller{ + efd: efd, + fdMapping: make(map[int]*EpollConsole), + }, nil +} + +// Add creates an epoll console based on the provided console. The console will +// be registered with EPOLLET (i.e. using edge-triggered notification) and its +// file descriptor will be set to non-blocking mode. After this, user should use +// the return console to perform I/O. +func (e *Epoller) Add(console Console) (*EpollConsole, error) { + sysfd := int(console.Fd()) + // Set sysfd to non-blocking mode + if err := unix.SetNonblock(sysfd, true); err != nil { + return nil, err + } + + ev := unix.EpollEvent{ + Events: unix.EPOLLIN | unix.EPOLLOUT | unix.EPOLLRDHUP | unix.EPOLLET, + Fd: int32(sysfd), + } + if err := unix.EpollCtl(e.efd, unix.EPOLL_CTL_ADD, sysfd, &ev); err != nil { + return nil, err + } + ef := &EpollConsole{ + Console: console, + sysfd: sysfd, + readc: sync.NewCond(&sync.Mutex{}), + writec: sync.NewCond(&sync.Mutex{}), + } + e.mu.Lock() + e.fdMapping[sysfd] = ef + e.mu.Unlock() + return ef, nil +} + +// Wait starts the loop to wait for its consoles' notifications and signal +// appropriate console that it can perform I/O. +func (e *Epoller) Wait() error { + events := make([]unix.EpollEvent, maxEvents) + for { + n, err := unix.EpollWait(e.efd, events, -1) + if err != nil { + // EINTR: The call was interrupted by a signal handler before either + // any of the requested events occurred or the timeout expired + if err == unix.EINTR { + continue + } + return err + } + for i := 0; i < n; i++ { + ev := &events[i] + // the console is ready to be read from + if ev.Events&(unix.EPOLLIN|unix.EPOLLHUP|unix.EPOLLERR) != 0 { + if epfile := e.getConsole(int(ev.Fd)); epfile != nil { + epfile.signalRead() + } + } + // the console is ready to be written to + if ev.Events&(unix.EPOLLOUT|unix.EPOLLHUP|unix.EPOLLERR) != 0 { + if epfile := e.getConsole(int(ev.Fd)); epfile != nil { + epfile.signalWrite() + } + } + } + } +} + +// CloseConsole unregisters the console's file descriptor from epoll interface +func (e *Epoller) CloseConsole(fd int) error { + e.mu.Lock() + defer e.mu.Unlock() + delete(e.fdMapping, fd) + return unix.EpollCtl(e.efd, unix.EPOLL_CTL_DEL, fd, &unix.EpollEvent{}) +} + +func (e *Epoller) getConsole(sysfd int) *EpollConsole { + e.mu.Lock() + f := e.fdMapping[sysfd] + e.mu.Unlock() + return f +} + +// Close closes the epoll fd +func (e *Epoller) Close() error { + return unix.Close(e.efd) +} + +// EpollConsole acts like a console but registers its file descriptor with an +// epoll fd and uses epoll API to perform I/O. +type EpollConsole struct { + Console + readc *sync.Cond + writec *sync.Cond + sysfd int + closed bool +} + +// Read reads up to len(p) bytes into p. It returns the number of bytes read +// (0 <= n <= len(p)) and any error encountered. +// +// If the console's read returns EAGAIN or EIO, we assume that it's a +// temporary error because the other side went away and wait for the signal +// generated by epoll event to continue. +func (ec *EpollConsole) Read(p []byte) (n int, err error) { + var read int + ec.readc.L.Lock() + defer ec.readc.L.Unlock() + for { + read, err = ec.Console.Read(p[n:]) + n += read + if err != nil { + var hangup bool + if perr, ok := err.(*os.PathError); ok { + hangup = (perr.Err == unix.EAGAIN || perr.Err == unix.EIO) + } else { + hangup = (err == unix.EAGAIN || err == unix.EIO) + } + // if the other end disappear, assume this is temporary and wait for the + // signal to continue again. Unless we didnt read anything and the + // console is already marked as closed then we should exit + if hangup && !(n == 0 && len(p) > 0 && ec.closed) { + ec.readc.Wait() + continue + } + } + break + } + // if we didnt read anything then return io.EOF to end gracefully + if n == 0 && len(p) > 0 && err == nil { + err = io.EOF + } + // signal for others that we finished the read + ec.readc.Signal() + return n, err +} + +// Writes len(p) bytes from p to the console. It returns the number of bytes +// written from p (0 <= n <= len(p)) and any error encountered that caused +// the write to stop early. +// +// If writes to the console returns EAGAIN or EIO, we assume that it's a +// temporary error because the other side went away and wait for the signal +// generated by epoll event to continue. +func (ec *EpollConsole) Write(p []byte) (n int, err error) { + var written int + ec.writec.L.Lock() + defer ec.writec.L.Unlock() + for { + written, err = ec.Console.Write(p[n:]) + n += written + if err != nil { + var hangup bool + if perr, ok := err.(*os.PathError); ok { + hangup = (perr.Err == unix.EAGAIN || perr.Err == unix.EIO) + } else { + hangup = (err == unix.EAGAIN || err == unix.EIO) + } + // if the other end disappears, assume this is temporary and wait for the + // signal to continue again. + if hangup { + ec.writec.Wait() + continue + } + } + // unrecoverable error, break the loop and return the error + break + } + if n < len(p) && err == nil { + err = io.ErrShortWrite + } + // signal for others that we finished the write + ec.writec.Signal() + return n, err +} + +// Shutdown closes the file descriptor and signals call waiters for this fd. +// It accepts a callback which will be called with the console's fd. The +// callback typically will be used to do further cleanup such as unregister the +// console's fd from the epoll interface. +// User should call Shutdown and wait for all I/O operation to be finished +// before closing the console. +func (ec *EpollConsole) Shutdown(close func(int) error) error { + ec.readc.L.Lock() + defer ec.readc.L.Unlock() + ec.writec.L.Lock() + defer ec.writec.L.Unlock() + + ec.readc.Broadcast() + ec.writec.Broadcast() + ec.closed = true + return close(ec.sysfd) +} + +// signalRead signals that the console is readable. +func (ec *EpollConsole) signalRead() { + ec.readc.L.Lock() + ec.readc.Signal() + ec.readc.L.Unlock() +} + +// signalWrite signals that the console is writable. +func (ec *EpollConsole) signalWrite() { + ec.writec.L.Lock() + ec.writec.Signal() + ec.writec.L.Unlock() +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/console/console_unix.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/console/console_unix.go new file mode 100644 index 0000000000..a4a8d1267b --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/console/console_unix.go @@ -0,0 +1,158 @@ +// +build darwin freebsd linux openbsd solaris + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package console + +import ( + "os" + + "golang.org/x/sys/unix" +) + +// NewPty creates a new pty pair +// The master is returned as the first console and a string +// with the path to the pty slave is returned as the second +func NewPty() (Console, string, error) { + f, err := os.OpenFile("/dev/ptmx", unix.O_RDWR|unix.O_NOCTTY|unix.O_CLOEXEC, 0) + if err != nil { + return nil, "", err + } + slave, err := ptsname(f) + if err != nil { + return nil, "", err + } + if err := unlockpt(f); err != nil { + return nil, "", err + } + m, err := newMaster(f) + if err != nil { + return nil, "", err + } + return m, slave, nil +} + +type master struct { + f *os.File + original *unix.Termios +} + +func (m *master) Read(b []byte) (int, error) { + return m.f.Read(b) +} + +func (m *master) Write(b []byte) (int, error) { + return m.f.Write(b) +} + +func (m *master) Close() error { + return m.f.Close() +} + +func (m *master) Resize(ws WinSize) error { + return tcswinsz(m.f.Fd(), ws) +} + +func (m *master) ResizeFrom(c Console) error { + ws, err := c.Size() + if err != nil { + return err + } + return m.Resize(ws) +} + +func (m *master) Reset() error { + if m.original == nil { + return nil + } + return tcset(m.f.Fd(), m.original) +} + +func (m *master) getCurrent() (unix.Termios, error) { + var termios unix.Termios + if err := tcget(m.f.Fd(), &termios); err != nil { + return unix.Termios{}, err + } + return termios, nil +} + +func (m *master) SetRaw() error { + rawState, err := m.getCurrent() + if err != nil { + return err + } + rawState = cfmakeraw(rawState) + rawState.Oflag = rawState.Oflag | unix.OPOST + return tcset(m.f.Fd(), &rawState) +} + +func (m *master) DisableEcho() error { + rawState, err := m.getCurrent() + if err != nil { + return err + } + rawState.Lflag = rawState.Lflag &^ unix.ECHO + return tcset(m.f.Fd(), &rawState) +} + +func (m *master) Size() (WinSize, error) { + return tcgwinsz(m.f.Fd()) +} + +func (m *master) Fd() uintptr { + return m.f.Fd() +} + +func (m *master) Name() string { + return m.f.Name() +} + +// checkConsole checks if the provided file is a console +func checkConsole(f *os.File) error { + var termios unix.Termios + if tcget(f.Fd(), &termios) != nil { + return ErrNotAConsole + } + return nil +} + +func newMaster(f *os.File) (Console, error) { + m := &master{ + f: f, + } + t, err := m.getCurrent() + if err != nil { + return nil, err + } + m.original = &t + return m, nil +} + +// ClearONLCR sets the necessary tty_ioctl(4)s to ensure that a pty pair +// created by us acts normally. In particular, a not-very-well-known default of +// Linux unix98 ptys is that they have +onlcr by default. While this isn't a +// problem for terminal emulators, because we relay data from the terminal we +// also relay that funky line discipline. +func ClearONLCR(fd uintptr) error { + return setONLCR(fd, false) +} + +// SetONLCR sets the necessary tty_ioctl(4)s to ensure that a pty pair +// created by us acts as intended for a terminal emulator. +func SetONLCR(fd uintptr) error { + return setONLCR(fd, true) +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/console/console_windows.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/console/console_windows.go new file mode 100644 index 0000000000..62dbe1c033 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/console/console_windows.go @@ -0,0 +1,216 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package console + +import ( + "fmt" + "os" + + "github.com/pkg/errors" + "golang.org/x/sys/windows" +) + +var ( + vtInputSupported bool + ErrNotImplemented = errors.New("not implemented") +) + +func (m *master) initStdios() { + m.in = windows.Handle(os.Stdin.Fd()) + if err := windows.GetConsoleMode(m.in, &m.inMode); err == nil { + // Validate that windows.ENABLE_VIRTUAL_TERMINAL_INPUT is supported, but do not set it. + if err = windows.SetConsoleMode(m.in, m.inMode|windows.ENABLE_VIRTUAL_TERMINAL_INPUT); err == nil { + vtInputSupported = true + } + // Unconditionally set the console mode back even on failure because SetConsoleMode + // remembers invalid bits on input handles. + windows.SetConsoleMode(m.in, m.inMode) + } else { + fmt.Printf("failed to get console mode for stdin: %v\n", err) + } + + m.out = windows.Handle(os.Stdout.Fd()) + if err := windows.GetConsoleMode(m.out, &m.outMode); err == nil { + if err := windows.SetConsoleMode(m.out, m.outMode|windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING); err == nil { + m.outMode |= windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING + } else { + windows.SetConsoleMode(m.out, m.outMode) + } + } else { + fmt.Printf("failed to get console mode for stdout: %v\n", err) + } + + m.err = windows.Handle(os.Stderr.Fd()) + if err := windows.GetConsoleMode(m.err, &m.errMode); err == nil { + if err := windows.SetConsoleMode(m.err, m.errMode|windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING); err == nil { + m.errMode |= windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING + } else { + windows.SetConsoleMode(m.err, m.errMode) + } + } else { + fmt.Printf("failed to get console mode for stderr: %v\n", err) + } +} + +type master struct { + in windows.Handle + inMode uint32 + + out windows.Handle + outMode uint32 + + err windows.Handle + errMode uint32 +} + +func (m *master) SetRaw() error { + if err := makeInputRaw(m.in, m.inMode); err != nil { + return err + } + + // Set StdOut and StdErr to raw mode, we ignore failures since + // windows.DISABLE_NEWLINE_AUTO_RETURN might not be supported on this version of + // Windows. + + windows.SetConsoleMode(m.out, m.outMode|windows.DISABLE_NEWLINE_AUTO_RETURN) + + windows.SetConsoleMode(m.err, m.errMode|windows.DISABLE_NEWLINE_AUTO_RETURN) + + return nil +} + +func (m *master) Reset() error { + for _, s := range []struct { + fd windows.Handle + mode uint32 + }{ + {m.in, m.inMode}, + {m.out, m.outMode}, + {m.err, m.errMode}, + } { + if err := windows.SetConsoleMode(s.fd, s.mode); err != nil { + return errors.Wrap(err, "unable to restore console mode") + } + } + + return nil +} + +func (m *master) Size() (WinSize, error) { + var info windows.ConsoleScreenBufferInfo + err := windows.GetConsoleScreenBufferInfo(m.out, &info) + if err != nil { + return WinSize{}, errors.Wrap(err, "unable to get console info") + } + + winsize := WinSize{ + Width: uint16(info.Window.Right - info.Window.Left + 1), + Height: uint16(info.Window.Bottom - info.Window.Top + 1), + } + + return winsize, nil +} + +func (m *master) Resize(ws WinSize) error { + return ErrNotImplemented +} + +func (m *master) ResizeFrom(c Console) error { + return ErrNotImplemented +} + +func (m *master) DisableEcho() error { + mode := m.inMode &^ windows.ENABLE_ECHO_INPUT + mode |= windows.ENABLE_PROCESSED_INPUT + mode |= windows.ENABLE_LINE_INPUT + + if err := windows.SetConsoleMode(m.in, mode); err != nil { + return errors.Wrap(err, "unable to set console to disable echo") + } + + return nil +} + +func (m *master) Close() error { + return nil +} + +func (m *master) Read(b []byte) (int, error) { + return os.Stdin.Read(b) +} + +func (m *master) Write(b []byte) (int, error) { + return os.Stdout.Write(b) +} + +func (m *master) Fd() uintptr { + return uintptr(m.in) +} + +// on windows, console can only be made from os.Std{in,out,err}, hence there +// isnt a single name here we can use. Return a dummy "console" value in this +// case should be sufficient. +func (m *master) Name() string { + return "console" +} + +// makeInputRaw puts the terminal (Windows Console) connected to the given +// file descriptor into raw mode +func makeInputRaw(fd windows.Handle, mode uint32) error { + // See + // -- https://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx + // -- https://msdn.microsoft.com/en-us/library/windows/desktop/ms683462(v=vs.85).aspx + + // Disable these modes + mode &^= windows.ENABLE_ECHO_INPUT + mode &^= windows.ENABLE_LINE_INPUT + mode &^= windows.ENABLE_MOUSE_INPUT + mode &^= windows.ENABLE_WINDOW_INPUT + mode &^= windows.ENABLE_PROCESSED_INPUT + + // Enable these modes + mode |= windows.ENABLE_EXTENDED_FLAGS + mode |= windows.ENABLE_INSERT_MODE + mode |= windows.ENABLE_QUICK_EDIT_MODE + + if vtInputSupported { + mode |= windows.ENABLE_VIRTUAL_TERMINAL_INPUT + } + + if err := windows.SetConsoleMode(fd, mode); err != nil { + return errors.Wrap(err, "unable to set console to raw mode") + } + + return nil +} + +func checkConsole(f *os.File) error { + var mode uint32 + if err := windows.GetConsoleMode(windows.Handle(f.Fd()), &mode); err != nil { + return err + } + return nil +} + +func newMaster(f *os.File) (Console, error) { + if f != os.Stdin && f != os.Stdout && f != os.Stderr { + return nil, errors.New("creating a console from a file is not supported on windows") + } + m := &master{} + m.initStdios() + return m, nil +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/console/tc_darwin.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/console/tc_darwin.go new file mode 100644 index 0000000000..b0128abb0c --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/console/tc_darwin.go @@ -0,0 +1,53 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package console + +import ( + "fmt" + "os" + "unsafe" + + "golang.org/x/sys/unix" +) + +const ( + cmdTcGet = unix.TIOCGETA + cmdTcSet = unix.TIOCSETA +) + +func ioctl(fd, flag, data uintptr) error { + if _, _, err := unix.Syscall(unix.SYS_IOCTL, fd, flag, data); err != 0 { + return err + } + return nil +} + +// unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f. +// unlockpt should be called before opening the slave side of a pty. +func unlockpt(f *os.File) error { + var u int32 + return ioctl(f.Fd(), unix.TIOCPTYUNLK, uintptr(unsafe.Pointer(&u))) +} + +// ptsname retrieves the name of the first available pts for the given master. +func ptsname(f *os.File) (string, error) { + n, err := unix.IoctlGetInt(int(f.Fd()), unix.TIOCPTYGNAME) + if err != nil { + return "", err + } + return fmt.Sprintf("/dev/pts/%d", n), nil +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/console/tc_freebsd.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/console/tc_freebsd.go new file mode 100644 index 0000000000..04583a6156 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/console/tc_freebsd.go @@ -0,0 +1,45 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package console + +import ( + "fmt" + "os" + + "golang.org/x/sys/unix" +) + +const ( + cmdTcGet = unix.TIOCGETA + cmdTcSet = unix.TIOCSETA +) + +// unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f. +// unlockpt should be called before opening the slave side of a pty. +// This does not exist on FreeBSD, it does not allocate controlling terminals on open +func unlockpt(f *os.File) error { + return nil +} + +// ptsname retrieves the name of the first available pts for the given master. +func ptsname(f *os.File) (string, error) { + n, err := unix.IoctlGetInt(int(f.Fd()), unix.TIOCGPTN) + if err != nil { + return "", err + } + return fmt.Sprintf("/dev/pts/%d", n), nil +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/console/tc_linux.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/console/tc_linux.go new file mode 100644 index 0000000000..1bdd68e6d5 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/console/tc_linux.go @@ -0,0 +1,49 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package console + +import ( + "fmt" + "os" + "unsafe" + + "golang.org/x/sys/unix" +) + +const ( + cmdTcGet = unix.TCGETS + cmdTcSet = unix.TCSETS +) + +// unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f. +// unlockpt should be called before opening the slave side of a pty. +func unlockpt(f *os.File) error { + var u int32 + if _, _, err := unix.Syscall(unix.SYS_IOCTL, f.Fd(), unix.TIOCSPTLCK, uintptr(unsafe.Pointer(&u))); err != 0 { + return err + } + return nil +} + +// ptsname retrieves the name of the first available pts for the given master. +func ptsname(f *os.File) (string, error) { + var u uint32 + if _, _, err := unix.Syscall(unix.SYS_IOCTL, f.Fd(), unix.TIOCGPTN, uintptr(unsafe.Pointer(&u))); err != 0 { + return "", err + } + return fmt.Sprintf("/dev/pts/%d", u), nil +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/console/tc_openbsd_cgo.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/console/tc_openbsd_cgo.go new file mode 100644 index 0000000000..f0cec06a72 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/console/tc_openbsd_cgo.go @@ -0,0 +1,51 @@ +// +build openbsd,cgo + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package console + +import ( + "os" + + "golang.org/x/sys/unix" +) + +//#include +import "C" + +const ( + cmdTcGet = unix.TIOCGETA + cmdTcSet = unix.TIOCSETA +) + +// ptsname retrieves the name of the first available pts for the given master. +func ptsname(f *os.File) (string, error) { + ptspath, err := C.ptsname(C.int(f.Fd())) + if err != nil { + return "", err + } + return C.GoString(ptspath), nil +} + +// unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f. +// unlockpt should be called before opening the slave side of a pty. +func unlockpt(f *os.File) error { + if _, err := C.grantpt(C.int(f.Fd())); err != nil { + return err + } + return nil +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/console/tc_openbsd_nocgo.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/console/tc_openbsd_nocgo.go new file mode 100644 index 0000000000..daccce2058 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/console/tc_openbsd_nocgo.go @@ -0,0 +1,47 @@ +// +build openbsd,!cgo + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +// +// Implementing the functions below requires cgo support. Non-cgo stubs +// versions are defined below to enable cross-compilation of source code +// that depends on these functions, but the resultant cross-compiled +// binaries cannot actually be used. If the stub function(s) below are +// actually invoked they will display an error message and cause the +// calling process to exit. +// + +package console + +import ( + "os" + + "golang.org/x/sys/unix" +) + +const ( + cmdTcGet = unix.TIOCGETA + cmdTcSet = unix.TIOCSETA +) + +func ptsname(f *os.File) (string, error) { + panic("ptsname() support requires cgo.") +} + +func unlockpt(f *os.File) error { + panic("unlockpt() support requires cgo.") +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/console/tc_solaris_cgo.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/console/tc_solaris_cgo.go new file mode 100644 index 0000000000..e36a68edd1 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/console/tc_solaris_cgo.go @@ -0,0 +1,51 @@ +// +build solaris,cgo + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package console + +import ( + "os" + + "golang.org/x/sys/unix" +) + +//#include +import "C" + +const ( + cmdTcGet = unix.TCGETS + cmdTcSet = unix.TCSETS +) + +// ptsname retrieves the name of the first available pts for the given master. +func ptsname(f *os.File) (string, error) { + ptspath, err := C.ptsname(C.int(f.Fd())) + if err != nil { + return "", err + } + return C.GoString(ptspath), nil +} + +// unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f. +// unlockpt should be called before opening the slave side of a pty. +func unlockpt(f *os.File) error { + if _, err := C.grantpt(C.int(f.Fd())); err != nil { + return err + } + return nil +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/console/tc_solaris_nocgo.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/console/tc_solaris_nocgo.go new file mode 100644 index 0000000000..eb0bd2c36b --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/console/tc_solaris_nocgo.go @@ -0,0 +1,47 @@ +// +build solaris,!cgo + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +// +// Implementing the functions below requires cgo support. Non-cgo stubs +// versions are defined below to enable cross-compilation of source code +// that depends on these functions, but the resultant cross-compiled +// binaries cannot actually be used. If the stub function(s) below are +// actually invoked they will display an error message and cause the +// calling process to exit. +// + +package console + +import ( + "os" + + "golang.org/x/sys/unix" +) + +const ( + cmdTcGet = unix.TCGETS + cmdTcSet = unix.TCSETS +) + +func ptsname(f *os.File) (string, error) { + panic("ptsname() support requires cgo.") +} + +func unlockpt(f *os.File) error { + panic("unlockpt() support requires cgo.") +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/console/tc_unix.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/console/tc_unix.go new file mode 100644 index 0000000000..7ae773c53e --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/console/tc_unix.go @@ -0,0 +1,91 @@ +// +build darwin freebsd linux openbsd solaris + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package console + +import ( + "golang.org/x/sys/unix" +) + +func tcget(fd uintptr, p *unix.Termios) error { + termios, err := unix.IoctlGetTermios(int(fd), cmdTcGet) + if err != nil { + return err + } + *p = *termios + return nil +} + +func tcset(fd uintptr, p *unix.Termios) error { + return unix.IoctlSetTermios(int(fd), cmdTcSet, p) +} + +func tcgwinsz(fd uintptr) (WinSize, error) { + var ws WinSize + + uws, err := unix.IoctlGetWinsize(int(fd), unix.TIOCGWINSZ) + if err != nil { + return ws, err + } + + // Translate from unix.Winsize to console.WinSize + ws.Height = uws.Row + ws.Width = uws.Col + ws.x = uws.Xpixel + ws.y = uws.Ypixel + return ws, nil +} + +func tcswinsz(fd uintptr, ws WinSize) error { + // Translate from console.WinSize to unix.Winsize + + var uws unix.Winsize + uws.Row = ws.Height + uws.Col = ws.Width + uws.Xpixel = ws.x + uws.Ypixel = ws.y + + return unix.IoctlSetWinsize(int(fd), unix.TIOCSWINSZ, &uws) +} + +func setONLCR(fd uintptr, enable bool) error { + var termios unix.Termios + if err := tcget(fd, &termios); err != nil { + return err + } + if enable { + // Set +onlcr so we can act like a real terminal + termios.Oflag |= unix.ONLCR + } else { + // Set -onlcr so we don't have to deal with \r. + termios.Oflag &^= unix.ONLCR + } + return tcset(fd, &termios) +} + +func cfmakeraw(t unix.Termios) unix.Termios { + t.Iflag &^= (unix.IGNBRK | unix.BRKINT | unix.PARMRK | unix.ISTRIP | unix.INLCR | unix.IGNCR | unix.ICRNL | unix.IXON) + t.Oflag &^= unix.OPOST + t.Lflag &^= (unix.ECHO | unix.ECHONL | unix.ICANON | unix.ISIG | unix.IEXTEN) + t.Cflag &^= (unix.CSIZE | unix.PARENB) + t.Cflag &^= unix.CS8 + t.Cc[unix.VMIN] = 1 + t.Cc[unix.VTIME] = 0 + + return t +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/go-runc/LICENSE b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/go-runc/LICENSE new file mode 100644 index 0000000000..261eeb9e9f --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/go-runc/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/go-runc/README.md b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/go-runc/README.md new file mode 100644 index 0000000000..239601f1e7 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/go-runc/README.md @@ -0,0 +1,14 @@ +# go-runc + +[![Build Status](https://travis-ci.org/containerd/go-runc.svg?branch=master)](https://travis-ci.org/containerd/go-runc) + + +This is a package for consuming the [runc](https://github.com/opencontainers/runc) binary in your Go applications. +It tries to expose all the settings and features of the runc CLI. If there is something missing then add it, its opensource! + +This needs runc @ [a9610f2c0](https://github.com/opencontainers/runc/commit/a9610f2c0237d2636d05a031ec8659a70e75ffeb) +or greater. + +## Docs + +Docs can be found at [godoc.org](https://godoc.org/github.com/containerd/go-runc). diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/go-runc/command_linux.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/go-runc/command_linux.go new file mode 100644 index 0000000000..71b52f9de4 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/go-runc/command_linux.go @@ -0,0 +1,41 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package runc + +import ( + "context" + "os" + "os/exec" + "syscall" +) + +func (r *Runc) command(context context.Context, args ...string) *exec.Cmd { + command := r.Command + if command == "" { + command = DefaultCommand + } + cmd := exec.CommandContext(context, command, append(r.args(), args...)...) + cmd.SysProcAttr = &syscall.SysProcAttr{ + Setpgid: r.Setpgid, + } + cmd.Env = os.Environ() + if r.PdeathSignal != 0 { + cmd.SysProcAttr.Pdeathsig = r.PdeathSignal + } + + return cmd +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/go-runc/command_other.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/go-runc/command_other.go new file mode 100644 index 0000000000..b8fd4b8660 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/go-runc/command_other.go @@ -0,0 +1,35 @@ +// +build !linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package runc + +import ( + "context" + "os" + "os/exec" +) + +func (r *Runc) command(context context.Context, args ...string) *exec.Cmd { + command := r.Command + if command == "" { + command = DefaultCommand + } + cmd := exec.CommandContext(context, command, append(r.args(), args...)...) + cmd.Env = os.Environ() + return cmd +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/go-runc/console.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/go-runc/console.go new file mode 100644 index 0000000000..ff223e4276 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/go-runc/console.go @@ -0,0 +1,165 @@ +// +build !windows + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package runc + +import ( + "fmt" + "io/ioutil" + "net" + "os" + "path/filepath" + + "github.com/containerd/console" + "golang.org/x/sys/unix" +) + +// NewConsoleSocket creates a new unix socket at the provided path to accept a +// pty master created by runc for use by the container +func NewConsoleSocket(path string) (*Socket, error) { + abs, err := filepath.Abs(path) + if err != nil { + return nil, err + } + addr, err := net.ResolveUnixAddr("unix", abs) + if err != nil { + return nil, err + } + l, err := net.ListenUnix("unix", addr) + if err != nil { + return nil, err + } + return &Socket{ + l: l, + }, nil +} + +// NewTempConsoleSocket returns a temp console socket for use with a container +// On Close(), the socket is deleted +func NewTempConsoleSocket() (*Socket, error) { + runtimeDir := os.Getenv("XDG_RUNTIME_DIR") + dir, err := ioutil.TempDir(runtimeDir, "pty") + if err != nil { + return nil, err + } + abs, err := filepath.Abs(filepath.Join(dir, "pty.sock")) + if err != nil { + return nil, err + } + addr, err := net.ResolveUnixAddr("unix", abs) + if err != nil { + return nil, err + } + l, err := net.ListenUnix("unix", addr) + if err != nil { + return nil, err + } + if runtimeDir != "" { + if err := os.Chmod(abs, 0755|os.ModeSticky); err != nil { + return nil, err + } + } + return &Socket{ + l: l, + rmdir: true, + }, nil +} + +// Socket is a unix socket that accepts the pty master created by runc +type Socket struct { + rmdir bool + l *net.UnixListener +} + +// Path returns the path to the unix socket on disk +func (c *Socket) Path() string { + return c.l.Addr().String() +} + +// recvFd waits for a file descriptor to be sent over the given AF_UNIX +// socket. The file name of the remote file descriptor will be recreated +// locally (it is sent as non-auxiliary data in the same payload). +func recvFd(socket *net.UnixConn) (*os.File, error) { + const MaxNameLen = 4096 + var oobSpace = unix.CmsgSpace(4) + + name := make([]byte, MaxNameLen) + oob := make([]byte, oobSpace) + + n, oobn, _, _, err := socket.ReadMsgUnix(name, oob) + if err != nil { + return nil, err + } + + if n >= MaxNameLen || oobn != oobSpace { + return nil, fmt.Errorf("recvfd: incorrect number of bytes read (n=%d oobn=%d)", n, oobn) + } + + // Truncate. + name = name[:n] + oob = oob[:oobn] + + scms, err := unix.ParseSocketControlMessage(oob) + if err != nil { + return nil, err + } + if len(scms) != 1 { + return nil, fmt.Errorf("recvfd: number of SCMs is not 1: %d", len(scms)) + } + scm := scms[0] + + fds, err := unix.ParseUnixRights(&scm) + if err != nil { + return nil, err + } + if len(fds) != 1 { + return nil, fmt.Errorf("recvfd: number of fds is not 1: %d", len(fds)) + } + fd := uintptr(fds[0]) + + return os.NewFile(fd, string(name)), nil +} + +// ReceiveMaster blocks until the socket receives the pty master +func (c *Socket) ReceiveMaster() (console.Console, error) { + conn, err := c.l.Accept() + if err != nil { + return nil, err + } + defer conn.Close() + uc, ok := conn.(*net.UnixConn) + if !ok { + return nil, fmt.Errorf("received connection which was not a unix socket") + } + f, err := recvFd(uc) + if err != nil { + return nil, err + } + return console.ConsoleFromFile(f) +} + +// Close closes the unix socket +func (c *Socket) Close() error { + err := c.l.Close() + if c.rmdir { + if rerr := os.RemoveAll(filepath.Dir(c.Path())); err == nil { + err = rerr + } + } + return err +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/go-runc/container.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/go-runc/container.go new file mode 100644 index 0000000000..107381a551 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/go-runc/container.go @@ -0,0 +1,30 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package runc + +import "time" + +// Container hold information for a runc container +type Container struct { + ID string `json:"id"` + Pid int `json:"pid"` + Status string `json:"status"` + Bundle string `json:"bundle"` + Rootfs string `json:"rootfs"` + Created time.Time `json:"created"` + Annotations map[string]string `json:"annotations"` +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/go-runc/events.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/go-runc/events.go new file mode 100644 index 0000000000..d610aeb34e --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/go-runc/events.go @@ -0,0 +1,100 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package runc + +type Event struct { + // Type are the event type generated by runc + // If the type is "error" then check the Err field on the event for + // the actual error + Type string `json:"type"` + ID string `json:"id"` + Stats *Stats `json:"data,omitempty"` + // Err has a read error if we were unable to decode the event from runc + Err error `json:"-"` +} + +type Stats struct { + Cpu Cpu `json:"cpu"` + Memory Memory `json:"memory"` + Pids Pids `json:"pids"` + Blkio Blkio `json:"blkio"` + Hugetlb map[string]Hugetlb `json:"hugetlb"` +} + +type Hugetlb struct { + Usage uint64 `json:"usage,omitempty"` + Max uint64 `json:"max,omitempty"` + Failcnt uint64 `json:"failcnt"` +} + +type BlkioEntry struct { + Major uint64 `json:"major,omitempty"` + Minor uint64 `json:"minor,omitempty"` + Op string `json:"op,omitempty"` + Value uint64 `json:"value,omitempty"` +} + +type Blkio struct { + IoServiceBytesRecursive []BlkioEntry `json:"ioServiceBytesRecursive,omitempty"` + IoServicedRecursive []BlkioEntry `json:"ioServicedRecursive,omitempty"` + IoQueuedRecursive []BlkioEntry `json:"ioQueueRecursive,omitempty"` + IoServiceTimeRecursive []BlkioEntry `json:"ioServiceTimeRecursive,omitempty"` + IoWaitTimeRecursive []BlkioEntry `json:"ioWaitTimeRecursive,omitempty"` + IoMergedRecursive []BlkioEntry `json:"ioMergedRecursive,omitempty"` + IoTimeRecursive []BlkioEntry `json:"ioTimeRecursive,omitempty"` + SectorsRecursive []BlkioEntry `json:"sectorsRecursive,omitempty"` +} + +type Pids struct { + Current uint64 `json:"current,omitempty"` + Limit uint64 `json:"limit,omitempty"` +} + +type Throttling struct { + Periods uint64 `json:"periods,omitempty"` + ThrottledPeriods uint64 `json:"throttledPeriods,omitempty"` + ThrottledTime uint64 `json:"throttledTime,omitempty"` +} + +type CpuUsage struct { + // Units: nanoseconds. + Total uint64 `json:"total,omitempty"` + Percpu []uint64 `json:"percpu,omitempty"` + Kernel uint64 `json:"kernel"` + User uint64 `json:"user"` +} + +type Cpu struct { + Usage CpuUsage `json:"usage,omitempty"` + Throttling Throttling `json:"throttling,omitempty"` +} + +type MemoryEntry struct { + Limit uint64 `json:"limit"` + Usage uint64 `json:"usage,omitempty"` + Max uint64 `json:"max,omitempty"` + Failcnt uint64 `json:"failcnt"` +} + +type Memory struct { + Cache uint64 `json:"cache,omitempty"` + Usage MemoryEntry `json:"usage,omitempty"` + Swap MemoryEntry `json:"swap,omitempty"` + Kernel MemoryEntry `json:"kernel,omitempty"` + KernelTCP MemoryEntry `json:"kernelTCP,omitempty"` + Raw map[string]uint64 `json:"raw,omitempty"` +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/go-runc/io.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/go-runc/io.go new file mode 100644 index 0000000000..6cf0410c9d --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/go-runc/io.go @@ -0,0 +1,218 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package runc + +import ( + "io" + "os" + "os/exec" +) + +type IO interface { + io.Closer + Stdin() io.WriteCloser + Stdout() io.ReadCloser + Stderr() io.ReadCloser + Set(*exec.Cmd) +} + +type StartCloser interface { + CloseAfterStart() error +} + +// IOOpt sets I/O creation options +type IOOpt func(*IOOption) + +// IOOption holds I/O creation options +type IOOption struct { + OpenStdin bool + OpenStdout bool + OpenStderr bool +} + +func defaultIOOption() *IOOption { + return &IOOption{ + OpenStdin: true, + OpenStdout: true, + OpenStderr: true, + } +} + +func newPipe() (*pipe, error) { + r, w, err := os.Pipe() + if err != nil { + return nil, err + } + return &pipe{ + r: r, + w: w, + }, nil +} + +type pipe struct { + r *os.File + w *os.File +} + +func (p *pipe) Close() error { + err := p.w.Close() + if rerr := p.r.Close(); err == nil { + err = rerr + } + return err +} + +type pipeIO struct { + in *pipe + out *pipe + err *pipe +} + +func (i *pipeIO) Stdin() io.WriteCloser { + if i.in == nil { + return nil + } + return i.in.w +} + +func (i *pipeIO) Stdout() io.ReadCloser { + if i.out == nil { + return nil + } + return i.out.r +} + +func (i *pipeIO) Stderr() io.ReadCloser { + if i.err == nil { + return nil + } + return i.err.r +} + +func (i *pipeIO) Close() error { + var err error + for _, v := range []*pipe{ + i.in, + i.out, + i.err, + } { + if v != nil { + if cerr := v.Close(); err == nil { + err = cerr + } + } + } + return err +} + +func (i *pipeIO) CloseAfterStart() error { + for _, f := range []*pipe{ + i.out, + i.err, + } { + if f != nil { + f.w.Close() + } + } + return nil +} + +// Set sets the io to the exec.Cmd +func (i *pipeIO) Set(cmd *exec.Cmd) { + if i.in != nil { + cmd.Stdin = i.in.r + } + if i.out != nil { + cmd.Stdout = i.out.w + } + if i.err != nil { + cmd.Stderr = i.err.w + } +} + +func NewSTDIO() (IO, error) { + return &stdio{}, nil +} + +type stdio struct { +} + +func (s *stdio) Close() error { + return nil +} + +func (s *stdio) Set(cmd *exec.Cmd) { + cmd.Stdin = os.Stdin + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr +} + +func (s *stdio) Stdin() io.WriteCloser { + return os.Stdin +} + +func (s *stdio) Stdout() io.ReadCloser { + return os.Stdout +} + +func (s *stdio) Stderr() io.ReadCloser { + return os.Stderr +} + +// NewNullIO returns IO setup for /dev/null use with runc +func NewNullIO() (IO, error) { + f, err := os.Open(os.DevNull) + if err != nil { + return nil, err + } + return &nullIO{ + devNull: f, + }, nil +} + +type nullIO struct { + devNull *os.File +} + +func (n *nullIO) Close() error { + // this should be closed after start but if not + // make sure we close the file but don't return the error + n.devNull.Close() + return nil +} + +func (n *nullIO) Stdin() io.WriteCloser { + return nil +} + +func (n *nullIO) Stdout() io.ReadCloser { + return nil +} + +func (n *nullIO) Stderr() io.ReadCloser { + return nil +} + +func (n *nullIO) Set(c *exec.Cmd) { + // don't set STDIN here + c.Stdout = n.devNull + c.Stderr = n.devNull +} + +func (n *nullIO) CloseAfterStart() error { + return n.devNull.Close() +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/go-runc/io_unix.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/go-runc/io_unix.go new file mode 100644 index 0000000000..567cd072e5 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/go-runc/io_unix.go @@ -0,0 +1,76 @@ +// +build !windows + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package runc + +import ( + "github.com/pkg/errors" + "golang.org/x/sys/unix" +) + +// NewPipeIO creates pipe pairs to be used with runc +func NewPipeIO(uid, gid int, opts ...IOOpt) (i IO, err error) { + option := defaultIOOption() + for _, o := range opts { + o(option) + } + var ( + pipes []*pipe + stdin, stdout, stderr *pipe + ) + // cleanup in case of an error + defer func() { + if err != nil { + for _, p := range pipes { + p.Close() + } + } + }() + if option.OpenStdin { + if stdin, err = newPipe(); err != nil { + return nil, err + } + pipes = append(pipes, stdin) + if err = unix.Fchown(int(stdin.r.Fd()), uid, gid); err != nil { + return nil, errors.Wrap(err, "failed to chown stdin") + } + } + if option.OpenStdout { + if stdout, err = newPipe(); err != nil { + return nil, err + } + pipes = append(pipes, stdout) + if err = unix.Fchown(int(stdout.w.Fd()), uid, gid); err != nil { + return nil, errors.Wrap(err, "failed to chown stdout") + } + } + if option.OpenStderr { + if stderr, err = newPipe(); err != nil { + return nil, err + } + pipes = append(pipes, stderr) + if err = unix.Fchown(int(stderr.w.Fd()), uid, gid); err != nil { + return nil, errors.Wrap(err, "failed to chown stderr") + } + } + return &pipeIO{ + in: stdin, + out: stdout, + err: stderr, + }, nil +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/go-runc/io_windows.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/go-runc/io_windows.go new file mode 100644 index 0000000000..fc56ac4f30 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/go-runc/io_windows.go @@ -0,0 +1,62 @@ +// +build windows + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package runc + +// NewPipeIO creates pipe pairs to be used with runc +func NewPipeIO(opts ...IOOpt) (i IO, err error) { + option := defaultIOOption() + for _, o := range opts { + o(option) + } + var ( + pipes []*pipe + stdin, stdout, stderr *pipe + ) + // cleanup in case of an error + defer func() { + if err != nil { + for _, p := range pipes { + p.Close() + } + } + }() + if option.OpenStdin { + if stdin, err = newPipe(); err != nil { + return nil, err + } + pipes = append(pipes, stdin) + } + if option.OpenStdout { + if stdout, err = newPipe(); err != nil { + return nil, err + } + pipes = append(pipes, stdout) + } + if option.OpenStderr { + if stderr, err = newPipe(); err != nil { + return nil, err + } + pipes = append(pipes, stderr) + } + return &pipeIO{ + in: stdin, + out: stdout, + err: stderr, + }, nil +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/go-runc/monitor.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/go-runc/monitor.go new file mode 100644 index 0000000000..ff06a3fca9 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/go-runc/monitor.go @@ -0,0 +1,76 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package runc + +import ( + "os/exec" + "syscall" + "time" +) + +var Monitor ProcessMonitor = &defaultMonitor{} + +type Exit struct { + Timestamp time.Time + Pid int + Status int +} + +// ProcessMonitor is an interface for process monitoring +// +// It allows daemons using go-runc to have a SIGCHLD handler +// to handle exits without introducing races between the handler +// and go's exec.Cmd +// These methods should match the methods exposed by exec.Cmd to provide +// a consistent experience for the caller +type ProcessMonitor interface { + Start(*exec.Cmd) (chan Exit, error) + Wait(*exec.Cmd, chan Exit) (int, error) +} + +type defaultMonitor struct { +} + +func (m *defaultMonitor) Start(c *exec.Cmd) (chan Exit, error) { + if err := c.Start(); err != nil { + return nil, err + } + ec := make(chan Exit, 1) + go func() { + var status int + if err := c.Wait(); err != nil { + status = 255 + if exitErr, ok := err.(*exec.ExitError); ok { + if ws, ok := exitErr.Sys().(syscall.WaitStatus); ok { + status = ws.ExitStatus() + } + } + } + ec <- Exit{ + Timestamp: time.Now(), + Pid: c.Process.Pid, + Status: status, + } + close(ec) + }() + return ec, nil +} + +func (m *defaultMonitor) Wait(c *exec.Cmd, ec chan Exit) (int, error) { + e := <-ec + return e.Status, nil +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/go-runc/runc.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/go-runc/runc.go new file mode 100644 index 0000000000..96262afab3 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/go-runc/runc.go @@ -0,0 +1,707 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package runc + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "io" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "strconv" + "strings" + "syscall" + "time" + + specs "github.com/opencontainers/runtime-spec/specs-go" +) + +// Format is the type of log formatting options avaliable +type Format string + +// TopBody represents the structured data of the full ps output +type TopResults struct { + // Processes running in the container, where each is process is an array of values corresponding to the headers + Processes [][]string `json:"Processes"` + + // Headers are the names of the columns + Headers []string `json:"Headers"` +} + +const ( + none Format = "" + JSON Format = "json" + Text Format = "text" + // DefaultCommand is the default command for Runc + DefaultCommand = "runc" +) + +// Runc is the client to the runc cli +type Runc struct { + //If command is empty, DefaultCommand is used + Command string + Root string + Debug bool + Log string + LogFormat Format + PdeathSignal syscall.Signal + Setpgid bool + Criu string + SystemdCgroup bool + Rootless *bool // nil stands for "auto" +} + +// List returns all containers created inside the provided runc root directory +func (r *Runc) List(context context.Context) ([]*Container, error) { + data, err := cmdOutput(r.command(context, "list", "--format=json"), false) + if err != nil { + return nil, err + } + var out []*Container + if err := json.Unmarshal(data, &out); err != nil { + return nil, err + } + return out, nil +} + +// State returns the state for the container provided by id +func (r *Runc) State(context context.Context, id string) (*Container, error) { + data, err := cmdOutput(r.command(context, "state", id), true) + if err != nil { + return nil, fmt.Errorf("%s: %s", err, data) + } + var c Container + if err := json.Unmarshal(data, &c); err != nil { + return nil, err + } + return &c, nil +} + +type ConsoleSocket interface { + Path() string +} + +type CreateOpts struct { + IO + // PidFile is a path to where a pid file should be created + PidFile string + ConsoleSocket ConsoleSocket + Detach bool + NoPivot bool + NoNewKeyring bool + ExtraFiles []*os.File +} + +func (o *CreateOpts) args() (out []string, err error) { + if o.PidFile != "" { + abs, err := filepath.Abs(o.PidFile) + if err != nil { + return nil, err + } + out = append(out, "--pid-file", abs) + } + if o.ConsoleSocket != nil { + out = append(out, "--console-socket", o.ConsoleSocket.Path()) + } + if o.NoPivot { + out = append(out, "--no-pivot") + } + if o.NoNewKeyring { + out = append(out, "--no-new-keyring") + } + if o.Detach { + out = append(out, "--detach") + } + if o.ExtraFiles != nil { + out = append(out, "--preserve-fds", strconv.Itoa(len(o.ExtraFiles))) + } + return out, nil +} + +// Create creates a new container and returns its pid if it was created successfully +func (r *Runc) Create(context context.Context, id, bundle string, opts *CreateOpts) error { + args := []string{"create", "--bundle", bundle} + if opts != nil { + oargs, err := opts.args() + if err != nil { + return err + } + args = append(args, oargs...) + } + cmd := r.command(context, append(args, id)...) + if opts != nil && opts.IO != nil { + opts.Set(cmd) + } + cmd.ExtraFiles = opts.ExtraFiles + + if cmd.Stdout == nil && cmd.Stderr == nil { + data, err := cmdOutput(cmd, true) + if err != nil { + return fmt.Errorf("%s: %s", err, data) + } + return nil + } + ec, err := Monitor.Start(cmd) + if err != nil { + return err + } + if opts != nil && opts.IO != nil { + if c, ok := opts.IO.(StartCloser); ok { + if err := c.CloseAfterStart(); err != nil { + return err + } + } + } + status, err := Monitor.Wait(cmd, ec) + if err == nil && status != 0 { + err = fmt.Errorf("%s did not terminate sucessfully", cmd.Args[0]) + } + return err +} + +// Start will start an already created container +func (r *Runc) Start(context context.Context, id string) error { + return r.runOrError(r.command(context, "start", id)) +} + +type ExecOpts struct { + IO + PidFile string + ConsoleSocket ConsoleSocket + Detach bool +} + +func (o *ExecOpts) args() (out []string, err error) { + if o.ConsoleSocket != nil { + out = append(out, "--console-socket", o.ConsoleSocket.Path()) + } + if o.Detach { + out = append(out, "--detach") + } + if o.PidFile != "" { + abs, err := filepath.Abs(o.PidFile) + if err != nil { + return nil, err + } + out = append(out, "--pid-file", abs) + } + return out, nil +} + +// Exec executres and additional process inside the container based on a full +// OCI Process specification +func (r *Runc) Exec(context context.Context, id string, spec specs.Process, opts *ExecOpts) error { + f, err := ioutil.TempFile(os.Getenv("XDG_RUNTIME_DIR"), "runc-process") + if err != nil { + return err + } + defer os.Remove(f.Name()) + err = json.NewEncoder(f).Encode(spec) + f.Close() + if err != nil { + return err + } + args := []string{"exec", "--process", f.Name()} + if opts != nil { + oargs, err := opts.args() + if err != nil { + return err + } + args = append(args, oargs...) + } + cmd := r.command(context, append(args, id)...) + if opts != nil && opts.IO != nil { + opts.Set(cmd) + } + if cmd.Stdout == nil && cmd.Stderr == nil { + data, err := cmdOutput(cmd, true) + if err != nil { + return fmt.Errorf("%s: %s", err, data) + } + return nil + } + ec, err := Monitor.Start(cmd) + if err != nil { + return err + } + if opts != nil && opts.IO != nil { + if c, ok := opts.IO.(StartCloser); ok { + if err := c.CloseAfterStart(); err != nil { + return err + } + } + } + status, err := Monitor.Wait(cmd, ec) + if err == nil && status != 0 { + err = fmt.Errorf("%s did not terminate sucessfully", cmd.Args[0]) + } + return err +} + +// Run runs the create, start, delete lifecycle of the container +// and returns its exit status after it has exited +func (r *Runc) Run(context context.Context, id, bundle string, opts *CreateOpts) (int, error) { + args := []string{"run", "--bundle", bundle} + if opts != nil { + oargs, err := opts.args() + if err != nil { + return -1, err + } + args = append(args, oargs...) + } + cmd := r.command(context, append(args, id)...) + if opts != nil && opts.IO != nil { + opts.Set(cmd) + } + ec, err := Monitor.Start(cmd) + if err != nil { + return -1, err + } + return Monitor.Wait(cmd, ec) +} + +type DeleteOpts struct { + Force bool +} + +func (o *DeleteOpts) args() (out []string) { + if o.Force { + out = append(out, "--force") + } + return out +} + +// Delete deletes the container +func (r *Runc) Delete(context context.Context, id string, opts *DeleteOpts) error { + args := []string{"delete"} + if opts != nil { + args = append(args, opts.args()...) + } + return r.runOrError(r.command(context, append(args, id)...)) +} + +// KillOpts specifies options for killing a container and its processes +type KillOpts struct { + All bool +} + +func (o *KillOpts) args() (out []string) { + if o.All { + out = append(out, "--all") + } + return out +} + +// Kill sends the specified signal to the container +func (r *Runc) Kill(context context.Context, id string, sig int, opts *KillOpts) error { + args := []string{ + "kill", + } + if opts != nil { + args = append(args, opts.args()...) + } + return r.runOrError(r.command(context, append(args, id, strconv.Itoa(sig))...)) +} + +// Stats return the stats for a container like cpu, memory, and io +func (r *Runc) Stats(context context.Context, id string) (*Stats, error) { + cmd := r.command(context, "events", "--stats", id) + rd, err := cmd.StdoutPipe() + if err != nil { + return nil, err + } + ec, err := Monitor.Start(cmd) + if err != nil { + return nil, err + } + defer func() { + rd.Close() + Monitor.Wait(cmd, ec) + }() + var e Event + if err := json.NewDecoder(rd).Decode(&e); err != nil { + return nil, err + } + return e.Stats, nil +} + +// Events returns an event stream from runc for a container with stats and OOM notifications +func (r *Runc) Events(context context.Context, id string, interval time.Duration) (chan *Event, error) { + cmd := r.command(context, "events", fmt.Sprintf("--interval=%ds", int(interval.Seconds())), id) + rd, err := cmd.StdoutPipe() + if err != nil { + return nil, err + } + ec, err := Monitor.Start(cmd) + if err != nil { + rd.Close() + return nil, err + } + var ( + dec = json.NewDecoder(rd) + c = make(chan *Event, 128) + ) + go func() { + defer func() { + close(c) + rd.Close() + Monitor.Wait(cmd, ec) + }() + for { + var e Event + if err := dec.Decode(&e); err != nil { + if err == io.EOF { + return + } + e = Event{ + Type: "error", + Err: err, + } + } + c <- &e + } + }() + return c, nil +} + +// Pause the container with the provided id +func (r *Runc) Pause(context context.Context, id string) error { + return r.runOrError(r.command(context, "pause", id)) +} + +// Resume the container with the provided id +func (r *Runc) Resume(context context.Context, id string) error { + return r.runOrError(r.command(context, "resume", id)) +} + +// Ps lists all the processes inside the container returning their pids +func (r *Runc) Ps(context context.Context, id string) ([]int, error) { + data, err := cmdOutput(r.command(context, "ps", "--format", "json", id), true) + if err != nil { + return nil, fmt.Errorf("%s: %s", err, data) + } + var pids []int + if err := json.Unmarshal(data, &pids); err != nil { + return nil, err + } + return pids, nil +} + +// Top lists all the processes inside the container returning the full ps data +func (r *Runc) Top(context context.Context, id string, psOptions string) (*TopResults, error) { + data, err := cmdOutput(r.command(context, "ps", "--format", "table", id, psOptions), true) + if err != nil { + return nil, fmt.Errorf("%s: %s", err, data) + } + + topResults, err := ParsePSOutput(data) + if err != nil { + return nil, fmt.Errorf("%s: ", err) + } + return topResults, nil +} + +type CheckpointOpts struct { + // ImagePath is the path for saving the criu image file + ImagePath string + // WorkDir is the working directory for criu + WorkDir string + // ParentPath is the path for previous image files from a pre-dump + ParentPath string + // AllowOpenTCP allows open tcp connections to be checkpointed + AllowOpenTCP bool + // AllowExternalUnixSockets allows external unix sockets to be checkpointed + AllowExternalUnixSockets bool + // AllowTerminal allows the terminal(pty) to be checkpointed with a container + AllowTerminal bool + // CriuPageServer is the address:port for the criu page server + CriuPageServer string + // FileLocks handle file locks held by the container + FileLocks bool + // Cgroups is the cgroup mode for how to handle the checkpoint of a container's cgroups + Cgroups CgroupMode + // EmptyNamespaces creates a namespace for the container but does not save its properties + // Provide the namespaces you wish to be checkpointed without their settings on restore + EmptyNamespaces []string +} + +type CgroupMode string + +const ( + Soft CgroupMode = "soft" + Full CgroupMode = "full" + Strict CgroupMode = "strict" +) + +func (o *CheckpointOpts) args() (out []string) { + if o.ImagePath != "" { + out = append(out, "--image-path", o.ImagePath) + } + if o.WorkDir != "" { + out = append(out, "--work-path", o.WorkDir) + } + if o.ParentPath != "" { + out = append(out, "--parent-path", o.ParentPath) + } + if o.AllowOpenTCP { + out = append(out, "--tcp-established") + } + if o.AllowExternalUnixSockets { + out = append(out, "--ext-unix-sk") + } + if o.AllowTerminal { + out = append(out, "--shell-job") + } + if o.CriuPageServer != "" { + out = append(out, "--page-server", o.CriuPageServer) + } + if o.FileLocks { + out = append(out, "--file-locks") + } + if string(o.Cgroups) != "" { + out = append(out, "--manage-cgroups-mode", string(o.Cgroups)) + } + for _, ns := range o.EmptyNamespaces { + out = append(out, "--empty-ns", ns) + } + return out +} + +type CheckpointAction func([]string) []string + +// LeaveRunning keeps the container running after the checkpoint has been completed +func LeaveRunning(args []string) []string { + return append(args, "--leave-running") +} + +// PreDump allows a pre-dump of the checkpoint to be made and completed later +func PreDump(args []string) []string { + return append(args, "--pre-dump") +} + +// Checkpoint allows you to checkpoint a container using criu +func (r *Runc) Checkpoint(context context.Context, id string, opts *CheckpointOpts, actions ...CheckpointAction) error { + args := []string{"checkpoint"} + if opts != nil { + args = append(args, opts.args()...) + } + for _, a := range actions { + args = a(args) + } + return r.runOrError(r.command(context, append(args, id)...)) +} + +type RestoreOpts struct { + CheckpointOpts + IO + + Detach bool + PidFile string + NoSubreaper bool + NoPivot bool + ConsoleSocket ConsoleSocket +} + +func (o *RestoreOpts) args() ([]string, error) { + out := o.CheckpointOpts.args() + if o.Detach { + out = append(out, "--detach") + } + if o.PidFile != "" { + abs, err := filepath.Abs(o.PidFile) + if err != nil { + return nil, err + } + out = append(out, "--pid-file", abs) + } + if o.ConsoleSocket != nil { + out = append(out, "--console-socket", o.ConsoleSocket.Path()) + } + if o.NoPivot { + out = append(out, "--no-pivot") + } + if o.NoSubreaper { + out = append(out, "-no-subreaper") + } + return out, nil +} + +// Restore restores a container with the provide id from an existing checkpoint +func (r *Runc) Restore(context context.Context, id, bundle string, opts *RestoreOpts) (int, error) { + args := []string{"restore"} + if opts != nil { + oargs, err := opts.args() + if err != nil { + return -1, err + } + args = append(args, oargs...) + } + args = append(args, "--bundle", bundle) + cmd := r.command(context, append(args, id)...) + if opts != nil && opts.IO != nil { + opts.Set(cmd) + } + ec, err := Monitor.Start(cmd) + if err != nil { + return -1, err + } + if opts != nil && opts.IO != nil { + if c, ok := opts.IO.(StartCloser); ok { + if err := c.CloseAfterStart(); err != nil { + return -1, err + } + } + } + return Monitor.Wait(cmd, ec) +} + +// Update updates the current container with the provided resource spec +func (r *Runc) Update(context context.Context, id string, resources *specs.LinuxResources) error { + buf := getBuf() + defer putBuf(buf) + + if err := json.NewEncoder(buf).Encode(resources); err != nil { + return err + } + args := []string{"update", "--resources", "-", id} + cmd := r.command(context, args...) + cmd.Stdin = buf + return r.runOrError(cmd) +} + +var ErrParseRuncVersion = errors.New("unable to parse runc version") + +type Version struct { + Runc string + Commit string + Spec string +} + +// Version returns the runc and runtime-spec versions +func (r *Runc) Version(context context.Context) (Version, error) { + data, err := cmdOutput(r.command(context, "--version"), false) + if err != nil { + return Version{}, err + } + return parseVersion(data) +} + +func parseVersion(data []byte) (Version, error) { + var v Version + parts := strings.Split(strings.TrimSpace(string(data)), "\n") + if len(parts) != 3 { + return v, nil + } + for i, p := range []struct { + dest *string + split string + }{ + { + dest: &v.Runc, + split: "version ", + }, + { + dest: &v.Commit, + split: ": ", + }, + { + dest: &v.Spec, + split: ": ", + }, + } { + p2 := strings.Split(parts[i], p.split) + if len(p2) != 2 { + return v, fmt.Errorf("unable to parse version line %q", parts[i]) + } + *p.dest = p2[1] + } + return v, nil +} + +func (r *Runc) args() (out []string) { + if r.Root != "" { + out = append(out, "--root", r.Root) + } + if r.Debug { + out = append(out, "--debug") + } + if r.Log != "" { + out = append(out, "--log", r.Log) + } + if r.LogFormat != none { + out = append(out, "--log-format", string(r.LogFormat)) + } + if r.Criu != "" { + out = append(out, "--criu", r.Criu) + } + if r.SystemdCgroup { + out = append(out, "--systemd-cgroup") + } + if r.Rootless != nil { + // nil stands for "auto" (differs from explicit "false") + out = append(out, "--rootless="+strconv.FormatBool(*r.Rootless)) + } + return out +} + +// runOrError will run the provided command. If an error is +// encountered and neither Stdout or Stderr was set the error and the +// stderr of the command will be returned in the format of : +// +func (r *Runc) runOrError(cmd *exec.Cmd) error { + if cmd.Stdout != nil || cmd.Stderr != nil { + ec, err := Monitor.Start(cmd) + if err != nil { + return err + } + status, err := Monitor.Wait(cmd, ec) + if err == nil && status != 0 { + err = fmt.Errorf("%s did not terminate sucessfully", cmd.Args[0]) + } + return err + } + data, err := cmdOutput(cmd, true) + if err != nil { + return fmt.Errorf("%s: %s", err, data) + } + return nil +} + +func cmdOutput(cmd *exec.Cmd, combined bool) ([]byte, error) { + b := getBuf() + defer putBuf(b) + + cmd.Stdout = b + if combined { + cmd.Stderr = b + } + ec, err := Monitor.Start(cmd) + if err != nil { + return nil, err + } + + status, err := Monitor.Wait(cmd, ec) + if err == nil && status != 0 { + err = fmt.Errorf("%s did not terminate sucessfully", cmd.Args[0]) + } + + return b.Bytes(), err +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/go-runc/utils.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/go-runc/utils.go new file mode 100644 index 0000000000..69ad6ead75 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/containerd/go-runc/utils.go @@ -0,0 +1,107 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package runc + +import ( + "bytes" + "io/ioutil" + "strconv" + "strings" + "sync" + "syscall" +) + +// ReadPidFile reads the pid file at the provided path and returns +// the pid or an error if the read and conversion is unsuccessful +func ReadPidFile(path string) (int, error) { + data, err := ioutil.ReadFile(path) + if err != nil { + return -1, err + } + return strconv.Atoi(string(data)) +} + +const exitSignalOffset = 128 + +// exitStatus returns the correct exit status for a process based on if it +// was signaled or exited cleanly +func exitStatus(status syscall.WaitStatus) int { + if status.Signaled() { + return exitSignalOffset + int(status.Signal()) + } + return status.ExitStatus() +} + +var bytesBufferPool = sync.Pool{ + New: func() interface{} { + return bytes.NewBuffer(nil) + }, +} + +func getBuf() *bytes.Buffer { + return bytesBufferPool.Get().(*bytes.Buffer) +} + +func putBuf(b *bytes.Buffer) { + b.Reset() + bytesBufferPool.Put(b) +} + +// fieldsASCII is similar to strings.Fields but only allows ASCII whitespaces +func fieldsASCII(s string) []string { + fn := func(r rune) bool { + switch r { + case '\t', '\n', '\f', '\r', ' ': + return true + } + return false + } + return strings.FieldsFunc(s, fn) +} + +// ParsePSOutput parses the runtime's ps raw output and returns a TopResults +func ParsePSOutput(output []byte) (*TopResults, error) { + topResults := &TopResults{} + + lines := strings.Split(string(output), "\n") + topResults.Headers = fieldsASCII(lines[0]) + + pidIndex := -1 + for i, name := range topResults.Headers { + if name == "PID" { + pidIndex = i + } + } + + for _, line := range lines[1:] { + if len(line) == 0 { + continue + } + + fields := fieldsASCII(line) + + if fields[pidIndex] == "-" { + continue + } + + process := fields[:len(topResults.Headers)-1] + process = append(process, strings.Join(fields[len(topResults.Headers)-1:], " ")) + topResults.Processes = append(topResults.Processes, process) + + } + return topResults, nil +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/hashicorp/errwrap/LICENSE b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/hashicorp/errwrap/LICENSE new file mode 100644 index 0000000000..c33dcc7c92 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/hashicorp/errwrap/LICENSE @@ -0,0 +1,354 @@ +Mozilla Public License, version 2.0 + +1. Definitions + +1.1. “Contributor” + + means each individual or legal entity that creates, contributes to the + creation of, or owns Covered Software. + +1.2. “Contributor Version” + + means the combination of the Contributions of others (if any) used by a + Contributor and that particular Contributor’s Contribution. + +1.3. “Contribution” + + means Covered Software of a particular Contributor. + +1.4. “Covered Software” + + means Source Code Form to which the initial Contributor has attached the + notice in Exhibit A, the Executable Form of such Source Code Form, and + Modifications of such Source Code Form, in each case including portions + thereof. + +1.5. “Incompatible With Secondary Licenses” + means + + a. that the initial Contributor has attached the notice described in + Exhibit B to the Covered Software; or + + b. that the Covered Software was made available under the terms of version + 1.1 or earlier of the License, but not also under the terms of a + Secondary License. + +1.6. “Executable Form” + + means any form of the work other than Source Code Form. + +1.7. “Larger Work” + + means a work that combines Covered Software with other material, in a separate + file or files, that is not Covered Software. + +1.8. “License” + + means this document. + +1.9. “Licensable” + + means having the right to grant, to the maximum extent possible, whether at the + time of the initial grant or subsequently, any and all of the rights conveyed by + this License. + +1.10. “Modifications” + + means any of the following: + + a. any file in Source Code Form that results from an addition to, deletion + from, or modification of the contents of Covered Software; or + + b. any new file in Source Code Form that contains any Covered Software. + +1.11. “Patent Claims” of a Contributor + + means any patent claim(s), including without limitation, method, process, + and apparatus claims, in any patent Licensable by such Contributor that + would be infringed, but for the grant of the License, by the making, + using, selling, offering for sale, having made, import, or transfer of + either its Contributions or its Contributor Version. + +1.12. “Secondary License” + + means either the GNU General Public License, Version 2.0, the GNU Lesser + General Public License, Version 2.1, the GNU Affero General Public + License, Version 3.0, or any later versions of those licenses. + +1.13. “Source Code Form” + + means the form of the work preferred for making modifications. + +1.14. “You” (or “Your”) + + means an individual or a legal entity exercising rights under this + License. For legal entities, “You” includes any entity that controls, is + controlled by, or is under common control with You. For purposes of this + definition, “control” means (a) the power, direct or indirect, to cause + the direction or management of such entity, whether by contract or + otherwise, or (b) ownership of more than fifty percent (50%) of the + outstanding shares or beneficial ownership of such entity. + + +2. License Grants and Conditions + +2.1. Grants + + Each Contributor hereby grants You a world-wide, royalty-free, + non-exclusive license: + + a. under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or as + part of a Larger Work; and + + b. under Patent Claims of such Contributor to make, use, sell, offer for + sale, have made, import, and otherwise transfer either its Contributions + or its Contributor Version. + +2.2. Effective Date + + The licenses granted in Section 2.1 with respect to any Contribution become + effective for each Contribution on the date the Contributor first distributes + such Contribution. + +2.3. Limitations on Grant Scope + + The licenses granted in this Section 2 are the only rights granted under this + License. No additional rights or licenses will be implied from the distribution + or licensing of Covered Software under this License. Notwithstanding Section + 2.1(b) above, no patent license is granted by a Contributor: + + a. for any code that a Contributor has removed from Covered Software; or + + b. for infringements caused by: (i) Your and any other third party’s + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + + c. under Patent Claims infringed by Covered Software in the absence of its + Contributions. + + This License does not grant any rights in the trademarks, service marks, or + logos of any Contributor (except as may be necessary to comply with the + notice requirements in Section 3.4). + +2.4. Subsequent Licenses + + No Contributor makes additional grants as a result of Your choice to + distribute the Covered Software under a subsequent version of this License + (see Section 10.2) or under the terms of a Secondary License (if permitted + under the terms of Section 3.3). + +2.5. Representation + + Each Contributor represents that the Contributor believes its Contributions + are its original creation(s) or it has sufficient rights to grant the + rights to its Contributions conveyed by this License. + +2.6. Fair Use + + This License is not intended to limit any rights You have under applicable + copyright doctrines of fair use, fair dealing, or other equivalents. + +2.7. Conditions + + Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in + Section 2.1. + + +3. Responsibilities + +3.1. Distribution of Source Form + + All distribution of Covered Software in Source Code Form, including any + Modifications that You create or to which You contribute, must be under the + terms of this License. You must inform recipients that the Source Code Form + of the Covered Software is governed by the terms of this License, and how + they can obtain a copy of this License. You may not attempt to alter or + restrict the recipients’ rights in the Source Code Form. + +3.2. Distribution of Executable Form + + If You distribute Covered Software in Executable Form then: + + a. such Covered Software must also be made available in Source Code Form, + as described in Section 3.1, and You must inform recipients of the + Executable Form how they can obtain a copy of such Source Code Form by + reasonable means in a timely manner, at a charge no more than the cost + of distribution to the recipient; and + + b. You may distribute such Executable Form under the terms of this License, + or sublicense it under different terms, provided that the license for + the Executable Form does not attempt to limit or alter the recipients’ + rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + + You may create and distribute a Larger Work under terms of Your choice, + provided that You also comply with the requirements of this License for the + Covered Software. If the Larger Work is a combination of Covered Software + with a work governed by one or more Secondary Licenses, and the Covered + Software is not Incompatible With Secondary Licenses, this License permits + You to additionally distribute such Covered Software under the terms of + such Secondary License(s), so that the recipient of the Larger Work may, at + their option, further distribute the Covered Software under the terms of + either this License or such Secondary License(s). + +3.4. Notices + + You may not remove or alter the substance of any license notices (including + copyright notices, patent notices, disclaimers of warranty, or limitations + of liability) contained within the Source Code Form of the Covered + Software, except that You may alter any license notices to the extent + required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + + You may choose to offer, and to charge a fee for, warranty, support, + indemnity or liability obligations to one or more recipients of Covered + Software. However, You may do so only on Your own behalf, and not on behalf + of any Contributor. You must make it absolutely clear that any such + warranty, support, indemnity, or liability obligation is offered by You + alone, and You hereby agree to indemnify every Contributor for any + liability incurred by such Contributor as a result of warranty, support, + indemnity or liability terms You offer. You may include additional + disclaimers of warranty and limitations of liability specific to any + jurisdiction. + +4. Inability to Comply Due to Statute or Regulation + + If it is impossible for You to comply with any of the terms of this License + with respect to some or all of the Covered Software due to statute, judicial + order, or regulation then You must: (a) comply with the terms of this License + to the maximum extent possible; and (b) describe the limitations and the code + they affect. Such description must be placed in a text file included with all + distributions of the Covered Software under this License. Except to the + extent prohibited by statute or regulation, such description must be + sufficiently detailed for a recipient of ordinary skill to be able to + understand it. + +5. Termination + +5.1. The rights granted under this License will terminate automatically if You + fail to comply with any of its terms. However, if You become compliant, + then the rights granted under this License from a particular Contributor + are reinstated (a) provisionally, unless and until such Contributor + explicitly and finally terminates Your grants, and (b) on an ongoing basis, + if such Contributor fails to notify You of the non-compliance by some + reasonable means prior to 60 days after You have come back into compliance. + Moreover, Your grants from a particular Contributor are reinstated on an + ongoing basis if such Contributor notifies You of the non-compliance by + some reasonable means, this is the first time You have received notice of + non-compliance with this License from such Contributor, and You become + compliant prior to 30 days after Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent + infringement claim (excluding declaratory judgment actions, counter-claims, + and cross-claims) alleging that a Contributor Version directly or + indirectly infringes any patent, then the rights granted to You by any and + all Contributors for the Covered Software under Section 2.1 of this License + shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user + license agreements (excluding distributors and resellers) which have been + validly granted by You or Your distributors under this License prior to + termination shall survive termination. + +6. Disclaimer of Warranty + + Covered Software is provided under this License on an “as is” basis, without + warranty of any kind, either expressed, implied, or statutory, including, + without limitation, warranties that the Covered Software is free of defects, + merchantable, fit for a particular purpose or non-infringing. The entire + risk as to the quality and performance of the Covered Software is with You. + Should any Covered Software prove defective in any respect, You (not any + Contributor) assume the cost of any necessary servicing, repair, or + correction. This disclaimer of warranty constitutes an essential part of this + License. No use of any Covered Software is authorized under this License + except under this disclaimer. + +7. Limitation of Liability + + Under no circumstances and under no legal theory, whether tort (including + negligence), contract, or otherwise, shall any Contributor, or anyone who + distributes Covered Software as permitted above, be liable to You for any + direct, indirect, special, incidental, or consequential damages of any + character including, without limitation, damages for lost profits, loss of + goodwill, work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses, even if such party shall have been + informed of the possibility of such damages. This limitation of liability + shall not apply to liability for death or personal injury resulting from such + party’s negligence to the extent applicable law prohibits such limitation. + Some jurisdictions do not allow the exclusion or limitation of incidental or + consequential damages, so this exclusion and limitation may not apply to You. + +8. Litigation + + Any litigation relating to this License may be brought only in the courts of + a jurisdiction where the defendant maintains its principal place of business + and such litigation shall be governed by laws of that jurisdiction, without + reference to its conflict-of-law provisions. Nothing in this Section shall + prevent a party’s ability to bring cross-claims or counter-claims. + +9. Miscellaneous + + This License represents the complete agreement concerning the subject matter + hereof. If any provision of this License is held to be unenforceable, such + provision shall be reformed only to the extent necessary to make it + enforceable. Any law or regulation which provides that the language of a + contract shall be construed against the drafter shall not be used to construe + this License against a Contributor. + + +10. Versions of the License + +10.1. New Versions + + Mozilla Foundation is the license steward. Except as provided in Section + 10.3, no one other than the license steward has the right to modify or + publish new versions of this License. Each version will be given a + distinguishing version number. + +10.2. Effect of New Versions + + You may distribute the Covered Software under the terms of the version of + the License under which You originally received the Covered Software, or + under the terms of any subsequent version published by the license + steward. + +10.3. Modified Versions + + If you create software not governed by this License, and you want to + create a new license for such software, you may create and use a modified + version of this License if you rename the license and remove any + references to the name of the license steward (except to note that such + modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses + If You choose to distribute Source Code Form that is Incompatible With + Secondary Licenses under the terms of this version of the License, the + notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice + + This Source Code Form is subject to the + terms of the Mozilla Public License, v. + 2.0. If a copy of the MPL was not + distributed with this file, You can + obtain one at + http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular file, then +You may include the notice in a location (such as a LICENSE file in a relevant +directory) where a recipient would be likely to look for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - “Incompatible With Secondary Licenses” Notice + + This Source Code Form is “Incompatible + With Secondary Licenses”, as defined by + the Mozilla Public License, v. 2.0. + diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/hashicorp/errwrap/README.md b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/hashicorp/errwrap/README.md new file mode 100644 index 0000000000..1c95f59782 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/hashicorp/errwrap/README.md @@ -0,0 +1,89 @@ +# errwrap + +`errwrap` is a package for Go that formalizes the pattern of wrapping errors +and checking if an error contains another error. + +There is a common pattern in Go of taking a returned `error` value and +then wrapping it (such as with `fmt.Errorf`) before returning it. The problem +with this pattern is that you completely lose the original `error` structure. + +Arguably the _correct_ approach is that you should make a custom structure +implementing the `error` interface, and have the original error as a field +on that structure, such [as this example](http://golang.org/pkg/os/#PathError). +This is a good approach, but you have to know the entire chain of possible +rewrapping that happens, when you might just care about one. + +`errwrap` formalizes this pattern (it doesn't matter what approach you use +above) by giving a single interface for wrapping errors, checking if a specific +error is wrapped, and extracting that error. + +## Installation and Docs + +Install using `go get github.com/hashicorp/errwrap`. + +Full documentation is available at +http://godoc.org/github.com/hashicorp/errwrap + +## Usage + +#### Basic Usage + +Below is a very basic example of its usage: + +```go +// A function that always returns an error, but wraps it, like a real +// function might. +func tryOpen() error { + _, err := os.Open("/i/dont/exist") + if err != nil { + return errwrap.Wrapf("Doesn't exist: {{err}}", err) + } + + return nil +} + +func main() { + err := tryOpen() + + // We can use the Contains helpers to check if an error contains + // another error. It is safe to do this with a nil error, or with + // an error that doesn't even use the errwrap package. + if errwrap.Contains(err, ErrNotExist) { + // Do something + } + if errwrap.ContainsType(err, new(os.PathError)) { + // Do something + } + + // Or we can use the associated `Get` functions to just extract + // a specific error. This would return nil if that specific error doesn't + // exist. + perr := errwrap.GetType(err, new(os.PathError)) +} +``` + +#### Custom Types + +If you're already making custom types that properly wrap errors, then +you can get all the functionality of `errwraps.Contains` and such by +implementing the `Wrapper` interface with just one function. Example: + +```go +type AppError { + Code ErrorCode + Err error +} + +func (e *AppError) WrappedErrors() []error { + return []error{e.Err} +} +``` + +Now this works: + +```go +err := &AppError{Err: fmt.Errorf("an error")} +if errwrap.ContainsType(err, fmt.Errorf("")) { + // This will work! +} +``` diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/hashicorp/errwrap/errwrap.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/hashicorp/errwrap/errwrap.go new file mode 100644 index 0000000000..a733bef18c --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/hashicorp/errwrap/errwrap.go @@ -0,0 +1,169 @@ +// Package errwrap implements methods to formalize error wrapping in Go. +// +// All of the top-level functions that take an `error` are built to be able +// to take any error, not just wrapped errors. This allows you to use errwrap +// without having to type-check and type-cast everywhere. +package errwrap + +import ( + "errors" + "reflect" + "strings" +) + +// WalkFunc is the callback called for Walk. +type WalkFunc func(error) + +// Wrapper is an interface that can be implemented by custom types to +// have all the Contains, Get, etc. functions in errwrap work. +// +// When Walk reaches a Wrapper, it will call the callback for every +// wrapped error in addition to the wrapper itself. Since all the top-level +// functions in errwrap use Walk, this means that all those functions work +// with your custom type. +type Wrapper interface { + WrappedErrors() []error +} + +// Wrap defines that outer wraps inner, returning an error type that +// can be cleanly used with the other methods in this package, such as +// Contains, GetAll, etc. +// +// This function won't modify the error message at all (the outer message +// will be used). +func Wrap(outer, inner error) error { + return &wrappedError{ + Outer: outer, + Inner: inner, + } +} + +// Wrapf wraps an error with a formatting message. This is similar to using +// `fmt.Errorf` to wrap an error. If you're using `fmt.Errorf` to wrap +// errors, you should replace it with this. +// +// format is the format of the error message. The string '{{err}}' will +// be replaced with the original error message. +func Wrapf(format string, err error) error { + outerMsg := "" + if err != nil { + outerMsg = err.Error() + } + + outer := errors.New(strings.Replace( + format, "{{err}}", outerMsg, -1)) + + return Wrap(outer, err) +} + +// Contains checks if the given error contains an error with the +// message msg. If err is not a wrapped error, this will always return +// false unless the error itself happens to match this msg. +func Contains(err error, msg string) bool { + return len(GetAll(err, msg)) > 0 +} + +// ContainsType checks if the given error contains an error with +// the same concrete type as v. If err is not a wrapped error, this will +// check the err itself. +func ContainsType(err error, v interface{}) bool { + return len(GetAllType(err, v)) > 0 +} + +// Get is the same as GetAll but returns the deepest matching error. +func Get(err error, msg string) error { + es := GetAll(err, msg) + if len(es) > 0 { + return es[len(es)-1] + } + + return nil +} + +// GetType is the same as GetAllType but returns the deepest matching error. +func GetType(err error, v interface{}) error { + es := GetAllType(err, v) + if len(es) > 0 { + return es[len(es)-1] + } + + return nil +} + +// GetAll gets all the errors that might be wrapped in err with the +// given message. The order of the errors is such that the outermost +// matching error (the most recent wrap) is index zero, and so on. +func GetAll(err error, msg string) []error { + var result []error + + Walk(err, func(err error) { + if err.Error() == msg { + result = append(result, err) + } + }) + + return result +} + +// GetAllType gets all the errors that are the same type as v. +// +// The order of the return value is the same as described in GetAll. +func GetAllType(err error, v interface{}) []error { + var result []error + + var search string + if v != nil { + search = reflect.TypeOf(v).String() + } + Walk(err, func(err error) { + var needle string + if err != nil { + needle = reflect.TypeOf(err).String() + } + + if needle == search { + result = append(result, err) + } + }) + + return result +} + +// Walk walks all the wrapped errors in err and calls the callback. If +// err isn't a wrapped error, this will be called once for err. If err +// is a wrapped error, the callback will be called for both the wrapper +// that implements error as well as the wrapped error itself. +func Walk(err error, cb WalkFunc) { + if err == nil { + return + } + + switch e := err.(type) { + case *wrappedError: + cb(e.Outer) + Walk(e.Inner, cb) + case Wrapper: + cb(err) + + for _, err := range e.WrappedErrors() { + Walk(err, cb) + } + default: + cb(err) + } +} + +// wrappedError is an implementation of error that has both the +// outer and inner errors. +type wrappedError struct { + Outer error + Inner error +} + +func (w *wrappedError) Error() string { + return w.Outer.Error() +} + +func (w *wrappedError) WrappedErrors() []error { + return []error{w.Outer, w.Inner} +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/hashicorp/go-multierror/LICENSE b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/hashicorp/go-multierror/LICENSE new file mode 100644 index 0000000000..82b4de97c7 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/hashicorp/go-multierror/LICENSE @@ -0,0 +1,353 @@ +Mozilla Public License, version 2.0 + +1. Definitions + +1.1. “Contributor” + + means each individual or legal entity that creates, contributes to the + creation of, or owns Covered Software. + +1.2. “Contributor Version” + + means the combination of the Contributions of others (if any) used by a + Contributor and that particular Contributor’s Contribution. + +1.3. “Contribution” + + means Covered Software of a particular Contributor. + +1.4. “Covered Software” + + means Source Code Form to which the initial Contributor has attached the + notice in Exhibit A, the Executable Form of such Source Code Form, and + Modifications of such Source Code Form, in each case including portions + thereof. + +1.5. “Incompatible With Secondary Licenses” + means + + a. that the initial Contributor has attached the notice described in + Exhibit B to the Covered Software; or + + b. that the Covered Software was made available under the terms of version + 1.1 or earlier of the License, but not also under the terms of a + Secondary License. + +1.6. “Executable Form” + + means any form of the work other than Source Code Form. + +1.7. “Larger Work” + + means a work that combines Covered Software with other material, in a separate + file or files, that is not Covered Software. + +1.8. “License” + + means this document. + +1.9. “Licensable” + + means having the right to grant, to the maximum extent possible, whether at the + time of the initial grant or subsequently, any and all of the rights conveyed by + this License. + +1.10. “Modifications” + + means any of the following: + + a. any file in Source Code Form that results from an addition to, deletion + from, or modification of the contents of Covered Software; or + + b. any new file in Source Code Form that contains any Covered Software. + +1.11. “Patent Claims” of a Contributor + + means any patent claim(s), including without limitation, method, process, + and apparatus claims, in any patent Licensable by such Contributor that + would be infringed, but for the grant of the License, by the making, + using, selling, offering for sale, having made, import, or transfer of + either its Contributions or its Contributor Version. + +1.12. “Secondary License” + + means either the GNU General Public License, Version 2.0, the GNU Lesser + General Public License, Version 2.1, the GNU Affero General Public + License, Version 3.0, or any later versions of those licenses. + +1.13. “Source Code Form” + + means the form of the work preferred for making modifications. + +1.14. “You” (or “Your”) + + means an individual or a legal entity exercising rights under this + License. For legal entities, “You” includes any entity that controls, is + controlled by, or is under common control with You. For purposes of this + definition, “control” means (a) the power, direct or indirect, to cause + the direction or management of such entity, whether by contract or + otherwise, or (b) ownership of more than fifty percent (50%) of the + outstanding shares or beneficial ownership of such entity. + + +2. License Grants and Conditions + +2.1. Grants + + Each Contributor hereby grants You a world-wide, royalty-free, + non-exclusive license: + + a. under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or as + part of a Larger Work; and + + b. under Patent Claims of such Contributor to make, use, sell, offer for + sale, have made, import, and otherwise transfer either its Contributions + or its Contributor Version. + +2.2. Effective Date + + The licenses granted in Section 2.1 with respect to any Contribution become + effective for each Contribution on the date the Contributor first distributes + such Contribution. + +2.3. Limitations on Grant Scope + + The licenses granted in this Section 2 are the only rights granted under this + License. No additional rights or licenses will be implied from the distribution + or licensing of Covered Software under this License. Notwithstanding Section + 2.1(b) above, no patent license is granted by a Contributor: + + a. for any code that a Contributor has removed from Covered Software; or + + b. for infringements caused by: (i) Your and any other third party’s + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + + c. under Patent Claims infringed by Covered Software in the absence of its + Contributions. + + This License does not grant any rights in the trademarks, service marks, or + logos of any Contributor (except as may be necessary to comply with the + notice requirements in Section 3.4). + +2.4. Subsequent Licenses + + No Contributor makes additional grants as a result of Your choice to + distribute the Covered Software under a subsequent version of this License + (see Section 10.2) or under the terms of a Secondary License (if permitted + under the terms of Section 3.3). + +2.5. Representation + + Each Contributor represents that the Contributor believes its Contributions + are its original creation(s) or it has sufficient rights to grant the + rights to its Contributions conveyed by this License. + +2.6. Fair Use + + This License is not intended to limit any rights You have under applicable + copyright doctrines of fair use, fair dealing, or other equivalents. + +2.7. Conditions + + Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in + Section 2.1. + + +3. Responsibilities + +3.1. Distribution of Source Form + + All distribution of Covered Software in Source Code Form, including any + Modifications that You create or to which You contribute, must be under the + terms of this License. You must inform recipients that the Source Code Form + of the Covered Software is governed by the terms of this License, and how + they can obtain a copy of this License. You may not attempt to alter or + restrict the recipients’ rights in the Source Code Form. + +3.2. Distribution of Executable Form + + If You distribute Covered Software in Executable Form then: + + a. such Covered Software must also be made available in Source Code Form, + as described in Section 3.1, and You must inform recipients of the + Executable Form how they can obtain a copy of such Source Code Form by + reasonable means in a timely manner, at a charge no more than the cost + of distribution to the recipient; and + + b. You may distribute such Executable Form under the terms of this License, + or sublicense it under different terms, provided that the license for + the Executable Form does not attempt to limit or alter the recipients’ + rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + + You may create and distribute a Larger Work under terms of Your choice, + provided that You also comply with the requirements of this License for the + Covered Software. If the Larger Work is a combination of Covered Software + with a work governed by one or more Secondary Licenses, and the Covered + Software is not Incompatible With Secondary Licenses, this License permits + You to additionally distribute such Covered Software under the terms of + such Secondary License(s), so that the recipient of the Larger Work may, at + their option, further distribute the Covered Software under the terms of + either this License or such Secondary License(s). + +3.4. Notices + + You may not remove or alter the substance of any license notices (including + copyright notices, patent notices, disclaimers of warranty, or limitations + of liability) contained within the Source Code Form of the Covered + Software, except that You may alter any license notices to the extent + required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + + You may choose to offer, and to charge a fee for, warranty, support, + indemnity or liability obligations to one or more recipients of Covered + Software. However, You may do so only on Your own behalf, and not on behalf + of any Contributor. You must make it absolutely clear that any such + warranty, support, indemnity, or liability obligation is offered by You + alone, and You hereby agree to indemnify every Contributor for any + liability incurred by such Contributor as a result of warranty, support, + indemnity or liability terms You offer. You may include additional + disclaimers of warranty and limitations of liability specific to any + jurisdiction. + +4. Inability to Comply Due to Statute or Regulation + + If it is impossible for You to comply with any of the terms of this License + with respect to some or all of the Covered Software due to statute, judicial + order, or regulation then You must: (a) comply with the terms of this License + to the maximum extent possible; and (b) describe the limitations and the code + they affect. Such description must be placed in a text file included with all + distributions of the Covered Software under this License. Except to the + extent prohibited by statute or regulation, such description must be + sufficiently detailed for a recipient of ordinary skill to be able to + understand it. + +5. Termination + +5.1. The rights granted under this License will terminate automatically if You + fail to comply with any of its terms. However, if You become compliant, + then the rights granted under this License from a particular Contributor + are reinstated (a) provisionally, unless and until such Contributor + explicitly and finally terminates Your grants, and (b) on an ongoing basis, + if such Contributor fails to notify You of the non-compliance by some + reasonable means prior to 60 days after You have come back into compliance. + Moreover, Your grants from a particular Contributor are reinstated on an + ongoing basis if such Contributor notifies You of the non-compliance by + some reasonable means, this is the first time You have received notice of + non-compliance with this License from such Contributor, and You become + compliant prior to 30 days after Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent + infringement claim (excluding declaratory judgment actions, counter-claims, + and cross-claims) alleging that a Contributor Version directly or + indirectly infringes any patent, then the rights granted to You by any and + all Contributors for the Covered Software under Section 2.1 of this License + shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user + license agreements (excluding distributors and resellers) which have been + validly granted by You or Your distributors under this License prior to + termination shall survive termination. + +6. Disclaimer of Warranty + + Covered Software is provided under this License on an “as is” basis, without + warranty of any kind, either expressed, implied, or statutory, including, + without limitation, warranties that the Covered Software is free of defects, + merchantable, fit for a particular purpose or non-infringing. The entire + risk as to the quality and performance of the Covered Software is with You. + Should any Covered Software prove defective in any respect, You (not any + Contributor) assume the cost of any necessary servicing, repair, or + correction. This disclaimer of warranty constitutes an essential part of this + License. No use of any Covered Software is authorized under this License + except under this disclaimer. + +7. Limitation of Liability + + Under no circumstances and under no legal theory, whether tort (including + negligence), contract, or otherwise, shall any Contributor, or anyone who + distributes Covered Software as permitted above, be liable to You for any + direct, indirect, special, incidental, or consequential damages of any + character including, without limitation, damages for lost profits, loss of + goodwill, work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses, even if such party shall have been + informed of the possibility of such damages. This limitation of liability + shall not apply to liability for death or personal injury resulting from such + party’s negligence to the extent applicable law prohibits such limitation. + Some jurisdictions do not allow the exclusion or limitation of incidental or + consequential damages, so this exclusion and limitation may not apply to You. + +8. Litigation + + Any litigation relating to this License may be brought only in the courts of + a jurisdiction where the defendant maintains its principal place of business + and such litigation shall be governed by laws of that jurisdiction, without + reference to its conflict-of-law provisions. Nothing in this Section shall + prevent a party’s ability to bring cross-claims or counter-claims. + +9. Miscellaneous + + This License represents the complete agreement concerning the subject matter + hereof. If any provision of this License is held to be unenforceable, such + provision shall be reformed only to the extent necessary to make it + enforceable. Any law or regulation which provides that the language of a + contract shall be construed against the drafter shall not be used to construe + this License against a Contributor. + + +10. Versions of the License + +10.1. New Versions + + Mozilla Foundation is the license steward. Except as provided in Section + 10.3, no one other than the license steward has the right to modify or + publish new versions of this License. Each version will be given a + distinguishing version number. + +10.2. Effect of New Versions + + You may distribute the Covered Software under the terms of the version of + the License under which You originally received the Covered Software, or + under the terms of any subsequent version published by the license + steward. + +10.3. Modified Versions + + If you create software not governed by this License, and you want to + create a new license for such software, you may create and use a modified + version of this License if you rename the license and remove any + references to the name of the license steward (except to note that such + modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses + If You choose to distribute Source Code Form that is Incompatible With + Secondary Licenses under the terms of this version of the License, the + notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice + + This Source Code Form is subject to the + terms of the Mozilla Public License, v. + 2.0. If a copy of the MPL was not + distributed with this file, You can + obtain one at + http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular file, then +You may include the notice in a location (such as a LICENSE file in a relevant +directory) where a recipient would be likely to look for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - “Incompatible With Secondary Licenses” Notice + + This Source Code Form is “Incompatible + With Secondary Licenses”, as defined by + the Mozilla Public License, v. 2.0. diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/hashicorp/go-multierror/README.md b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/hashicorp/go-multierror/README.md new file mode 100644 index 0000000000..ead5830f7b --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/hashicorp/go-multierror/README.md @@ -0,0 +1,97 @@ +# go-multierror + +[![Build Status](http://img.shields.io/travis/hashicorp/go-multierror.svg?style=flat-square)][travis] +[![Go Documentation](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)][godocs] + +[travis]: https://travis-ci.org/hashicorp/go-multierror +[godocs]: https://godoc.org/github.com/hashicorp/go-multierror + +`go-multierror` is a package for Go that provides a mechanism for +representing a list of `error` values as a single `error`. + +This allows a function in Go to return an `error` that might actually +be a list of errors. If the caller knows this, they can unwrap the +list and access the errors. If the caller doesn't know, the error +formats to a nice human-readable format. + +`go-multierror` implements the +[errwrap](https://github.com/hashicorp/errwrap) interface so that it can +be used with that library, as well. + +## Installation and Docs + +Install using `go get github.com/hashicorp/go-multierror`. + +Full documentation is available at +http://godoc.org/github.com/hashicorp/go-multierror + +## Usage + +go-multierror is easy to use and purposely built to be unobtrusive in +existing Go applications/libraries that may not be aware of it. + +**Building a list of errors** + +The `Append` function is used to create a list of errors. This function +behaves a lot like the Go built-in `append` function: it doesn't matter +if the first argument is nil, a `multierror.Error`, or any other `error`, +the function behaves as you would expect. + +```go +var result error + +if err := step1(); err != nil { + result = multierror.Append(result, err) +} +if err := step2(); err != nil { + result = multierror.Append(result, err) +} + +return result +``` + +**Customizing the formatting of the errors** + +By specifying a custom `ErrorFormat`, you can customize the format +of the `Error() string` function: + +```go +var result *multierror.Error + +// ... accumulate errors here, maybe using Append + +if result != nil { + result.ErrorFormat = func([]error) string { + return "errors!" + } +} +``` + +**Accessing the list of errors** + +`multierror.Error` implements `error` so if the caller doesn't know about +multierror, it will work just fine. But if you're aware a multierror might +be returned, you can use type switches to access the list of errors: + +```go +if err := something(); err != nil { + if merr, ok := err.(*multierror.Error); ok { + // Use merr.Errors + } +} +``` + +**Returning a multierror only if there are errors** + +If you build a `multierror.Error`, you can use the `ErrorOrNil` function +to return an `error` implementation only if there are errors to return: + +```go +var result *multierror.Error + +// ... accumulate errors here + +// Return the `error` only if errors were added to the multierror, otherwise +// return nil since there are no errors. +return result.ErrorOrNil() +``` diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/hashicorp/go-multierror/append.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/hashicorp/go-multierror/append.go new file mode 100644 index 0000000000..775b6e753e --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/hashicorp/go-multierror/append.go @@ -0,0 +1,41 @@ +package multierror + +// Append is a helper function that will append more errors +// onto an Error in order to create a larger multi-error. +// +// If err is not a multierror.Error, then it will be turned into +// one. If any of the errs are multierr.Error, they will be flattened +// one level into err. +func Append(err error, errs ...error) *Error { + switch err := err.(type) { + case *Error: + // Typed nils can reach here, so initialize if we are nil + if err == nil { + err = new(Error) + } + + // Go through each error and flatten + for _, e := range errs { + switch e := e.(type) { + case *Error: + if e != nil { + err.Errors = append(err.Errors, e.Errors...) + } + default: + if e != nil { + err.Errors = append(err.Errors, e) + } + } + } + + return err + default: + newErrs := make([]error, 0, len(errs)+1) + if err != nil { + newErrs = append(newErrs, err) + } + newErrs = append(newErrs, errs...) + + return Append(&Error{}, newErrs...) + } +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/hashicorp/go-multierror/flatten.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/hashicorp/go-multierror/flatten.go new file mode 100644 index 0000000000..aab8e9abec --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/hashicorp/go-multierror/flatten.go @@ -0,0 +1,26 @@ +package multierror + +// Flatten flattens the given error, merging any *Errors together into +// a single *Error. +func Flatten(err error) error { + // If it isn't an *Error, just return the error as-is + if _, ok := err.(*Error); !ok { + return err + } + + // Otherwise, make the result and flatten away! + flatErr := new(Error) + flatten(err, flatErr) + return flatErr +} + +func flatten(err error, flatErr *Error) { + switch err := err.(type) { + case *Error: + for _, e := range err.Errors { + flatten(e, flatErr) + } + default: + flatErr.Errors = append(flatErr.Errors, err) + } +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/hashicorp/go-multierror/format.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/hashicorp/go-multierror/format.go new file mode 100644 index 0000000000..6c7a3cc91d --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/hashicorp/go-multierror/format.go @@ -0,0 +1,27 @@ +package multierror + +import ( + "fmt" + "strings" +) + +// ErrorFormatFunc is a function callback that is called by Error to +// turn the list of errors into a string. +type ErrorFormatFunc func([]error) string + +// ListFormatFunc is a basic formatter that outputs the number of errors +// that occurred along with a bullet point list of the errors. +func ListFormatFunc(es []error) string { + if len(es) == 1 { + return fmt.Sprintf("1 error occurred:\n\n* %s", es[0]) + } + + points := make([]string, len(es)) + for i, err := range es { + points[i] = fmt.Sprintf("* %s", err) + } + + return fmt.Sprintf( + "%d errors occurred:\n\n%s", + len(es), strings.Join(points, "\n")) +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/hashicorp/go-multierror/multierror.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/hashicorp/go-multierror/multierror.go new file mode 100644 index 0000000000..2ea0827329 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/hashicorp/go-multierror/multierror.go @@ -0,0 +1,51 @@ +package multierror + +import ( + "fmt" +) + +// Error is an error type to track multiple errors. This is used to +// accumulate errors in cases and return them as a single "error". +type Error struct { + Errors []error + ErrorFormat ErrorFormatFunc +} + +func (e *Error) Error() string { + fn := e.ErrorFormat + if fn == nil { + fn = ListFormatFunc + } + + return fn(e.Errors) +} + +// ErrorOrNil returns an error interface if this Error represents +// a list of errors, or returns nil if the list of errors is empty. This +// function is useful at the end of accumulation to make sure that the value +// returned represents the existence of errors. +func (e *Error) ErrorOrNil() error { + if e == nil { + return nil + } + if len(e.Errors) == 0 { + return nil + } + + return e +} + +func (e *Error) GoString() string { + return fmt.Sprintf("*%#v", *e) +} + +// WrappedErrors returns the list of errors that this Error is wrapping. +// It is an implementatin of the errwrap.Wrapper interface so that +// multierror.Error can be used with that library. +// +// This method is not safe to be called concurrently and is no different +// than accessing the Errors field directly. It is implementd only to +// satisfy the errwrap.Wrapper interface. +func (e *Error) WrappedErrors() []error { + return e.Errors +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/hashicorp/go-multierror/prefix.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/hashicorp/go-multierror/prefix.go new file mode 100644 index 0000000000..5c477abe44 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/hashicorp/go-multierror/prefix.go @@ -0,0 +1,37 @@ +package multierror + +import ( + "fmt" + + "github.com/hashicorp/errwrap" +) + +// Prefix is a helper function that will prefix some text +// to the given error. If the error is a multierror.Error, then +// it will be prefixed to each wrapped error. +// +// This is useful to use when appending multiple multierrors +// together in order to give better scoping. +func Prefix(err error, prefix string) error { + if err == nil { + return nil + } + + format := fmt.Sprintf("%s {{err}}", prefix) + switch err := err.(type) { + case *Error: + // Typed nils can reach here, so initialize if we are nil + if err == nil { + err = new(Error) + } + + // Wrap each of the errors + for i, e := range err.Errors { + err.Errors[i] = errwrap.Wrapf(format, e) + } + + return err + default: + return errwrap.Wrapf(format, err) + } +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/konsorten/go-windows-terminal-sequences/LICENSE b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/konsorten/go-windows-terminal-sequences/LICENSE new file mode 100644 index 0000000000..14127cd831 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/konsorten/go-windows-terminal-sequences/LICENSE @@ -0,0 +1,9 @@ +(The MIT License) + +Copyright (c) 2017 marvin + konsorten GmbH (open-source@konsorten.de) + +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. diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/konsorten/go-windows-terminal-sequences/README.md b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/konsorten/go-windows-terminal-sequences/README.md new file mode 100644 index 0000000000..949b77e304 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/konsorten/go-windows-terminal-sequences/README.md @@ -0,0 +1,40 @@ +# Windows Terminal Sequences + +This library allow for enabling Windows terminal color support for Go. + +See [Console Virtual Terminal Sequences](https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences) for details. + +## Usage + +```go +import ( + "syscall" + + sequences "github.com/konsorten/go-windows-terminal-sequences" +) + +func main() { + sequences.EnableVirtualTerminalProcessing(syscall.Stdout, true) +} + +``` + +## Authors + +The tool is sponsored by the [marvin + konsorten GmbH](http://www.konsorten.de). + +We thank all the authors who provided code to this library: + +* Felix Kollmann + +## License + +(The MIT License) + +Copyright (c) 2018 marvin + konsorten GmbH (open-source@konsorten.de) + +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. diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/konsorten/go-windows-terminal-sequences/sequences.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/konsorten/go-windows-terminal-sequences/sequences.go new file mode 100644 index 0000000000..ef18d8f978 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/konsorten/go-windows-terminal-sequences/sequences.go @@ -0,0 +1,36 @@ +// +build windows + +package sequences + +import ( + "syscall" + "unsafe" +) + +var ( + kernel32Dll *syscall.LazyDLL = syscall.NewLazyDLL("Kernel32.dll") + setConsoleMode *syscall.LazyProc = kernel32Dll.NewProc("SetConsoleMode") +) + +func EnableVirtualTerminalProcessing(stream syscall.Handle, enable bool) error { + const ENABLE_VIRTUAL_TERMINAL_PROCESSING uint32 = 0x4 + + var mode uint32 + err := syscall.GetConsoleMode(syscall.Stdout, &mode) + if err != nil { + return err + } + + if enable { + mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING + } else { + mode &^= ENABLE_VIRTUAL_TERMINAL_PROCESSING + } + + ret, _, err := setConsoleMode.Call(uintptr(unsafe.Pointer(stream)), uintptr(mode)) + if ret == 0 { + return err + } + + return nil +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/linuxkit/virtsock/LICENSE b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/linuxkit/virtsock/LICENSE new file mode 100644 index 0000000000..57e2b431d5 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/linuxkit/virtsock/LICENSE @@ -0,0 +1,16 @@ +Unless explicitly stated at the top of the file, this code is covered +by the following license: + +Copyright 2016-2017 The authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/linuxkit/virtsock/README.md b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/linuxkit/virtsock/README.md new file mode 100644 index 0000000000..39780d7ffd --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/linuxkit/virtsock/README.md @@ -0,0 +1,100 @@ + +This repository contains Go bindings and sample code for [Hyper-V sockets](https://msdn.microsoft.com/en-us/virtualization/hyperv_on_windows/develop/make_mgmt_service) and [virtio sockets](http://stefanha.github.io/virtio/)(VSOCK). + +## Organisation + +- `pkg/hvsock`: Go binding for Hyper-V sockets +- `pkg/vsock`: Go binding for virtio VSOCK +- `cmd/sock_stress`: A stress test program for virtsock +- `cmd/vsudd`: A unix domain socket to virtsock proxy (used in Docker for Mac/Windows) +- `scripts`: Miscellaneous scripts +- `c`: Sample C code (including benchmarks and stress tests) +- `data`: Data from benchmarks + + +## Building + +By default the Go sample code is build in a container. Simply type `make`. + +If you want to build binaries on a local system use `make build-binaries`. + +## Testing + +There are several examples and tests written both in [Go](./cmd) and in [C](./c). The C code is Hyper-V sockets specific while the Go code also works with virtio sockets and [HyperKit](https://github.com/moby/hyperkit). The respective READMEs contain instructions on how to run the tests, but the simplest way is to use [LinuxKit](https://github.com/linuxkit/linuxkit). + +Assuming you have LinuxKit installed, the make target `make linuxkit` +will build a custom Linux image which can be booted on HyperKit or on +Windows. The custom Linux image contains the test binaries. + +### macOS + +Boot the Linux VM: +``` +linuxkit run hvtest +``` +This should create a directory called `./hvtest-state`. + +Run the server in the VM and client on the host: +``` +linux$ sock_stress -s vsock -v 1 +macos$ ./bin/sock_stress.darwin -c vsock://3 -m hyperkit:./hvtest-state -v 1 +``` + +Run the server on the host and the client inside the VM: +``` +macos$ ./bin/sock_stress.darwin -s vsock -m hyperkit:./hvtest-state -v 1 +linux$ sock_stress -c vsock://2 -v 1 +``` + +### Windows + +On Windows we currently only support the server to be run inside the +VM and the host connecting to it. In the future we will support +running the server on the host as well. + +For Linux guests on Windows there are two different implmentations, +one in the LinuxKit 4.9.x kernels and one in 4.14.x upstream +kernels. They require different protocols to be used. The +`sock_stress` and `vsudd` programs automatically detect which version +to use. + +Boot the Linux VM (from an elevated powershell): +``` +linuxkit run -name hvtest hvtest-efi.iso +``` + +Run the server in the VM and client on the host: +``` +linux$ sock_stress -v 1 -s hvsock +win$ sock_stress -v 1 -c hvsock:// +``` +(where `` is from the output of: `(get-vm hvtest).Id`) + +Run the server on the host and the client inside the VM: +``` +win$ sock_stress -v 1 -s hvsock +linux$ sock_stress -v 1 -c hvsock://parent +``` +**Note:** This may fail on the client with receiving unexpected EOFs (see below). + + +## Known limitations + +- `hvsock`: When running the server on the host with a client in a + Linux VM, it looks like unidirectional `shutdown()` is not working + properly. There appears to be a race of sort. + +- `hvsock`: Hyper-V socket implementations prior to Windows build + 10586 (aka 1511, aka Threshold 2) was buggy. There may even be + issues with build prior to build 14393 (aka 1607, aka Redstone 1). + +- `hvsock`: Earlier versions of this code supported the older Windows + builds, but support has now been removed. If you require the older version, + please use the `end_10586_tag`. + +- `vsock`: There is general host side implementation as the interface + is hypervisor specific. The `vsock` package includes some support + for connecting with the VSOCK implementation in + [Hyperkit](https://github.com/moby/hyperkit), but there is no + implementation for, e.g. `qemu`. + diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/linuxkit/virtsock/c/README.md b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/linuxkit/virtsock/c/README.md new file mode 100644 index 0000000000..cd34da242d --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/linuxkit/virtsock/c/README.md @@ -0,0 +1,48 @@ +# Hyper-V sockets sample applications + +## Building + +Building is driven by `make` (or `mingw32-make.exe`). By default both +Linux and Windows binaries are build. + +Linux builds are done via Dockerfiles and create static binaries. + +Windows builds require MSBuild, Visual Studio and Windows SDK +installed with a minimum version of 14290. The project/solutions +assumes 14291, so you may have to adjust the +`WindowsTargetPlatformVersion` in the project files. + + +## Running + +All sample application assume a service ID of `3049197C-FACB-11E6-BD58-64006A7986D3` which needs to be registered *once* using: +``` +$service = New-Item -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Virtualization\GuestCommunicationServices" -Name 3049197C-FACB-11E6-BD58-64006A7986D3 + +$service.SetValue("ElementName", "Hyper-V Socket Echo Service") +``` + +### Echo applications + +The echo server is started with: +``` +hvecho -s +``` + +The client supports a number of modes. By default, with no arguments supplied it will connected using loopback mode, i.e. it tries to connect to the server on the same partition: +``` +hvecho -c +``` + +The client can be run in a VM and started with: +``` +hvecho -c parent +``` +which attempts to connect to the server in the parent partition. + + +Finally, if the server is run in a VM, the client can be invoked in the parent partition with: +``` +client -c +``` +where `` is the GUID of the VM the server is running in. The GUID can be retrieved with: `(get-vm ).id`. diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/linuxkit/virtsock/c/compat.h b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/linuxkit/virtsock/c/compat.h new file mode 100644 index 0000000000..7078db8b46 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/linuxkit/virtsock/c/compat.h @@ -0,0 +1,365 @@ +/* + * Compatibility layer between Windows and Linux + */ +#ifdef _MSC_VER + +#undef UNICODE +#define WIN32_LEAN_AND_MEAN +#define _CRT_SECURE_NO_WARNINGS + +#include +#include +#include +#include + +#pragma comment (lib, "Ws2_32.lib") +#pragma comment (lib, "Mswsock.lib") +#pragma comment (lib, "AdvApi32.lib") + +#else /* !_MSC_VER */ +#include +#include +#include +#include +#include +#include +#include +#include +#endif /* !_MSC_VER */ + +#include + +#ifdef _MSC_VER +typedef int socklen_t; + +typedef __int8 int8_t; +typedef __int16 int16_t; +typedef __int32 int32_t; +typedef __int64 int64_t; + +typedef unsigned __int8 uint8_t; +typedef unsigned __int16 uint16_t; +typedef unsigned __int32 uint32_t; +typedef unsigned __int64 uint64_t; +#endif + +#ifndef _MSC_VER +/* Compat layer for Linux/Unix */ +typedef int SOCKET; + +#ifndef SOCKET_ERROR +#define SOCKET_ERROR -1 +#endif + +#ifndef INVALID_SOCKET +#define INVALID_SOCKET -1 +#endif + +#define closesocket(_fd) close(_fd) + +/* Shutdown flags are different too */ +#define SD_SEND SHUT_WR +#define SD_RECEIVE SHUT_RD +#define SD_BOTH SHUT_RDWR + +#define __cdecl + +/* GUID handling */ +typedef struct _GUID { + uint32_t Data1; + uint16_t Data2; + uint16_t Data3; + uint8_t Data4[8]; +} GUID; + +#define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ + const GUID name = {l, w1, w2, {b1, b2, b3, b4, b5, b6, b7, b8}} + + +/* HV Socket definitions */ +#define AF_HYPERV 43 +#define HV_PROTOCOL_RAW 1 + +typedef struct _SOCKADDR_HV +{ + unsigned short Family; + unsigned short Reserved; + GUID VmId; + GUID ServiceId; +} SOCKADDR_HV; + +DEFINE_GUID(HV_GUID_ZERO, + 0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); +DEFINE_GUID(HV_GUID_BROADCAST, + 0xFFFFFFFF, 0xFFFF, 0xFFFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); +DEFINE_GUID(HV_GUID_WILDCARD, + 0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); + +DEFINE_GUID(HV_GUID_CHILDREN, + 0x90db8b89, 0x0d35, 0x4f79, 0x8c, 0xe9, 0x49, 0xea, 0x0a, 0xc8, 0xb7, 0xcd); +DEFINE_GUID(HV_GUID_LOOPBACK, + 0xe0e16197, 0xdd56, 0x4a10, 0x91, 0x95, 0x5e, 0xe7, 0xa1, 0x55, 0xa8, 0x38); +DEFINE_GUID(HV_GUID_PARENT, + 0xa42e7cda, 0xd03f, 0x480c, 0x9c, 0xc2, 0xa4, 0xde, 0x20, 0xab, 0xb8, 0x78); + +#endif /* !_MSC_VER */ + +/* Common definitions (only valid on Linux, though) */ +#ifndef AF_VSOCK +#define AF_VSOCK 40 +#endif +#ifndef VMADDR_CID_ANY +#define VMADDR_CID_ANY -1U +#endif +#ifndef VMADDR_CID_HYPERVISOR +#define VMADDR_CID_HYPERVISOR 0 +#endif +#ifndef VMADDR_CID_RESERVED +#define VMADDR_CID_RESERVED 1 +#endif +#ifndef VMADDR_CID_HOST +#define VMADDR_CID_HOST 2 +#endif +typedef struct _SOCKADDR_VM +{ + unsigned short Family; + unsigned short Reserved; + unsigned int SvmPort; + unsigned int SvmCID; +#ifndef _MSC_VER + unsigned char svm_zero[sizeof(struct sockaddr) - + sizeof(sa_family_t) - sizeof(unsigned short) - + sizeof(unsigned int) - sizeof(unsigned int)]; +#endif +} SOCKADDR_VM; + + +/* Thread wrappers */ +#ifdef _MSC_VER +typedef HANDLE THREAD_HANDLE; + +static inline int thread_create(THREAD_HANDLE *t, void *(*f)(void *), void *arg) +{ + *t = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)f, arg, 0, NULL); + return 0; +} + +static inline int thread_join(THREAD_HANDLE t) +{ + WaitForSingleObject(t, INFINITE); + return 0; +} + +static inline int thread_detach(THREAD_HANDLE t) +{ + return CloseHandle(t); +} +#else +#include + +typedef pthread_t THREAD_HANDLE; + +static inline int thread_create(THREAD_HANDLE *t, void *(*f)(void *), void *arg) +{ + return pthread_create(t, NULL, f, arg); +} + +static inline int thread_join(THREAD_HANDLE t) +{ + return pthread_join(t, NULL); +} + +static inline int thread_detach(THREAD_HANDLE t) +{ + return pthread_detach(t); +} +#endif + + +/* Time wrappers */ +#ifdef _MSC_VER +static inline uint64_t time_ns(void) +{ + LARGE_INTEGER t, freq; + + QueryPerformanceFrequency(&freq); + QueryPerformanceCounter(&t); + + t.QuadPart *= 1000000000; + return (uint64_t)t.QuadPart / freq.QuadPart; +} + +static inline unsigned int sleep(unsigned int sec) +{ + Sleep(sec * 1000); + return 0; +} + +#else +static inline uint64_t time_ns(void) +{ + struct timespec ts; + int ret; + + ret = clock_gettime(CLOCK_MONOTONIC_RAW, &ts); + if (ret) + return 0; + + /* We don't really mind if this overflows...There are plenty of bits */ + return (uint64_t)ts.tv_sec * 1000000000 + ts.tv_nsec; +} +#endif + +/* + * Finally some common utility macros and functions + */ +#include +#include + +#define GUID_FMT "%08x-%04hx-%04hx-%02x%02x-%02x%02x%02x%02x%02x%02x" +#define GUID_ARGS(_g) \ + (_g).Data1, (_g).Data2, (_g).Data3, \ + (_g).Data4[0], (_g).Data4[1], (_g).Data4[2], (_g).Data4[3], \ + (_g).Data4[4], (_g).Data4[5], (_g).Data4[6], (_g).Data4[7] +#define GUID_SARGS(_g) \ + &(_g).Data1, &(_g).Data2, &(_g).Data3, \ + &(_g).Data4[0], &(_g).Data4[1], &(_g).Data4[2], &(_g).Data4[3], \ + &(_g).Data4[4], &(_g).Data4[5], &(_g).Data4[6], &(_g).Data4[7] + + +static inline int parseguid(const char *s, GUID *g) +{ + int res; + int p0, p1, p2, p3, p4, p5, p6, p7; + + res = sscanf(s, GUID_FMT, + &g->Data1, &g->Data2, &g->Data3, + &p0, &p1, &p2, &p3, &p4, &p5, &p6, &p7); + if (res != 11) + return 1; + g->Data4[0] = p0; + g->Data4[1] = p1; + g->Data4[2] = p2; + g->Data4[3] = p3; + g->Data4[4] = p4; + g->Data4[5] = p5; + g->Data4[6] = p6; + g->Data4[7] = p7; + return 0; +} + +/* Slightly different error handling between Windows and Linux */ +static inline void sockerr(const char *msg) +{ +#ifdef _MSC_VER + fprintf(stderr, "%s Error: %d\n", msg, WSAGetLastError()); +#else + fprintf(stderr, "%s Error: %d. %s\n", msg, errno, strerror(errno)); +#endif +} + +/* poll wrappers */ + +/* Set socket to non-blocking */ +static inline int poll_enable(SOCKET s) +{ + int ret; +#ifdef _MSC_VER + unsigned long mode = 1; + ret = ioctlsocket(s, FIONBIO, &mode); +#else + int flags; + flags = fcntl(s, F_GETFL, 0); + if (flags < 0) + return flags; + ret = fcntl(s, F_SETFL, flags | O_NONBLOCK); +#endif + return ret; +} + +/* Set socket to non-blocking */ +static inline int poll_disable(SOCKET s) +{ + int ret; +#ifdef _MSC_VER + unsigned long mode = 0; + ret = ioctlsocket(s, FIONBIO, &mode); +#else + int flags; + flags = fcntl(s, F_GETFL, 0); + if (flags < 0) + return flags; + ret = fcntl(s, F_SETFL, flags & ~O_NONBLOCK); +#endif + return ret; +} + +/* Return true if we should poll */ +static inline int poll_check() +{ +#ifdef _MSC_VER + int err = WSAGetLastError(); + return err == WSAEWOULDBLOCK || err == WSAEFAULT; +#else + return errno == EWOULDBLOCK || errno == EAGAIN; +#endif +} + +#ifdef _MSC_VER +static inline int poll(struct pollfd fds[], unsigned long nfds, int timeout) +{ + return WSAPoll(fds, nfds, timeout); +} +#endif + +/* Connect with timeout (in milliseconds), different to WinSock ConnectEx() */ +static inline int connect_ex(int s, const struct sockaddr *sa, + socklen_t len, int timeout) +{ + struct timeval tv; + fd_set fdset; + int ret; + + ret = poll_enable(s); + if (ret < 0) + return ret; + + ret = connect(s, sa, len); + if (!ret) + goto out; /* Connected */ + + /* Got an error, see if we should select() */ +#ifdef _MSC_VER + ret = WSAGetLastError(); + if (ret != WSAEWOULDBLOCK) { + ret = SOCKET_ERROR; + goto out; + } +#else + if (errno != EINPROGRESS) + goto out; +#endif + + FD_ZERO(&fdset); + FD_SET(s, &fdset); + tv.tv_sec = 0; + tv.tv_usec = timeout * 1000; + + ret = select(s + 1, NULL, &fdset, NULL, &tv); + if (ret != 1) { + ret = SOCKET_ERROR; + goto out; + } + + /* Check status */ + ret = 0; + len = sizeof(ret); + /* char * is for windows... */ + getsockopt(s, SOL_SOCKET, SO_ERROR, (char *)&ret, &len); + if (ret != 0) + ret = SOCKET_ERROR; + +out: + poll_disable(s); + return ret; +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/linuxkit/virtsock/c/hvbench.c b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/linuxkit/virtsock/c/hvbench.c new file mode 100644 index 0000000000..b35f902988 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/linuxkit/virtsock/c/hvbench.c @@ -0,0 +1,552 @@ +/* + * A Hyper-V socket benchmarking program + */ +#include "compat.h" + +#include +#include +#include + +/* 3049197C-FACB-11E6-BD58-64006A7986D3 */ +DEFINE_GUID(BM_GUID, + 0x3049197c, 0xfacb, 0x11e6, 0xbd, 0x58, 0x64, 0x00, 0x6a, 0x79, 0x86, 0xd3); +#define BM_PORT 0x3049197c + +#ifdef _MSC_VER +static WSADATA wsaData; +#endif + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(_arr) (sizeof(_arr)/sizeof(*(_arr))) +#endif + +/* Use a static buffer for send and receive. */ +#define MAX_BUF_LEN (2 * 1024 * 1024) +static char buf[MAX_BUF_LEN]; + +/* Time (in ns) to run eeach bandwidth test */ +#define BM_BW_TIME (10ULL * 1000 * 1000 * 1000) + +/* How many connections to make */ +#define BM_CONNS 2000 + +static int verbose; +#define INFO(...) \ + do { \ + if (verbose) { \ + printf(__VA_ARGS__); \ + fflush(stdout); \ + } \ + } while (0) +#define DBG(...) \ + do { \ + if (verbose > 1) { \ + printf(__VA_ARGS__); \ + fflush(stdout); \ + } \ + } while (0) +#define TRC(...) \ + do { \ + if (verbose > 2) { \ + printf(__VA_ARGS__); \ + fflush(stdout); \ + } \ + } while (0) + + +enum benchmark { + BM_BW_UNI = 1, /* Uni-directional Bandwidth benchamrk */ + BM_LAT = 2, /* Message ping-pong latency over single connection */ + BM_CONN = 3, /* Connection benchmark */ +}; + + +/* There's anecdotal evidence that a blocking send()/recv() is slower + * than performing non-blocking send()/recv() calls and then use + * epoll()/WSAPoll(). This flags switches between the two + */ +static int opt_poll; +/* Use the vsock interface on Linux */ +static int opt_vsock; + + +/* Bandwidth tests: + * + * The TX side sends a fixed amount of data in fixed sized + * messages. The RX side drains the ring in message sized chunks (or less). + */ +static int bw_rx(SOCKET fd, int msg_sz) +{ + struct pollfd pfd = { 0 }; + int rx_sz; + int ret; + + if (opt_poll) { + pfd.fd = fd; + pfd.events = POLLIN; + } + + rx_sz = msg_sz ? msg_sz : ARRAY_SIZE(buf); + + DBG("bw_rx: msg_sz=%d rx_sz=%d\n", msg_sz, rx_sz); + + for (;;) { + ret = recv(fd, buf, rx_sz, 0); + if (ret == 0) { + break; + } else if (ret == SOCKET_ERROR) { + if (opt_poll && poll_check()) { + pfd.revents = 0; + poll(&pfd, 1, -1); /* XXX no error checking */ + continue; + } + sockerr("recv()"); + ret = -1; + goto err_out; + } + TRC("Received: %d\n", ret); + } + ret = 0; + +err_out: + return ret; +} + +static int bw_tx(SOCKET fd, int msg_sz, uint64_t *bw) +{ + struct pollfd pfd = { 0 }; + uint64_t start, end, diff; + int msgs_sent = 0; + int tx_sz; + int sent; + int ret; + + if (opt_poll) { + pfd.fd = fd; + pfd.events = POLLOUT; + } + + tx_sz = msg_sz ? msg_sz : ARRAY_SIZE(buf); + + DBG("bw_tx: msg_sz=%d tx_sz=%d \n", msg_sz, tx_sz); + + start = time_ns(); + end = time_ns(); + + while (end < start + BM_BW_TIME) { + sent = 0; + while (sent < tx_sz) { + ret = send(fd, buf + sent, tx_sz - sent, 0); + if (ret == SOCKET_ERROR) { + if (opt_poll && poll_check()) { + pfd.revents = 0; + poll(&pfd, 1, -1); /* XXX no error checking */ + continue; + } + sockerr("send()"); + ret = -1; + goto err_out; + } + sent += ret; + TRC("Sent: %d %d\n", sent, ret); + } + msgs_sent++; + if (!(msgs_sent % 1000)) + end = time_ns(); + } + DBG("bw_tx: %d %"PRIu64" %"PRIu64"\n", msgs_sent, start, end); + + /* Bandwidth in Mbits per second */ + diff = end - start; + diff /= 1000 * 1000; /* Time in milliseconds */ + *bw = (8ULL * msgs_sent * msg_sz * 1000) / (diff * 1024 * 1024); + ret = 0; + +err_out: + return ret; +} + +/* + * Main server and client entry points + */ +static int server(int bm, int msg_sz) +{ + SOCKET lsock, csock; + SOCKADDR_VM savm, sacvm; + SOCKADDR_HV sahv, sachv; + socklen_t socklen; + int max_conn; + int ret = 0; + + INFO("server: bm=%d msg_sz=%d\n", bm, msg_sz); + + if (opt_vsock) + lsock = socket(AF_VSOCK, SOCK_STREAM, 0); + else + lsock = socket(AF_HYPERV, SOCK_STREAM, HV_PROTOCOL_RAW); + if (lsock == INVALID_SOCKET) { + sockerr("socket()"); + return 1; + } + + memset(&savm, 0, sizeof(savm)); + savm.Family = AF_VSOCK; + savm.SvmCID = VMADDR_CID_ANY; + savm.SvmPort = BM_PORT; + + memset(&sahv, 0, sizeof(sahv)); + sahv.Family = AF_HYPERV; + sahv.VmId = HV_GUID_WILDCARD; + sahv.ServiceId = BM_GUID; + + if (opt_vsock) + ret = bind(lsock, (const struct sockaddr *)&savm, sizeof(savm)); + else + ret = bind(lsock, (const struct sockaddr *)&sahv, sizeof(sahv)); + if (ret == SOCKET_ERROR) { + sockerr("bind()"); + closesocket(lsock); + return 1; + } + + ret = listen(lsock, SOMAXCONN); + if (ret == SOCKET_ERROR) { + sockerr("listen()"); + goto err_out; + } + + INFO("server: listening\n"); + + if (bm == BM_CONN) + max_conn = BM_CONNS; + else + max_conn = 1; + + while (max_conn) { + max_conn--; + + memset(&sacvm, 0, sizeof(sacvm)); + memset(&sachv, 0, sizeof(sachv)); + if (opt_vsock) { + socklen = sizeof(sacvm); + csock = accept(lsock, (struct sockaddr *)&sacvm, &socklen); + } else { + socklen = sizeof(sachv); + csock = accept(lsock, (struct sockaddr *)&sachv, &socklen); + } + if (csock == INVALID_SOCKET) { + sockerr("accept()"); + ret = -1; + continue; + } + + INFO("server: accepted\n"); + + /* Switch to non-blocking if we want to poll */ + if (opt_poll) + poll_enable(csock); + + ret = bw_rx(csock, msg_sz); + + closesocket(csock); + } + +err_out: + closesocket(lsock); + return ret; +} + +static int client(GUID target_guid, unsigned int target_cid, + int bm, int msg_sz) +{ + SOCKET fd; + SOCKADDR_VM savm; + SOCKADDR_HV sahv; + uint64_t res; + int ret = 0; + + INFO("client: bm=%d msg_sz=%d\n", bm, msg_sz); + + if (opt_vsock) + fd = socket(AF_VSOCK, SOCK_STREAM, 0); + else + fd = socket(AF_HYPERV, SOCK_STREAM, HV_PROTOCOL_RAW); + if (fd == INVALID_SOCKET) { + sockerr("socket()"); + return 1; + } + + memset(&sahv, 0, sizeof(sahv)); + savm.Family = AF_VSOCK; + savm.SvmCID = target_cid; + savm.SvmPort = BM_PORT; + + memset(&sahv, 0, sizeof(sahv)); + sahv.Family = AF_HYPERV; + sahv.VmId = target_guid; + sahv.ServiceId = BM_GUID; + + if (opt_vsock) + ret = connect(fd, (const struct sockaddr *)&savm, sizeof(savm)); + else + ret = connect(fd, (const struct sockaddr *)&sahv, sizeof(sahv)); + if (ret == SOCKET_ERROR) { + sockerr("connect()"); + ret = -1; + goto err_out; + } + + INFO("client: connected\n"); + + /* Switch to non-blocking if we want to poll */ + if (opt_poll) + poll_enable(fd); + + if (bm == BM_BW_UNI) { + ret = bw_tx(fd, msg_sz, &res); + if (ret) + goto err_out; + printf("%d %"PRIu64"\n", msg_sz, res); + } else { + fprintf(stderr, "Unknown benchmark %d\n", bm); + ret = -1; + } + +err_out: + closesocket(fd); + return ret; +} + +/* Different client for connection tests */ +#define BM_CONN_TIMEOUT 500 /* 500ms */ +static int client_conn(GUID target_guid, unsigned int target_cid) +{ + uint64_t start, end, diff; + int histogram[3 * 9 + 3]; + SOCKADDR_VM savm; + SOCKADDR_HV sahv; + SOCKET fd; + int sum; + int ret; + int i; + + memset(histogram, 0, sizeof(histogram)); + + INFO("client: connection test\n"); + + for (i = 0; i < BM_CONNS; i++) { + if (opt_vsock) + fd = socket(AF_VSOCK, SOCK_STREAM, 0); + else + fd = socket(AF_HYPERV, SOCK_STREAM, HV_PROTOCOL_RAW); + if (fd == INVALID_SOCKET) { + histogram[ARRAY_SIZE(histogram) - 1] += 1; + DBG("conn: %d -> socket error\n", i); + continue; + } + + memset(&sahv, 0, sizeof(sahv)); + savm.Family = AF_VSOCK; + savm.SvmCID = target_cid; + savm.SvmPort = BM_PORT; + + memset(&sahv, 0, sizeof(sahv)); + sahv.Family = AF_HYPERV; + sahv.VmId = target_guid; + sahv.ServiceId = BM_GUID; + + start = time_ns(); + + if (opt_poll) + if (opt_vsock) + ret = connect_ex(fd, (const struct sockaddr *)&savm, sizeof(savm), + BM_CONN_TIMEOUT); + else + ret = connect_ex(fd, (const struct sockaddr *)&sahv, sizeof(sahv), + BM_CONN_TIMEOUT); + else + if (opt_vsock) + ret = connect(fd, (const struct sockaddr *)&savm, sizeof(savm)); + else + ret = connect(fd, (const struct sockaddr *)&sahv, sizeof(sahv)); + + if (ret == SOCKET_ERROR) { + histogram[ARRAY_SIZE(histogram) - 2] += 1; + DBG("conn: %d -> connect error\n", i); + } else { + end = time_ns(); + diff = (end - start); + DBG("conn: %d -> %"PRIu64"ns\n", i, diff); + + diff /= (1000 * 1000); + if (diff < 10) + histogram[diff] += 1; + else if (diff < 100) + histogram[9 + diff / 10] += 1; + else if (diff < 1000) + histogram[18 + diff / 100] += 1; + else + histogram[ARRAY_SIZE(histogram) - 3] += 1; + } + + closesocket(fd); + } + + /* Print the results */ + printf("# time (ms) vs count vs cumulative percent\n"); + sum = 0; + for (i = 0; i < ARRAY_SIZE(histogram); i++) { + sum += histogram[i]; + if (i < 9) + printf("%d %d %6.2f\n", i + 1, histogram[i], + sum * 100.0 / BM_CONNS); + else if (i < 18) + printf("%d %d %6.2f\n", (i - 9 + 1) * 10, histogram[i], + sum * 100.0 / BM_CONNS); + else if (i < 27) + printf("%d %d %6.2f\n", (i - 18 + 1) * 100, histogram[i], + sum * 100.0 / BM_CONNS); + else if (i == ARRAY_SIZE(histogram) - 3) + printf(">=%d %d %6.2f\n", (i - 27 + 1) * 1000, histogram[i], + sum * 100.0 / BM_CONNS); + else if (i == ARRAY_SIZE(histogram) - 2) + printf("connect_err %d %6.2f\n", histogram[i], + sum * 100.0 / BM_CONNS); + else + printf("socket_err %d %6.2f\n", histogram[i], + sum * 100.0 / BM_CONNS); + } + + return 0; +} + +void usage(char *name) +{ + printf("%s: -s|-c -b|-l -m [-v]\n", name); + printf(" -s Server mode\n"); + printf(" -c Client mode. :\n"); + printf(" 'loopback': Connect in loopback mode\n"); + printf(" 'parent': Connect to the parent partition\n"); + printf(" : Connect to VM with GUID\n"); + printf("\n"); + printf(" -B Bandwidth test\n"); + printf(" -L Latency test\n"); + printf(" -C Connection test\n"); + printf("\n"); + printf(" -vsock Use vsock (Linux only)\n"); + printf(" -m Message size in bytes\n"); + printf(" -p Use poll instead of blocking send()/recv()\n"); + printf(" -v Verbose output\n"); +} + +int __cdecl main(int argc, char **argv) +{ + int opt_server = 0; + int opt_bm = 0; + int opt_msgsz = 0; + GUID target_guid; + unsigned int target_cid; + char *target_str = NULL; + int res = 0; + int i; + +#ifdef _MSC_VER + /* Initialize Winsock */ + res = WSAStartup(MAKEWORD(2,2), &wsaData); + if (res != 0) { + fprintf(stderr, "WSAStartup() failed with error: %d\n", res); + return 1; + } +#endif + + /* No getopt on windows. Do some manual parsing */ + for (i = 1; i < argc; i++) { + if (strcmp(argv[i], "-s") == 0) { + opt_server = 1; + } else if (strcmp(argv[i], "-c") == 0) { + opt_server = 0; + if (i + 1 >= argc) { + fprintf(stderr, "-c requires an argument\n"); + usage(argv[0]); + goto out; + } + if (strcmp(argv[i + 1], "loopback") == 0) { + target_guid = HV_GUID_LOOPBACK; + target_cid = VMADDR_CID_HYPERVISOR; + } else if (strcmp(argv[i + 1], "parent") == 0) { + target_guid = HV_GUID_PARENT; + target_cid = VMADDR_CID_HOST; + } else { + target_str = argv[i + 1]; + } + i++; + + } else if (strcmp(argv[i], "-B") == 0) { + opt_bm = BM_BW_UNI; + } else if (strcmp(argv[i], "-L") == 0) { + opt_bm = BM_LAT; + } else if (strcmp(argv[i], "-C") == 0) { + opt_bm = BM_CONN; + + } else if (strcmp(argv[i], "-vsock") == 0) { + opt_vsock = 1; + } else if (strcmp(argv[i], "-m") == 0) { + if (i + 1 >= argc) { + fprintf(stderr, "-m requires an argument\n"); + usage(argv[0]); + goto out; + } + opt_msgsz = atoi(argv[++i]); + } else if (strcmp(argv[i], "-p") == 0) { + opt_poll = 1; + } else if (strcmp(argv[i], "-v") == 0) { + verbose++; + } else { + usage(argv[0]); + goto out; + } + } + +#ifdef _MSC_VER + if (opt_vsock) { + fprintf(stderr, "-vsock is not valid on Windows\n"); + goto out; + } +#endif + + if (target_str) { + if (opt_vsock) { + target_cid = strtoul(target_str, NULL, 0); + } else { + res = parseguid(target_str, &target_guid); + if (res != 0) { + fprintf(stderr, "failed to scan: %s\n", target_str); + goto out; + } + } + } + + if (!opt_bm) { + fprintf(stderr, "You need to specify a test\n"); + goto out; + } + if (opt_bm == BM_LAT) { + fprintf(stderr, "Latency tests currently not implemented\n"); + goto out; + } + + if (opt_server) { + res = server(opt_bm, opt_msgsz); + } else { + if (opt_bm == BM_CONN) + res = client_conn(target_guid, target_cid); + else + res = client(target_guid, target_cid, opt_bm, opt_msgsz); + } + +out: +#ifdef _MSC_VER + WSACleanup(); +#endif + return res; +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/linuxkit/virtsock/c/hvecho.c b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/linuxkit/virtsock/c/hvecho.c new file mode 100644 index 0000000000..869d3a2921 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/linuxkit/virtsock/c/hvecho.c @@ -0,0 +1,331 @@ +/* + * A simple Echo server and client using Hyper-V sockets + * + * Works on Linux and Windows (kinda) + * + * This was primarily written to checkout shutdown(), which turns out + * does not work. + */ +#include "compat.h" + +#include +#include +#include + +/* 3049197C-FACB-11E6-BD58-64006A7986D3 */ +DEFINE_GUID(SERVICE_GUID, + 0x3049197c, 0xfacb, 0x11e6, 0xbd, 0x58, 0x64, 0x00, 0x6a, 0x79, 0x86, 0xd3); +#define SERVICE_PORT 0x3049197c + +#define MY_BUFLEN 4096 + +#ifdef _MSC_VER +static WSADATA wsaData; +#endif + +/* Use the vsock interface on Linux */ +static int opt_vsock; + + +/* Handle a connection. Echo back anything sent to us and when the + * connection is closed send a bye message. + */ +static void handle(SOCKET fd) +{ + char recvbuf[MY_BUFLEN]; + int recvbuflen = MY_BUFLEN; + const char *byebuf = "Bye!"; + int sent; + int res; + + do { + res = recv(fd, recvbuf, recvbuflen, 0); + if (res == 0) { + printf("Peer closed\n"); + break; + } else if (res == SOCKET_ERROR) { + sockerr("recv()"); + return; + } + + /* No error, echo */ + printf("Bytes received: %d\n", res); + sent = send(fd, recvbuf, res, 0); + if (sent == SOCKET_ERROR) { + sockerr("send()"); + return; + } + printf("Bytes sent: %d\n", sent); + + } while (res > 0); + + /* Send bye */ + sent = send(fd, byebuf, sizeof(byebuf), 0); + if (sent == SOCKET_ERROR) { + sockerr("send() bye"); + return; + } + printf("Bye Bytes sent: %d\n", sent); +} + + +/* Server: + * accept() in an endless loop, handle a connection at a time + */ +static int server(void) +{ + SOCKET lsock, csock; + SOCKADDR_VM savm, sacvm; + SOCKADDR_HV sahv, sachv; + socklen_t socklen; + int res; + + if (opt_vsock) + lsock = socket(AF_VSOCK, SOCK_STREAM, 0); + else + lsock = socket(AF_HYPERV, SOCK_STREAM, HV_PROTOCOL_RAW); + if (lsock == INVALID_SOCKET) { + sockerr("socket()"); + return 1; + } + + memset(&savm, 0, sizeof(savm)); + savm.Family = AF_VSOCK; + savm.SvmCID = VMADDR_CID_ANY; + savm.SvmPort = SERVICE_PORT; + + memset(&sahv, 0, sizeof(sahv)); + sahv.Family = AF_HYPERV; + sahv.VmId = HV_GUID_WILDCARD; + sahv.ServiceId = SERVICE_GUID; + + if (opt_vsock) + res = bind(lsock, (const struct sockaddr *)&savm, sizeof(savm)); + else + res = bind(lsock, (const struct sockaddr *)&sahv, sizeof(sahv)); + if (res == SOCKET_ERROR) { + sockerr("bind()"); + closesocket(lsock); + return 1; + } + + res = listen(lsock, SOMAXCONN); + if (res == SOCKET_ERROR) { + sockerr("listen()"); + closesocket(lsock); + return 1; + } + + while(1) { + memset(&sacvm, 0, sizeof(sacvm)); + memset(&sachv, 0, sizeof(sachv)); + if (opt_vsock) { + socklen = sizeof(sacvm); + csock = accept(lsock, (struct sockaddr *)&sacvm, &socklen); + } else { + socklen = sizeof(sachv); + csock = accept(lsock, (struct sockaddr *)&sachv, &socklen); + } + if (csock == INVALID_SOCKET) { + sockerr("accept()"); + closesocket(lsock); + return 1; + } + + if (opt_vsock) + printf("Connect from: 0x%08x.0x%08x\n", sacvm.SvmCID, sacvm.SvmPort); + else + printf("Connect from: "GUID_FMT":"GUID_FMT"\n", + GUID_ARGS(sachv.VmId), GUID_ARGS(sachv.ServiceId)); + + handle(csock); + closesocket(csock); + } +} + + +/* The client sends a messages, and waits for the echo before shutting + * down the send side. It then expects a bye message from the server. + */ +static int client(GUID target_guid, unsigned int target_cid) +{ + SOCKET fd = INVALID_SOCKET; + SOCKADDR_VM savm; + SOCKADDR_HV sahv; + char *sendbuf = "this is a test"; + char recvbuf[MY_BUFLEN]; + int recvbuflen = MY_BUFLEN; + int res; + + if (opt_vsock) + fd = socket(AF_VSOCK, SOCK_STREAM, 0); + else + fd = socket(AF_HYPERV, SOCK_STREAM, HV_PROTOCOL_RAW); + if (fd == INVALID_SOCKET) { + sockerr("socket()"); + return 1; + } + + memset(&sahv, 0, sizeof(sahv)); + savm.Family = AF_VSOCK; + savm.SvmCID = target_cid; + savm.SvmPort = SERVICE_PORT; + + memset(&sahv, 0, sizeof(sahv)); + sahv.Family = AF_HYPERV; + sahv.VmId = target_guid; + sahv.ServiceId = SERVICE_GUID; + + if (opt_vsock) { + printf("Connect to: 0x%08x.0x%08x\n", savm.SvmCID, savm.SvmPort); + res = connect(fd, (const struct sockaddr *)&savm, sizeof(savm)); + } else { + printf("Connect to: "GUID_FMT":"GUID_FMT"\n", + GUID_ARGS(sahv.VmId), GUID_ARGS(sahv.ServiceId)); + res = connect(fd, (const struct sockaddr *)&sahv, sizeof(sahv)); + } + if (res == SOCKET_ERROR) { + sockerr("connect()"); + goto out; + } + + res = send(fd, sendbuf, (int)strlen(sendbuf), 0); + if (res == SOCKET_ERROR) { + sockerr("send()"); + goto out; + } + + printf("Bytes Sent: %d\n", res); + + res = recv(fd, recvbuf, recvbuflen, 0); + if (res < 0) { + sockerr("recv()"); + goto out; + } else if (res == 0) { + printf("Connection closed\n"); + res = 1; + goto out; + } + + printf("Bytes received: %d\n", res); + printf("->%s\n", recvbuf); + printf("Shutdown\n"); + + /* XXX shutdown does not work! */ + res = shutdown(fd, SD_SEND); + if (res == SOCKET_ERROR) { + sockerr("shutdown()"); + goto out; + } + + printf("Wait for bye\n"); + res = recv(fd, recvbuf, recvbuflen, 0); + if (res < 0) { + sockerr("recv()"); + goto out; + } else if (res == 0) { + printf("Connection closed\n"); + res = 1; + goto out; + } + + printf("Bytes received: %d\n", res); + recvbuf[res] = '\0'; + printf("->%s\n", recvbuf); + res = 0; + + out: + closesocket(fd); + return res; +} + +void usage(char *name) +{ + printf("%s: -s | -c [-vsock]\n", name); + printf(" -s Server mode\n"); + printf(" -c Client mode. :\n"); + printf(" 'loopback': Connect in loopback mode\n"); + printf(" 'parent': Connect to the parent partition\n"); + printf(" : Connect to VM with GUID\n"); + printf(" -vsock Use AF_VSOCK (Linux only)\n"); +} + +int __cdecl main(int argc, char **argv) +{ + int opt_server; + int res = 0; + GUID target_guid; + unsigned int target_cid; + char *target_str = NULL; + int i; + +#ifdef _MSC_VER + // Initialize Winsock + res = WSAStartup(MAKEWORD(2,2), &wsaData); + if (res != 0) { + fprintf(stderr, "WSAStartup() failed with error: %d\n", res); + return 1; + } +#endif + + /* No getopt on windows. Do some manual parsing */ + for (i = 1; i < argc; i++) { + if (strcmp(argv[i], "-s") == 0) { + opt_server = 1; + } else if (strcmp(argv[i], "-c") == 0) { + opt_server = 0; + if (i + 1 >= argc) { + fprintf(stderr, "-c requires an argument\n"); + usage(argv[0]); + goto out; + } + if (strcmp(argv[i + 1], "loopback") == 0) { + target_guid = HV_GUID_LOOPBACK; + target_cid = VMADDR_CID_HYPERVISOR; + } else if (strcmp(argv[i + 1], "parent") == 0) { + target_guid = HV_GUID_PARENT; + target_cid = VMADDR_CID_HOST; + } else { + target_str = argv[i + 1]; + } + i++; + + } else if (strcmp(argv[i], "-vsock") == 0) { + opt_vsock = 1; + } else { + fprintf(stderr, "Unknown argument: %s\n", argv[i]); + usage(argv[0]); + goto out; + } + } + +#ifdef _MSC_VER + if (opt_vsock) { + fprintf(stderr, "-vsock is not valid on Windows\n"); + goto out; + } +#endif + + if (target_str) { + if (opt_vsock) { + target_cid = strtoul(target_str, NULL, 0); + } else { + res = parseguid(target_str, &target_guid); + if (res != 0) { + fprintf(stderr, "failed to scan: %s\n", target_str); + goto out; + } + } + } + + if (opt_server) + res = server(); + else + res = client(target_guid, target_cid); + +out: +#ifdef _MSC_VER + WSACleanup(); +#endif + return res; +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/linuxkit/virtsock/c/hvstress.c b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/linuxkit/virtsock/c/hvstress.c new file mode 100644 index 0000000000..f9b1698a16 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/linuxkit/virtsock/c/hvstress.c @@ -0,0 +1,607 @@ +/* + * A simple Hyper-V sockets stress test. + * + * This program uses a configurable number of client threads which all + * open a connection to a server and then transfer a random amount of + * data to the server which echos the data back. + * + * The send()/recv() calls optionally alternate between RXTX_BUF_LEN + * and RXTX_SMALL_LEN worth of data to add more variability in the + * interaction. + */ +#include "compat.h" + +#include +#include +#include + +/* 3049197C-FACB-11E6-BD58-64006A7986D3 */ +DEFINE_GUID(SERVICE_GUID, + 0x3049197c, 0xfacb, 0x11e6, 0xbd, 0x58, 0x64, 0x00, 0x6a, 0x79, 0x86, 0xd3); +#define SERVICE_PORT 0x3049197c + +/* Maximum amount of data for a single send()/recv() call. + * Note: On Windows the maximum length seems to be 8KB and if larger + * buffers are passed to send() the connection will be close. We could + * use getsockopt(SO_MAX_MSG_SIZE) */ +#define RXTX_BUF_LEN (4 * 1024) +/* Small send()/recv() lengths */ +#define RXTX_SMALL_LEN 4 +/* Default number of connections made by the client */ +#define DEFAULT_CLIENT_CONN 100 + +/* Maximum amount of data to send per connection */ +static int opt_max_len = 20 * 1024 * 1024; +/* Global flag to alternate between short and long send()/recv() buffers */ +static int opt_alternate; + /* Use the vsock interface on Linux */ +static int opt_vsock; + +static int verbose; +#define INFO(...) \ + do { \ + if (verbose) { \ + printf(__VA_ARGS__); \ + fflush(stdout); \ + } \ + } while (0) +#define DBG(...) \ + do { \ + if (verbose > 1) { \ + printf(__VA_ARGS__); \ + fflush(stdout); \ + } \ + } while (0) +#define TRC(...) \ + do { \ + if (verbose > 2) { \ + printf(__VA_ARGS__); \ + fflush(stdout); \ + } \ + } while (0) + +#ifdef _MSC_VER +static WSADATA wsaData; +#endif + +static unsigned char sendbuf[RXTX_BUF_LEN]; + +/* A simple hexdump */ +static void dump(int id, int conn, const unsigned char *b, int len) +{ + int i, c; + + for (i = 0; i < (len + 16 - 1 - (len - 1) % 16); i += 16) { + printf("[%02d:%05d] %04x: ", id, conn, i); + for (c = i; c < i + 8; c++) + if ( c < len) + printf("%02x ", b[c]); + printf(" "); + for (c = i + 8; c < i + 16; c++) + if ( c < len) + printf("%02x ", b[c]); + printf("\n"); + } + fflush(stdout); +} + +/* Server code + * + * The server accepts a new connection and spins of a new thread to + * handle it. The thread simply echos back the data. We use a thread + * per connection because it's simpler code, but ideally we should be + * using a pool of worker threads. + */ + +/* Arguments to the server thread */ +struct svr_args { + SOCKET fd; + int conn; +}; + +/* Thread entry point for a server */ +static void *handle(void *a) +{ + struct svr_args *args = a; + uint64_t start, end, diff; + char recvbuf[RXTX_BUF_LEN]; + int total_bytes = 0; + int rxlen = RXTX_SMALL_LEN; + int received; + int sent; + int res; + + TRC("[%05d] server: handle fd=%d\n", args->conn, (int)args->fd); + + start = time_ns(); + + for (;;) { + if (opt_alternate) + rxlen = (rxlen == RXTX_SMALL_LEN) ? RXTX_BUF_LEN : RXTX_SMALL_LEN; + else + rxlen = RXTX_BUF_LEN; + received = recv(args->fd, recvbuf, rxlen, 0); + if (received == 0) { + DBG("[%05d] Peer closed\n", args->conn); + break; + } else if (received == SOCKET_ERROR) { + sockerr("recv()"); + goto out; + } + TRC("[%05d] server: fd=%d RX %d bytes\n", + args->conn, (int)args->fd, received); + + sent = 0; + while (sent < received) { + res = send(args->fd, recvbuf + sent, received - sent, 0); + if (res == SOCKET_ERROR) { + sockerr("send()"); + goto out; + } + sent += res; + TRC("[%05d] server: fd=%d TX %d bytes\n", + args->conn, (int)args->fd, res); + } + total_bytes += sent; + } + + end = time_ns(); + +out: + diff = end - start; + diff /= 1000 * 1000; + INFO("[%05d] ECHOED: %9d Bytes in %5"PRIu64"ms\n", + args->conn, total_bytes, diff); + TRC("close(%d)\n", (int)args->fd); + closesocket(args->fd); + free(args); + return NULL; +} + + +/* Server entry point */ +static int server(int multi_threaded, int max_conn) +{ + SOCKET lsock, csock; + SOCKADDR_VM savm, sacvm; + SOCKADDR_HV sahv, sachv; + socklen_t socklen; + struct svr_args *args; + THREAD_HANDLE st; + int conn = 0; + int res; + + if (opt_vsock) + lsock = socket(AF_VSOCK, SOCK_STREAM, 0); + else + lsock = socket(AF_HYPERV, SOCK_STREAM, HV_PROTOCOL_RAW); + if (lsock == INVALID_SOCKET) { + sockerr("socket()"); + return 1; + } + + memset(&savm, 0, sizeof(savm)); + savm.Family = AF_VSOCK; + savm.SvmCID = VMADDR_CID_ANY; + savm.SvmPort = SERVICE_PORT; + + memset(&sahv, 0, sizeof(sahv)); + sahv.Family = AF_HYPERV; + sahv.VmId = HV_GUID_WILDCARD; + sahv.ServiceId = SERVICE_GUID; + + if (opt_vsock) + res = bind(lsock, (const struct sockaddr *)&savm, sizeof(savm)); + else + res = bind(lsock, (const struct sockaddr *)&sahv, sizeof(sahv)); + if (res == SOCKET_ERROR) { + sockerr("bind()"); + closesocket(lsock); + return 1; + } + + res = listen(lsock, SOMAXCONN); + if (res == SOCKET_ERROR) { + sockerr("listen()"); + closesocket(lsock); + return 1; + } + + while(1) { + memset(&sacvm, 0, sizeof(sacvm)); + memset(&sachv, 0, sizeof(sachv)); + if (opt_vsock) { + socklen = sizeof(sacvm); + csock = accept(lsock, (struct sockaddr *)&sacvm, &socklen); + } else { + socklen = sizeof(sachv); + csock = accept(lsock, (struct sockaddr *)&sachv, &socklen); + } + if (csock == INVALID_SOCKET) { + sockerr("accept()"); + closesocket(lsock); + return 1; + } + + if (opt_vsock) + DBG("Connect from: 0x%08x.0x%08x\n", sacvm.SvmCID, sacvm.SvmPort); + else + DBG("Connect from: "GUID_FMT":"GUID_FMT"\n", + GUID_ARGS(sachv.VmId), GUID_ARGS(sachv.ServiceId)); + + + /* Spin up a new thread per connection. Not the most + * efficient, but stops us from having to faff about with + * worker threads and the like. */ + args = malloc(sizeof(*args)); + if (!args) { + fprintf(stderr, "failed to malloc thread state\n"); + return 1; + } + args->fd = csock; + args->conn = conn++; + if (multi_threaded) { + thread_create(&st, &handle, args); + thread_detach(st); + } else { + handle(args); + } + + /* Note, since we are not waiting for thread to finish, this may + * cause the last n connections not being handled properly. */ + if (conn >= max_conn) + break; + } + + closesocket(lsock); + return 0; +} + + +/* Client code + * + * The client sends one message of random size and expects the server + * to echo it back. The sending is done in a separate thread so we can + * simultaneously drain the server's replies. Could do this in a + * single thread with poll()/select() as well, but this keeps the code + * simpler. + */ + +/* Arguments for client threads */ +struct client_args { + THREAD_HANDLE h; + GUID target_guid; + unsigned int target_cid; + int id; + int conns; + int rand; + + int res; +}; + +/* Argument passed to Client send thread */ +struct client_tx_args { + SOCKET fd; + int tosend; + int id; + int conn; +}; + +static void *client_tx(void *a) +{ + struct client_tx_args *args = a; + char tmp[128]; + int tosend, txlen = RXTX_SMALL_LEN; + int res; + + tosend = args->tosend; + while (tosend) { + if (opt_alternate) + txlen = (txlen == RXTX_SMALL_LEN) ? RXTX_BUF_LEN : RXTX_SMALL_LEN; + else + txlen = RXTX_BUF_LEN; + txlen = (tosend > txlen) ? txlen : tosend; + + res = send(args->fd, sendbuf, txlen, 0); + if (res == SOCKET_ERROR) { + snprintf(tmp, sizeof(tmp), "[%02d:%05d] send() after %d bytes", + args->id, args->conn, args->tosend - tosend); + sockerr(tmp); + goto out; + } + TRC("[%02d:%05d] client: TX %d bytes\n", args->id, args->conn, res); + tosend -= res; + } + DBG("[%02d:%05d] TX: %9d bytes sent\n", args->id, args->conn, args->tosend); + +out: + return NULL; +} + +/* Client code for a single connection */ +static int client_one(GUID target_guid, unsigned int target_cid, + int id, int conn) +{ + struct client_tx_args args; + uint64_t start, end, diff; + THREAD_HANDLE st; + SOCKADDR_VM savm; + SOCKADDR_HV sahv; + SOCKET fd; + unsigned char recvbuf[RXTX_BUF_LEN]; + int rxlen = RXTX_SMALL_LEN; + char tmp[128]; + int tosend, received = 0; + int res; + + TRC("[%02d:%05d] start\n", id, conn); + + start = time_ns(); + + if (opt_vsock) + fd = socket(AF_VSOCK, SOCK_STREAM, 0); + else + fd = socket(AF_HYPERV, SOCK_STREAM, HV_PROTOCOL_RAW); + if (fd == INVALID_SOCKET) { + sockerr("socket()"); + return 1; + } + + if (opt_vsock) { + savm.Family = AF_VSOCK; + savm.SvmCID = target_cid; + savm.SvmPort = SERVICE_PORT; + DBG("[%02d:%05d] Connected to: 0x%08x.0x%08x fd=%d\n", + id, conn, savm.SvmCID, savm.SvmPort, (int)fd); + res = connect(fd, (const struct sockaddr *)&savm, sizeof(savm)); + } else { + sahv.Family = AF_HYPERV; + sahv.Reserved = 0; + sahv.VmId = target_guid; + sahv.ServiceId = SERVICE_GUID; + DBG("[%02d:%05d] Connected to: "GUID_FMT":"GUID_FMT" fd=%d\n", + id, conn, GUID_ARGS(sahv.VmId), GUID_ARGS(sahv.ServiceId), (int)fd); + res = connect(fd, (const struct sockaddr *)&sahv, sizeof(sahv)); + } + if (res == SOCKET_ERROR) { + sockerr("connect()"); + goto out; + } + + if (RAND_MAX < opt_max_len) + tosend = (int)((1ULL * RAND_MAX + 1) * rand() + rand()); + else + tosend = rand(); + + tosend = tosend % (opt_max_len - 1) + 1; + + DBG("[%02d:%05d] TOSEND: %d bytes\n", id, conn, tosend); + args.fd = fd; + args.tosend = tosend; + args.id = id; + args.conn = conn; + thread_create(&st, &client_tx, &args); + + while (received < tosend) { + if (opt_alternate) + rxlen = (rxlen == RXTX_SMALL_LEN) ? RXTX_BUF_LEN : RXTX_SMALL_LEN; + else + rxlen = RXTX_BUF_LEN; + res = recv(fd, recvbuf, rxlen, 0); + if (res < 0) { + snprintf(tmp, sizeof(tmp), "[%02d:%05d] recv() after %d bytes", + id, conn, received); + sockerr(tmp); + goto thout; + } else if (res == 0) { + INFO("[%02d:%05d] Connection closed\n", id, conn); + res = 1; + goto thout; + } + TRC("[%02d:%05d] client: RX %d bytes\n", id, conn, res); + if (verbose > 3) + dump(id, conn, recvbuf, res); + received += res; + } + + res = 0; + +thout: + thread_join(st); + end = time_ns(); + diff = end - start; + diff /= 1000 * 1000; + INFO("[%02d:%05d] TX/RX: %9d bytes in %5"PRIu64"ms\n", + id, conn, received, diff); +out: + TRC("[%02d:%05d] close(%d)\n", id, conn, (int)fd); + closesocket(fd); + return res; +} + +static void *client_thd(void *a) +{ + struct client_args *args = a; + int res, i; + + if (args->rand) + srand(time(NULL) + args->id); + + for (i = 0; i < args->conns; i++) { + res = client_one(args->target_guid, args->target_cid, args->id, i); + if (res) + break; + } + + args->res = res; + return args; +} + +void usage(char *name) +{ + printf("%s: -s|-c [-i ]\n", name); + printf(" -s Server mode\n"); + printf(" -1 " + "Use a single thread (handle one connection at a time)\n"); + printf("\n"); + printf(" -c Client mode. :\n"); + printf(" 'loopback': Connect in loopback mode\n"); + printf(" 'parent': Connect to the parent partition\n"); + printf(" : Connect to VM with GUID\n"); + printf(" -p Run 'num' connections in parallel (default 1)\n"); + printf(" -m Maximum amount of data to send per connection\n"); + printf(" -r Initialise random number generator with the time\n"); + printf("\n"); + printf("Common options\n"); + printf(" -i Number connections the client makes (default %d)\n", + DEFAULT_CLIENT_CONN); + printf(" -vsock Use vsock (Linux only)\n"); + printf(" -a Alternate using short/long send()/recv() buffers\n"); + printf(" -v Verbose output (use multiple times)\n"); +} + +int __cdecl main(int argc, char **argv) +{ + struct client_args *args; + int opt_conns = DEFAULT_CLIENT_CONN; + int opt_multi_thds = 1; + int opt_server = 0; + int opt_rand = 0; + int opt_par = 1; + GUID target_guid; + unsigned int target_cid; + char *target_str = NULL; + int res = 0; + int i; + +#ifdef _MSC_VER + /* Initialize Winsock */ + res = WSAStartup(MAKEWORD(2,2), &wsaData); + if (res != 0) { + fprintf(stderr, "WSAStartup() failed with error: %d\n", res); + return 1; + } +#endif + + /* No getopt on windows. Do some manual parsing */ + for (i = 1; i < argc; i++) { + if (strcmp(argv[i], "-s") == 0) { + opt_server = 1; + } else if (strcmp(argv[i], "-c") == 0) { + opt_server = 0; + if (i + 1 >= argc) { + fprintf(stderr, "-c requires an argument\n"); + usage(argv[0]); + goto out; + } + if (strcmp(argv[i + 1], "loopback") == 0) { + target_guid = HV_GUID_LOOPBACK; + target_cid = VMADDR_CID_HYPERVISOR; + } else if (strcmp(argv[i + 1], "parent") == 0) { + target_guid = HV_GUID_PARENT; + target_cid = VMADDR_CID_HOST; + } else { + target_str = argv[i + 1]; + } + i++; + + } else if (strcmp(argv[i], "-i") == 0) { + if (i + 1 >= argc) { + fprintf(stderr, "-i requires an argument\n"); + usage(argv[0]); + goto out; + } + opt_conns = atoi(argv[++i]); + } else if (strcmp(argv[i], "-p") == 0) { + if (i + 1 >= argc) { + fprintf(stderr, "-p requires an argument\n"); + usage(argv[0]); + goto out; + } + opt_par = atoi(argv[++i]); + } else if (strcmp(argv[i], "-m") == 0) { + if (i + 1 >= argc) { + fprintf(stderr, "-p requires an argument\n"); + usage(argv[0]); + goto out; + } + opt_max_len = atoi(argv[++i]); + } else if (strcmp(argv[i], "-r") == 0) { + opt_rand = 1; + } else if (strcmp(argv[i], "-1") == 0) { + opt_multi_thds = 0; + } else if (strcmp(argv[i], "-vsock") == 0) { + opt_vsock = 1; + } else if (strcmp(argv[i], "-a") == 0) { + opt_alternate = 1; + } else if (strcmp(argv[i], "-v") == 0) { + verbose++; + } else { + usage(argv[0]); + goto out; + } + } + +#ifdef _MSC_VER + if (opt_vsock) { + fprintf(stderr, "-vsock is not valid on Windows\n"); + goto out; + } +#endif + + if (target_str) { + if (opt_vsock) { + target_cid = strtoul(target_str, NULL, 0); + } else { + res = parseguid(target_str, &target_guid); + if (res != 0) { + fprintf(stderr, "failed to scan: %s\n", target_str); + goto out; + } + } + } + + if (opt_server) { + server(opt_multi_thds, opt_conns); + } else { + /* Initialise the send buffer with a known pattern */ + for (i = 0; i < RXTX_BUF_LEN; i++) { + if ((i >> 8) % 2) + sendbuf[i] = i & 0xff; + else + sendbuf[i] = 0xff - (i & 0xff); + } + + args = calloc(opt_par, sizeof(*args)); + if (!args) { + fprintf(stderr, "failed to malloc"); + res = -1; + goto out; + } + + /* Create threads */ + for (i = 0; i < opt_par; i++) { + args[i].target_guid = target_guid; + args[i].target_cid = target_cid; + args[i].id = i; + args[i].conns = opt_conns / opt_par; + args[i].rand = opt_rand; + thread_create(&args[i].h, &client_thd, &args[i]); + } + + /* Wait for threads to finish and collect return codes */ + res = 0; + for (i = 0; i < opt_par; i++) { + thread_join(args[i].h); + if (args[i].res) + fprintf(stderr, "THREAD[%d] failed with %d\n", i, args[i].res); + res |= args[i].res; + } + } + +out: +#ifdef _MSC_VER + WSACleanup(); +#endif + return res; +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/linuxkit/virtsock/pkg/hvsock/hvsock.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/linuxkit/virtsock/pkg/hvsock/hvsock.go new file mode 100644 index 0000000000..f54ddda5f5 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/linuxkit/virtsock/pkg/hvsock/hvsock.go @@ -0,0 +1,115 @@ +// Package hvsock provides a Go interface to Hyper-V sockets both on +// Windows and on Linux. The Linux bindings require patches for the +// 4.9.x kernel. If you are using a Linux kernel 4.14.x or newer you +// should use the vsock package instead as the Hyper-V socket support +// in these kernels have been merged with the virtio sockets +// implementation. +package hvsock + +import ( + "encoding/binary" + "fmt" + "net" + "reflect" +) + +var ( + // GUIDZero used by listeners to accept connections from all partitions + GUIDZero, _ = GUIDFromString("00000000-0000-0000-0000-000000000000") + // GUIDWildcard used by listeners to accept connections from all partitions + GUIDWildcard, _ = GUIDFromString("00000000-0000-0000-0000-000000000000") + // GUIDBroadcast undocumented + GUIDBroadcast, _ = GUIDFromString("FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF") + // GUIDChildren used by listeners to accept connections from children + GUIDChildren, _ = GUIDFromString("90db8b89-0d35-4f79-8ce9-49ea0ac8b7cd") + // GUIDLoopback use to connect in loopback mode + GUIDLoopback, _ = GUIDFromString("e0e16197-dd56-4a10-9195-5ee7a155a838") + // GUIDParent use to connect to the parent partition + GUIDParent, _ = GUIDFromString("a42e7cda-d03f-480c-9cc2-a4de20abb878") + + // GUIDs for LinuxVMs with the new Hyper-V socket implementation need to match this template + guidTemplate, _ = GUIDFromString("00000000-facb-11e6-bd58-64006a7986d3") +) + +const ( + // The Hyper-V socket implementation used in the 4.9.x kernels + // seems to fail silently if messages are above 8k. The newer + // implementation in the 4.14.x (and newer) kernels seems to + // work fine with larger messages. This is constant is used as + // a temporary workaround to limit the amount of data sent and + // should be removed once support for 4.9.x kernels is + // deprecated. + maxMsgSize = 8 * 1024 +) + +// GUID is used by Hypper-V sockets for "addresses" and "ports" +type GUID [16]byte + +// Convert a GUID into a string +func (g *GUID) String() string { + /* XXX This assume little endian */ + return fmt.Sprintf("%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", + g[3], g[2], g[1], g[0], + g[5], g[4], + g[7], g[6], + g[8], g[9], + g[10], g[11], g[12], g[13], g[14], g[15]) +} + +// Port converts a Service GUID to a "port" usable by the vsock package. +// It can be used to convert hvsock code to vsock code. On 4.14.x +// kernels Service GUIDs for talking to Linux should have the form of +// xxxxxxxx-facb-11e6-bd58-64006a7986d3, where xxxxxxxx is the vsock port. +func (g *GUID) Port() (uint32, error) { + // Check that the GUID is as expected + if !reflect.DeepEqual(g[4:], guidTemplate[4:]) { + return 0, fmt.Errorf("%s does not conform with the template", g) + } + return binary.LittleEndian.Uint32(g[0:4]), nil +} + +// GUIDFromString parses a string and returns a GUID +func GUIDFromString(s string) (GUID, error) { + var g GUID + var err error + _, err = fmt.Sscanf(s, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", + &g[3], &g[2], &g[1], &g[0], + &g[5], &g[4], + &g[7], &g[6], + &g[8], &g[9], + &g[10], &g[11], &g[12], &g[13], &g[14], &g[15]) + return g, err +} + +// Addr represents a Hyper-V socket address +type Addr struct { + VMID GUID + ServiceID GUID +} + +// Network returns the type of network for Hyper-V sockets +func (a Addr) Network() string { + return "hvsock" +} + +func (a Addr) String() string { + vmid := a.VMID.String() + svc := a.ServiceID.String() + + return vmid + ":" + svc +} + +// Conn is a hvsock connection which supports half-close. +type Conn interface { + net.Conn + CloseRead() error + CloseWrite() error +} + +// Since there doesn't seem to be a standard min function +func min(x, y int) int { + if x < y { + return x + } + return y +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/linuxkit/virtsock/pkg/hvsock/hvsock_fallback.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/linuxkit/virtsock/pkg/hvsock/hvsock_fallback.go new file mode 100644 index 0000000000..050419bd36 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/linuxkit/virtsock/pkg/hvsock/hvsock_fallback.go @@ -0,0 +1,22 @@ +// +build !linux,!windows + +package hvsock + +import ( + "fmt" + "net" + "runtime" +) + +// Supported returns if hvsocks are supported on your platform +func Supported() bool { + return false +} + +func Dial(raddr Addr) (Conn, error) { + return nil, fmt.Errorf("Dial() not implemented on %s", runtime.GOOS) +} + +func Listen(addr Addr) (net.Listener, error) { + return nil, fmt.Errorf("Listen() not implemented on %s", runtime.GOOS) +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/linuxkit/virtsock/pkg/hvsock/hvsock_linux.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/linuxkit/virtsock/pkg/hvsock/hvsock_linux.go new file mode 100644 index 0000000000..8a9983eacc --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/linuxkit/virtsock/pkg/hvsock/hvsock_linux.go @@ -0,0 +1,262 @@ +package hvsock + +// On Linux we have to deal with two different implementations. The +// "legacy" implementation never made it into the kernel, but several +// kernels, including the LinuxKit one carried patches for it for +// quite a while. The legacy version defined a new address family +// while the new version sits on top of the existing VMware/virtio +// socket implementation. +// +// We try to determine at init if we are on a kernel with the legacy +// implementation or the new version and set "legacyMode" accordingly. +// +// We can't just reuse the vsock implementation as we still need to +// emulated CloseRead()/CloseWrite() as not all Windows builds support +// it. + +/* +#include + +struct sockaddr_hv { + unsigned short shv_family; + unsigned short reserved; + unsigned char shv_vm_id[16]; + unsigned char shv_service_id[16]; +}; +int bind_sockaddr_hv(int fd, const struct sockaddr_hv *sa_hv) { + return bind(fd, (const struct sockaddr*)sa_hv, sizeof(*sa_hv)); +} +int connect_sockaddr_hv(int fd, const struct sockaddr_hv *sa_hv) { + return connect(fd, (const struct sockaddr*)sa_hv, sizeof(*sa_hv)); +} +int accept_hv(int fd, struct sockaddr_hv *sa_hv, socklen_t *sa_hv_len) { + return accept4(fd, (struct sockaddr *)sa_hv, sa_hv_len, 0); +} +*/ +import "C" + +import ( + "fmt" + "net" + "os" + "syscall" + "time" + + "github.com/pkg/errors" + "golang.org/x/sys/unix" +) + +const ( + hvsockAF = 43 //SHV_PROTO_RAW + hvsockRaw = 1 // SHV_PROTO_RAW +) + +// Supported returns if hvsocks are supported on your platform +func Supported() bool { + // Try opening a hvsockAF socket. If it works we are on older, i.e. 4.9.x kernels. + // 4.11 defines AF_SMC as 43 but it doesn't support protocol 1 so the + // socket() call should fail. + fd, err := syscall.Socket(hvsockAF, syscall.SOCK_STREAM, hvsockRaw) + if err != nil { + return false + } + syscall.Close(fd) + return true +} + +// Dial a Hyper-V socket address +func Dial(raddr Addr) (Conn, error) { + fd, err := syscall.Socket(hvsockAF, syscall.SOCK_STREAM, hvsockRaw) + if err != nil { + return nil, err + } + + sa := C.struct_sockaddr_hv{} + sa.shv_family = hvsockAF + sa.reserved = 0 + + for i := 0; i < 16; i++ { + sa.shv_vm_id[i] = C.uchar(raddr.VMID[i]) + } + for i := 0; i < 16; i++ { + sa.shv_service_id[i] = C.uchar(raddr.ServiceID[i]) + } + + // Retry connect in a loop if EINTR is encountered. + for { + if ret, errno := C.connect_sockaddr_hv(C.int(fd), &sa); ret != 0 { + if errno == syscall.EINTR { + continue + } + return nil, fmt.Errorf("connect(%s) failed with %d, errno=%d", raddr, ret, errno) + } + break + } + + return newHVsockConn(uintptr(fd), &Addr{VMID: GUIDZero, ServiceID: GUIDZero}, &raddr), nil +} + +// Listen returns a net.Listener which can accept connections on the given port +func Listen(addr Addr) (net.Listener, error) { + fd, err := syscall.Socket(hvsockAF, syscall.SOCK_STREAM, hvsockRaw) + if err != nil { + return nil, err + } + + sa := C.struct_sockaddr_hv{} + sa.shv_family = hvsockAF + sa.reserved = 0 + + for i := 0; i < 16; i++ { + sa.shv_vm_id[i] = C.uchar(addr.VMID[i]) + } + for i := 0; i < 16; i++ { + sa.shv_service_id[i] = C.uchar(addr.ServiceID[i]) + } + + if ret, errno := C.bind_sockaddr_hv(C.int(fd), &sa); ret != 0 { + return nil, fmt.Errorf("listen(%s) failed with %d, errno=%d", addr, ret, errno) + } + + err = syscall.Listen(fd, syscall.SOMAXCONN) + if err != nil { + return nil, errors.Wrapf(err, "listen(%s) failed", addr) + } + return &hvsockListener{fd, addr}, nil +} + +// +// Hyper-v sockets Listener implementation +// + +type hvsockListener struct { + fd int + local Addr +} + +// Accept accepts an incoming call and returns the new connection. +func (v *hvsockListener) Accept() (net.Conn, error) { + var acceptSA C.struct_sockaddr_hv + var acceptSALen C.socklen_t + + acceptSALen = C.sizeof_struct_sockaddr_hv + fd, err := C.accept_hv(C.int(v.fd), &acceptSA, &acceptSALen) + if err != nil { + return nil, errors.Wrapf(err, "accept(%s) failed", v.local) + } + + remote := &Addr{VMID: guidFromC(acceptSA.shv_vm_id), ServiceID: guidFromC(acceptSA.shv_service_id)} + return newHVsockConn(uintptr(fd), &v.local, remote), nil +} + +// Close closes the listening connection +func (v *hvsockListener) Close() error { + // Note this won't cause the Accept to unblock. + return unix.Close(v.fd) +} + +// Addr returns the address the Listener is listening on +func (v *hvsockListener) Addr() net.Addr { + return v.local +} + +// +// Hyper-V socket connection implementation +// + +// hvsockConn represents a connection over a Hyper-V socket +type hvsockConn struct { + hvsock *os.File + fd uintptr + local *Addr + remote *Addr +} + +func newHVsockConn(fd uintptr, local, remote *Addr) *hvsockConn { + hvsock := os.NewFile(fd, fmt.Sprintf("hvsock:%d", fd)) + return &hvsockConn{hvsock: hvsock, fd: fd, local: local, remote: remote} +} + +// LocalAddr returns the local address of a connection +func (v *hvsockConn) LocalAddr() net.Addr { + return v.local +} + +// RemoteAddr returns the remote address of a connection +func (v *hvsockConn) RemoteAddr() net.Addr { + return v.remote +} + +// Close closes the connection +func (v *hvsockConn) Close() error { + return v.hvsock.Close() +} + +// CloseRead shuts down the reading side of a hvsock connection +func (v *hvsockConn) CloseRead() error { + return syscall.Shutdown(int(v.fd), syscall.SHUT_RD) +} + +// CloseWrite shuts down the writing side of a hvsock connection +func (v *hvsockConn) CloseWrite() error { + return syscall.Shutdown(int(v.fd), syscall.SHUT_WR) +} + +// Read reads data from the connection +func (v *hvsockConn) Read(buf []byte) (int, error) { + return v.hvsock.Read(buf) +} + +// Write writes data over the connection +// TODO(rn): replace with a straight call to v.hvsock.Write() once 4.9.x support is deprecated +func (v *hvsockConn) Write(buf []byte) (int, error) { + written := 0 + toWrite := len(buf) + for toWrite > 0 { + thisBatch := min(toWrite, maxMsgSize) + n, err := v.hvsock.Write(buf[written : written+thisBatch]) + if err != nil { + return written, err + } + if n != thisBatch { + return written, fmt.Errorf("short write %d != %d", n, thisBatch) + } + toWrite -= n + written += n + } + + return written, nil +} + +// SetDeadline sets the read and write deadlines associated with the connection +func (v *hvsockConn) SetDeadline(t time.Time) error { + return nil // FIXME +} + +// SetReadDeadline sets the deadline for future Read calls. +func (v *hvsockConn) SetReadDeadline(t time.Time) error { + return nil // FIXME +} + +// SetWriteDeadline sets the deadline for future Write calls +func (v *hvsockConn) SetWriteDeadline(t time.Time) error { + return nil // FIXME +} + +// File duplicates the underlying socket descriptor and returns it. +func (v *hvsockConn) File() (*os.File, error) { + // This is equivalent to dup(2) but creates the new fd with CLOEXEC already set. + r0, _, e1 := syscall.Syscall(syscall.SYS_FCNTL, uintptr(v.hvsock.Fd()), syscall.F_DUPFD_CLOEXEC, 0) + if e1 != 0 { + return nil, os.NewSyscallError("fcntl", e1) + } + return os.NewFile(r0, v.hvsock.Name()), nil +} + +func guidFromC(cg [16]C.uchar) GUID { + var g GUID + for i := 0; i < 16; i++ { + g[i] = byte(cg[i]) + } + return g +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/linuxkit/virtsock/pkg/hvsock/hvsock_windows.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/linuxkit/virtsock/pkg/hvsock/hvsock_windows.go new file mode 100644 index 0000000000..f21e9a3151 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/linuxkit/virtsock/pkg/hvsock/hvsock_windows.go @@ -0,0 +1,496 @@ +package hvsock + +import ( + "fmt" + "io" + "log" + "net" + "runtime" + "sync" + "sync/atomic" + "syscall" + "time" + "unsafe" + + "github.com/pkg/errors" +) + +// Make sure Winsock2 is initialised +func init() { + e := syscall.WSAStartup(uint32(0x202), &wsaData) + if e != nil { + log.Fatal("WSAStartup", e) + } +} + +const ( + hvsockAF = 34 // AF_HYPERV + hvsockRaw = 1 // SHV_PROTO_RAW +) + +var ( + // ErrTimeout is an error returned on timeout + ErrTimeout = &timeoutError{} + + wsaData syscall.WSAData +) + +// Supported returns if hvsocks are supported on your platform +func Supported() bool { + return true +} + +// Dial a Hyper-V socket address +func Dial(raddr Addr) (Conn, error) { + fd, err := syscall.Socket(hvsockAF, syscall.SOCK_STREAM, hvsockRaw) + if err != nil { + return nil, err + } + + var sa rawSockaddrHyperv + ptr, n, err := raddr.sockaddr(&sa) + if err != nil { + return nil, err + } + + if err := sys_connect(fd, ptr, n); err != nil { + return nil, errors.Wrapf(err, "connect(%s) failed", raddr) + } + + return newHVsockConn(fd, Addr{VMID: GUIDZero, ServiceID: GUIDZero}, raddr) +} + +// Listen returns a net.Listener which can accept connections on the given port +func Listen(addr Addr) (net.Listener, error) { + fd, err := syscall.Socket(hvsockAF, syscall.SOCK_STREAM, hvsockRaw) + if err != nil { + return nil, err + } + + var sa rawSockaddrHyperv + ptr, n, err := addr.sockaddr(&sa) + if err != nil { + return nil, err + } + if err := sys_bind(fd, ptr, n); err != nil { + return nil, fmt.Errorf("bind(%s) failed with %v", addr, err) + } + + err = syscall.Listen(fd, syscall.SOMAXCONN) + if err != nil { + return nil, errors.Wrapf(err, "listen(%s) failed", addr) + } + + return &hvsockListener{fd, addr}, nil +} + +// +// Hyper-v sockets Listener implementation +// + +type hvsockListener struct { + fd syscall.Handle + local Addr +} + +// Accept accepts an incoming call and returns the new connection +func (v *hvsockListener) Accept() (net.Conn, error) { + var sa rawSockaddrHyperv + var n = int32(unsafe.Sizeof(sa)) + fd, err := sys_accept(v.fd, &sa, &n) + if err != nil { + return nil, err + } + + // Extract an Addr from sa + raddr := Addr{} + for i := 0; i < len(raddr.VMID); i++ { + raddr.VMID[i] = sa.VMID[i] + } + for i := 0; i < len(raddr.ServiceID); i++ { + raddr.ServiceID[i] = sa.ServiceID[i] + } + return newHVsockConn(fd, v.local, raddr) +} + +// Close closes the listening connection +func (v *hvsockListener) Close() error { + return syscall.Close(v.fd) +} + +// Addr returns the address the Listener is listening on +func (v *hvsockListener) Addr() net.Addr { + return v.local +} + +// +// Hyper-V socket connection implementation +// + +// hvsockConn represent a Hyper-V connection. Complex mostly due to asynch send()/recv() syscalls. +type hvsockConn struct { + fd syscall.Handle + local Addr + remote Addr + + wg sync.WaitGroup + wgLock sync.RWMutex + closing atomicBool + + readDeadline deadlineHandler + writeDeadline deadlineHandler +} + +func newHVsockConn(h syscall.Handle, local Addr, remote Addr) (*hvsockConn, error) { + ioInitOnce.Do(initIo) + v := &hvsockConn{fd: h, local: local, remote: remote} + + _, err := createIoCompletionPort(h, ioCompletionPort, 0, 0xffffffff) + if err != nil { + return nil, err + } + err = setFileCompletionNotificationModes(h, + cFILE_SKIP_COMPLETION_PORT_ON_SUCCESS|cFILE_SKIP_SET_EVENT_ON_HANDLE) + if err != nil { + return nil, err + } + v.readDeadline.channel = make(timeoutChan) + v.writeDeadline.channel = make(timeoutChan) + + return v, nil +} + +// LocalAddr returns the local address of a connection +func (v *hvsockConn) LocalAddr() net.Addr { + return v.local +} + +// RemoteAddr returns the remote address of a connection +func (v *hvsockConn) RemoteAddr() net.Addr { + return v.remote +} + +// Close closes the connection +func (v *hvsockConn) Close() error { + v.close() + return nil +} + +// CloseRead shuts down the reading side of a hvsock connection +func (v *hvsockConn) CloseRead() error { + return syscall.Shutdown(v.fd, syscall.SHUT_RD) +} + +// CloseWrite shuts down the writing side of a hvsock connection +func (v *hvsockConn) CloseWrite() error { + return syscall.Shutdown(v.fd, syscall.SHUT_WR) +} + +// Read reads data from the connection +func (v *hvsockConn) Read(buf []byte) (int, error) { + var b syscall.WSABuf + var f uint32 + + b.Len = uint32(len(buf)) + b.Buf = &buf[0] + + c, err := v.prepareIo() + if err != nil { + return 0, err + } + defer v.wg.Done() + + if v.readDeadline.timedout.isSet() { + return 0, ErrTimeout + } + + var bytes uint32 + err = syscall.WSARecv(v.fd, &b, 1, &bytes, &f, &c.o, nil) + n, err := v.asyncIo(c, &v.readDeadline, bytes, err) + runtime.KeepAlive(buf) + + // Handle EOF conditions. + if err == nil && n == 0 && len(buf) != 0 { + return 0, io.EOF + } else if err == syscall.ERROR_BROKEN_PIPE { + return 0, io.EOF + } else { + return n, err + } +} + +// Write writes data over the connection +// TODO(rn): Remove once 4.9.x support is deprecated +func (v *hvsockConn) Write(buf []byte) (int, error) { + written := 0 + toWrite := len(buf) + for toWrite > 0 { + thisBatch := min(toWrite, maxMsgSize) + n, err := v.write(buf[written : written+thisBatch]) + if err != nil { + return written, err + } + if n != thisBatch { + return written, fmt.Errorf("short write %d != %d", n, thisBatch) + } + toWrite -= n + written += n + } + + return written, nil +} + +func (v *hvsockConn) write(buf []byte) (int, error) { + var b syscall.WSABuf + var f uint32 + + if len(buf) == 0 { + return 0, nil + } + + f = 0 + b.Len = uint32(len(buf)) + b.Buf = &buf[0] + + c, err := v.prepareIo() + if err != nil { + return 0, err + } + defer v.wg.Done() + + if v.writeDeadline.timedout.isSet() { + return 0, ErrTimeout + } + + var bytes uint32 + err = syscall.WSASend(v.fd, &b, 1, &bytes, f, &c.o, nil) + n, err := v.asyncIo(c, &v.writeDeadline, bytes, err) + runtime.KeepAlive(buf) + return n, err +} + +// SetReadDeadline implementation for Hyper-V sockets +func (v *hvsockConn) SetReadDeadline(deadline time.Time) error { + return v.readDeadline.set(deadline) +} + +// SetWriteDeadline implementation for Hyper-V sockets +func (v *hvsockConn) SetWriteDeadline(deadline time.Time) error { + return v.writeDeadline.set(deadline) +} + +// SetDeadline implementation for Hyper-V sockets +func (v *hvsockConn) SetDeadline(deadline time.Time) error { + if err := v.SetReadDeadline(deadline); err != nil { + return err + } + return v.SetWriteDeadline(deadline) +} + +// Helper functions for conversion to sockaddr + +// struck sockaddr equivalent +type rawSockaddrHyperv struct { + Family uint16 + Reserved uint16 + VMID GUID + ServiceID GUID +} + +// Utility function to build a struct sockaddr for syscalls. +func (a Addr) sockaddr(sa *rawSockaddrHyperv) (unsafe.Pointer, int32, error) { + sa.Family = hvsockAF + sa.Reserved = 0 + for i := 0; i < len(sa.VMID); i++ { + sa.VMID[i] = a.VMID[i] + } + for i := 0; i < len(sa.ServiceID); i++ { + sa.ServiceID[i] = a.ServiceID[i] + } + + return unsafe.Pointer(sa), int32(unsafe.Sizeof(*sa)), nil +} + +// Help for read/write timeouts +type deadlineHandler struct { + setLock sync.Mutex + channel timeoutChan + channelLock sync.RWMutex + timer *time.Timer + timedout atomicBool +} + +// The code below here is adjusted from: +// https://github.com/Microsoft/go-winio/blob/master/file.go +type atomicBool int32 + +func (b *atomicBool) isSet() bool { return atomic.LoadInt32((*int32)(b)) != 0 } +func (b *atomicBool) setFalse() { atomic.StoreInt32((*int32)(b), 0) } +func (b *atomicBool) setTrue() { atomic.StoreInt32((*int32)(b), 1) } +func (b *atomicBool) swap(new bool) bool { + var newInt int32 + if new { + newInt = 1 + } + return atomic.SwapInt32((*int32)(b), newInt) == 1 +} + +type timeoutError struct{} + +func (e *timeoutError) Error() string { return "i/o timeout" } +func (e *timeoutError) Timeout() bool { return true } +func (e *timeoutError) Temporary() bool { return true } + +type timeoutChan chan struct{} + +var ioInitOnce sync.Once +var ioCompletionPort syscall.Handle + +// ioResult contains the result of an asynchronous IO operation +type ioResult struct { + bytes uint32 + err error +} + +type ioOperation struct { + o syscall.Overlapped + ch chan ioResult +} + +func initIo() { + h, err := createIoCompletionPort(syscall.InvalidHandle, 0, 0, 0xffffffff) + if err != nil { + panic(err) + } + ioCompletionPort = h + go ioCompletionProcessor(h) +} + +func (v *hvsockConn) close() { + v.wgLock.Lock() + if !v.closing.swap(true) { + v.wgLock.Unlock() + // cancel all IO and wait for it to complete + cancelIoEx(v.fd, nil) + v.wg.Wait() + // at this point, no new IO can start + syscall.Close(v.fd) + v.fd = 0 + } else { + v.wgLock.Unlock() + } +} + +// prepareIo prepares for a new IO operation +func (v *hvsockConn) prepareIo() (*ioOperation, error) { + v.wgLock.RLock() + if v.closing.isSet() { + v.wgLock.RUnlock() + return nil, fmt.Errorf("HvSocket has already been closed") + } + v.wg.Add(1) + v.wgLock.RUnlock() + c := &ioOperation{} + c.ch = make(chan ioResult) + return c, nil +} + +// ioCompletionProcessor processes completed async IOs forever +func ioCompletionProcessor(h syscall.Handle) { + // Set the timer resolution to 1. This fixes a performance regression in golang 1.6. + timeBeginPeriod(1) + for { + var bytes uint32 + var key uintptr + var op *ioOperation + err := getQueuedCompletionStatus(h, &bytes, &key, &op, syscall.INFINITE) + if op == nil { + panic(err) + } + op.ch <- ioResult{bytes, err} + } +} + +// asyncIo processes the return value from Recv or Send, blocking until +// the operation has actually completed. +func (v *hvsockConn) asyncIo(c *ioOperation, d *deadlineHandler, bytes uint32, err error) (int, error) { + if err != syscall.ERROR_IO_PENDING { + return int(bytes), err + } + + if v.closing.isSet() { + cancelIoEx(v.fd, &c.o) + } + + var timeout timeoutChan + if d != nil { + d.channelLock.Lock() + timeout = d.channel + d.channelLock.Unlock() + } + + var r ioResult + select { + case r = <-c.ch: + err = r.err + if err == syscall.ERROR_OPERATION_ABORTED { + if v.closing.isSet() { + err = fmt.Errorf("HvSocket has already been closed") + } + } + case <-timeout: + cancelIoEx(v.fd, &c.o) + r = <-c.ch + err = r.err + if err == syscall.ERROR_OPERATION_ABORTED { + err = ErrTimeout + } + } + + // runtime.KeepAlive is needed, as c is passed via native + // code to ioCompletionProcessor, c must remain alive + // until the channel read is complete. + runtime.KeepAlive(c) + return int(r.bytes), err +} + +func (d *deadlineHandler) set(deadline time.Time) error { + d.setLock.Lock() + defer d.setLock.Unlock() + + if d.timer != nil { + if !d.timer.Stop() { + <-d.channel + } + d.timer = nil + } + d.timedout.setFalse() + + select { + case <-d.channel: + d.channelLock.Lock() + d.channel = make(chan struct{}) + d.channelLock.Unlock() + default: + } + + if deadline.IsZero() { + return nil + } + + timeoutIO := func() { + d.timedout.setTrue() + close(d.channel) + } + + now := time.Now() + duration := deadline.Sub(now) + if deadline.After(now) { + // Deadline is in the future, set a timer to wait + d.timer = time.AfterFunc(duration, timeoutIO) + } else { + // Deadline is in the past. Cancel all pending IO now. + timeoutIO() + } + return nil +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/linuxkit/virtsock/pkg/hvsock/zsyscall_windows.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/linuxkit/virtsock/pkg/hvsock/zsyscall_windows.go new file mode 100644 index 0000000000..bd4ca8a4f5 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/linuxkit/virtsock/pkg/hvsock/zsyscall_windows.go @@ -0,0 +1,171 @@ +package hvsock + +/* +Most of this code was derived from: https://github.com/Microsoft/go-winio +which has the following license: + +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. +*/ + +import ( + "syscall" + "unsafe" +) + +var ( + modws2_32 = syscall.NewLazyDLL("ws2_32.dll") + modwinmm = syscall.NewLazyDLL("winmm.dll") + modkernel32 = syscall.NewLazyDLL("kernel32.dll") + + procConnect = modws2_32.NewProc("connect") + procBind = modws2_32.NewProc("bind") + procAccept = modws2_32.NewProc("accept") + + procCancelIoEx = modkernel32.NewProc("CancelIoEx") + procCreateIoCompletionPort = modkernel32.NewProc("CreateIoCompletionPort") + procGetQueuedCompletionStatus = modkernel32.NewProc("GetQueuedCompletionStatus") + procSetFileCompletionNotificationModes = modkernel32.NewProc("SetFileCompletionNotificationModes") + proctimeBeginPeriod = modwinmm.NewProc("timeBeginPeriod") +) + +// Do the interface allocations only once for common +// Errno values. +const ( + errnoERROR_IO_PENDING = 997 + socketError = uintptr(^uint32(0)) + + cFILE_SKIP_COMPLETION_PORT_ON_SUCCESS = 1 + cFILE_SKIP_SET_EVENT_ON_HANDLE = 2 +) + +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 +} + +func sys_connect(s syscall.Handle, name unsafe.Pointer, namelen int32) (err error) { + r1, _, e1 := syscall.Syscall(procConnect.Addr(), 3, uintptr(s), uintptr(name), uintptr(namelen)) + if r1 == socketError { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + + return +} + +func sys_bind(s syscall.Handle, name unsafe.Pointer, namelen int32) (err error) { + r1, _, e1 := syscall.Syscall(procBind.Addr(), 3, uintptr(s), uintptr(name), uintptr(namelen)) + if r1 == socketError { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func sys_accept(s syscall.Handle, rsa *rawSockaddrHyperv, addrlen *int32) (handle syscall.Handle, err error) { + r1, _, e1 := syscall.Syscall(procAccept.Addr(), 3, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + handle = syscall.Handle(r1) + if r1 == socketError { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func cancelIoEx(file syscall.Handle, o *syscall.Overlapped) (err error) { + r1, _, e1 := syscall.Syscall(procCancelIoEx.Addr(), 2, uintptr(file), uintptr(unsafe.Pointer(o)), 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + 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) + if newport == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func getQueuedCompletionStatus(port syscall.Handle, bytes *uint32, key *uintptr, o **ioOperation, timeout uint32) (err error) { + r1, _, e1 := syscall.Syscall6(procGetQueuedCompletionStatus.Addr(), 5, uintptr(port), uintptr(unsafe.Pointer(bytes)), uintptr(unsafe.Pointer(key)), uintptr(unsafe.Pointer(o)), uintptr(timeout), 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func setFileCompletionNotificationModes(h syscall.Handle, flags uint8) (err error) { + r1, _, e1 := syscall.Syscall(procSetFileCompletionNotificationModes.Addr(), 2, uintptr(h), uintptr(flags), 0) + if r1 == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func timeBeginPeriod(period uint32) (n int32) { + r0, _, _ := syscall.Syscall(proctimeBeginPeriod.Addr(), 1, uintptr(period), 0, 0) + n = int32(r0) + return +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/linuxkit/virtsock/vendor.conf b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/linuxkit/virtsock/vendor.conf new file mode 100644 index 0000000000..9ae7d64f1d --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/linuxkit/virtsock/vendor.conf @@ -0,0 +1,2 @@ +github.com/pkg/errors 2b3a18b5f0fb6b4f9190549597d3f962c02bc5eb +golang.org/x/sys 9c9d83fe39ed3fd2d9249fcf6b755891fff54b03 diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-spec/LICENSE b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-spec/LICENSE new file mode 100644 index 0000000000..bdc403653e --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-spec/LICENSE @@ -0,0 +1,191 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + Copyright 2015 The Linux Foundation. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-spec/README.md b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-spec/README.md new file mode 100644 index 0000000000..b40dba17d8 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-spec/README.md @@ -0,0 +1,153 @@ +# Open Container Initiative Runtime Specification + +The [Open Container Initiative][oci] develops specifications for standards on Operating System process and application containers. + +The specification can be found [here](spec.md). + +## Table of Contents + +Additional documentation about how this group operates: + +- [Code of Conduct][code-of-conduct] +- [Style and Conventions](style.md) +- [Implementations](implementations.md) +- [Releases](RELEASES.md) +- [project](project.md) +- [charter][charter] + +## Use Cases + +To provide context for users the following section gives example use cases for each part of the spec. + +### Application Bundle Builders + +Application bundle builders can create a [bundle](bundle.md) directory that includes all of the files required for launching an application as a container. +The bundle contains an OCI [configuration file](config.md) where the builder can specify host-independent details such as [which executable to launch](config.md#process) and host-specific settings such as [mount](config.md#mounts) locations, [hook](config.md#posix-platform-hooks) paths, Linux [namespaces](config-linux.md#namespaces) and [cgroups](config-linux.md#control-groups). +Because the configuration includes host-specific settings, application bundle directories copied between two hosts may require configuration adjustments. + +### Hook Developers + +[Hook](config.md#posix-platform-hooks) developers can extend the functionality of an OCI-compliant runtime by hooking into a container's lifecycle with an external application. +Example use cases include sophisticated network configuration, volume garbage collection, etc. + +### Runtime Developers + +Runtime developers can build runtime implementations that run OCI-compliant bundles and container configuration, containing low-level OS and host-specific details, on a particular platform. + +## Contributing + +Development happens on GitHub for the spec. +Issues are used for bugs and actionable items and longer discussions can happen on the [mailing list](#mailing-list). + +The specification and code is licensed under the Apache 2.0 license found in the [LICENSE](./LICENSE) file. + +### Discuss your design + +The project welcomes submissions, but please let everyone know what you are working on. + +Before undertaking a nontrivial change to this specification, send mail to the [mailing list](#mailing-list) to discuss what you plan to do. +This gives everyone a chance to validate the design, helps prevent duplication of effort, and ensures that the idea fits. +It also guarantees that the design is sound before code is written; a GitHub pull-request is not the place for high-level discussions. + +Typos and grammatical errors can go straight to a pull-request. +When in doubt, start on the [mailing-list](#mailing-list). + +### Meetings + +The contributors and maintainers of all OCI projects have monthly meetings, which are usually at 2:00 PM (USA Pacific) on the first Wednesday of every month. +There is an [iCalendar][rfc5545] format for the meetings [here](meeting.ics). +Everyone is welcome to participate via [UberConference web][uberconference] or audio-only: +1 415 968 0849 (no PIN needed). +An initial agenda will be posted to the [mailing list](#mailing-list) in the week before each meeting, and everyone is welcome to propose additional topics or suggest other agenda alterations there. +Minutes are posted to the [mailing list](#mailing-list) and minutes from past calls are archived [here][minutes], with minutes from especially old meetings (September 2015 and earlier) archived [here][runtime-wiki]. + +### Mailing List + +You can subscribe and join the mailing list on [Google Groups][dev-list]. + +### IRC + +OCI discussion happens on #opencontainers on Freenode ([logs][irc-logs]). + +### Git commit + +#### Sign your work + +The sign-off is a simple line at the end of the explanation for the patch, which certifies that you wrote it or otherwise have the right to pass it on as an open-source patch. +The rules are pretty simple: if you can certify the below (from http://developercertificate.org): + +``` +Developer Certificate of Origin +Version 1.1 + +Copyright (C) 2004, 2006 The Linux Foundation and its contributors. +660 York Street, Suite 102, +San Francisco, CA 94110 USA + +Everyone is permitted to copy and distribute verbatim copies of this +license document, but changing it is not allowed. + + +Developer's Certificate of Origin 1.1 + +By making a contribution to this project, I certify that: + +(a) The contribution was created in whole or in part by me and I + have the right to submit it under the open source license + indicated in the file; or + +(b) The contribution is based upon previous work that, to the best + of my knowledge, is covered under an appropriate open source + license and I have the right under that license to submit that + work with modifications, whether created in whole or in part + by me, under the same open source license (unless I am + permitted to submit under a different license), as indicated + in the file; or + +(c) The contribution was provided directly to me by some other + person who certified (a), (b) or (c) and I have not modified + it. + +(d) I understand and agree that this project and the contribution + are public and that a record of the contribution (including all + personal information I submit with it, including my sign-off) is + maintained indefinitely and may be redistributed consistent with + this project or the open source license(s) involved. +``` + +then you just add a line to every git commit message: + + Signed-off-by: Joe Smith + +using your real name (sorry, no pseudonyms or anonymous contributions.) + +You can add the sign off when creating the git commit via `git commit -s`. + +#### Commit Style + +Simple house-keeping for clean git history. +Read more on [How to Write a Git Commit Message][how-to-git-commit] or the Discussion section of [git-commit(1)][git-commit.1]. + +1. Separate the subject from body with a blank line +2. Limit the subject line to 50 characters +3. Capitalize the subject line +4. Do not end the subject line with a period +5. Use the imperative mood in the subject line +6. Wrap the body at 72 characters +7. Use the body to explain what and why vs. how + * If there was important/useful/essential conversation or information, copy or include a reference +8. When possible, one keyword to scope the change in the subject (i.e. "README: ...", "runtime: ...") + + +[charter]: https://www.opencontainers.org/about/governance +[code-of-conduct]: https://github.com/opencontainers/tob/blob/master/code-of-conduct.md +[dev-list]: https://groups.google.com/a/opencontainers.org/forum/#!forum/dev +[how-to-git-commit]: http://chris.beams.io/posts/git-commit +[irc-logs]: http://ircbot.wl.linuxfoundation.org/eavesdrop/%23opencontainers/ +[iso-week]: https://en.wikipedia.org/wiki/ISO_week_date#Calculating_the_week_number_of_a_given_date +[minutes]: http://ircbot.wl.linuxfoundation.org/meetings/opencontainers/ +[oci]: https://www.opencontainers.org +[rfc5545]: https://tools.ietf.org/html/rfc5545 +[runtime-wiki]: https://github.com/opencontainers/runtime-spec/wiki +[uberconference]: https://www.uberconference.com/opencontainers + +[git-commit.1]: http://git-scm.com/docs/git-commit diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-spec/specs-go/config.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-spec/specs-go/config.go new file mode 100644 index 0000000000..f32698cab2 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-spec/specs-go/config.go @@ -0,0 +1,632 @@ +package specs + +import "os" + +// Spec is the base configuration for the container. +type Spec struct { + // Version of the Open Container Initiative Runtime Specification with which the bundle complies. + Version string `json:"ociVersion"` + // Process configures the container process. + Process *Process `json:"process,omitempty"` + // Root configures the container's root filesystem. + Root *Root `json:"root,omitempty"` + // Hostname configures the container's hostname. + Hostname string `json:"hostname,omitempty"` + // Mounts configures additional mounts (on top of Root). + Mounts []Mount `json:"mounts,omitempty"` + // Hooks configures callbacks for container lifecycle events. + Hooks *Hooks `json:"hooks,omitempty" platform:"linux,solaris"` + // Annotations contains arbitrary metadata for the container. + Annotations map[string]string `json:"annotations,omitempty"` + + // Linux is platform-specific configuration for Linux based containers. + Linux *Linux `json:"linux,omitempty" platform:"linux"` + // Solaris is platform-specific configuration for Solaris based containers. + Solaris *Solaris `json:"solaris,omitempty" platform:"solaris"` + // Windows is platform-specific configuration for Windows based containers. + Windows *Windows `json:"windows,omitempty" platform:"windows"` + // VM specifies configuration for virtual-machine-based containers. + VM *VM `json:"vm,omitempty" platform:"vm"` +} + +// Process contains information to start a specific application inside the container. +type Process struct { + // Terminal creates an interactive terminal for the container. + Terminal bool `json:"terminal,omitempty"` + // ConsoleSize specifies the size of the console. + ConsoleSize *Box `json:"consoleSize,omitempty"` + // User specifies user information for the process. + User User `json:"user"` + // Args specifies the binary and arguments for the application to execute. + Args []string `json:"args"` + // Env populates the process environment for the process. + Env []string `json:"env,omitempty"` + // Cwd is the current working directory for the process and must be + // relative to the container's root. + Cwd string `json:"cwd"` + // Capabilities are Linux capabilities that are kept for the process. + Capabilities *LinuxCapabilities `json:"capabilities,omitempty" platform:"linux"` + // Rlimits specifies rlimit options to apply to the process. + Rlimits []POSIXRlimit `json:"rlimits,omitempty" platform:"linux,solaris"` + // NoNewPrivileges controls whether additional privileges could be gained by processes in the container. + NoNewPrivileges bool `json:"noNewPrivileges,omitempty" platform:"linux"` + // ApparmorProfile specifies the apparmor profile for the container. + ApparmorProfile string `json:"apparmorProfile,omitempty" platform:"linux"` + // Specify an oom_score_adj for the container. + OOMScoreAdj *int `json:"oomScoreAdj,omitempty" platform:"linux"` + // SelinuxLabel specifies the selinux context that the container process is run as. + SelinuxLabel string `json:"selinuxLabel,omitempty" platform:"linux"` +} + +// LinuxCapabilities specifies the whitelist of capabilities that are kept for a process. +// http://man7.org/linux/man-pages/man7/capabilities.7.html +type LinuxCapabilities struct { + // Bounding is the set of capabilities checked by the kernel. + Bounding []string `json:"bounding,omitempty" platform:"linux"` + // Effective is the set of capabilities checked by the kernel. + Effective []string `json:"effective,omitempty" platform:"linux"` + // Inheritable is the capabilities preserved across execve. + Inheritable []string `json:"inheritable,omitempty" platform:"linux"` + // Permitted is the limiting superset for effective capabilities. + Permitted []string `json:"permitted,omitempty" platform:"linux"` + // Ambient is the ambient set of capabilities that are kept. + Ambient []string `json:"ambient,omitempty" platform:"linux"` +} + +// Box specifies dimensions of a rectangle. Used for specifying the size of a console. +type Box struct { + // Height is the vertical dimension of a box. + Height uint `json:"height"` + // Width is the horizontal dimension of a box. + Width uint `json:"width"` +} + +// User specifies specific user (and group) information for the container process. +type User struct { + // UID is the user id. + UID uint32 `json:"uid" platform:"linux,solaris"` + // GID is the group id. + GID uint32 `json:"gid" platform:"linux,solaris"` + // AdditionalGids are additional group ids set for the container's process. + AdditionalGids []uint32 `json:"additionalGids,omitempty" platform:"linux,solaris"` + // Username is the user name. + Username string `json:"username,omitempty" platform:"windows"` +} + +// Root contains information about the container's root filesystem on the host. +type Root struct { + // Path is the absolute path to the container's root filesystem. + Path string `json:"path"` + // Readonly makes the root filesystem for the container readonly before the process is executed. + Readonly bool `json:"readonly,omitempty"` +} + +// Mount specifies a mount for a container. +type Mount struct { + // Destination is the absolute path where the mount will be placed in the container. + Destination string `json:"destination"` + // Type specifies the mount kind. + Type string `json:"type,omitempty" platform:"linux,solaris"` + // Source specifies the source path of the mount. + Source string `json:"source,omitempty"` + // Options are fstab style mount options. + Options []string `json:"options,omitempty"` +} + +// Hook specifies a command that is run at a particular event in the lifecycle of a container +type Hook struct { + Path string `json:"path"` + Args []string `json:"args,omitempty"` + Env []string `json:"env,omitempty"` + Timeout *int `json:"timeout,omitempty"` +} + +// Hooks for container setup and teardown +type Hooks struct { + // Prestart is a list of hooks to be run before the container process is executed. + Prestart []Hook `json:"prestart,omitempty"` + // Poststart is a list of hooks to be run after the container process is started. + Poststart []Hook `json:"poststart,omitempty"` + // Poststop is a list of hooks to be run after the container process exits. + Poststop []Hook `json:"poststop,omitempty"` +} + +// Linux contains platform-specific configuration for Linux based containers. +type Linux struct { + // UIDMapping specifies user mappings for supporting user namespaces. + UIDMappings []LinuxIDMapping `json:"uidMappings,omitempty"` + // GIDMapping specifies group mappings for supporting user namespaces. + GIDMappings []LinuxIDMapping `json:"gidMappings,omitempty"` + // Sysctl are a set of key value pairs that are set for the container on start + Sysctl map[string]string `json:"sysctl,omitempty"` + // Resources contain cgroup information for handling resource constraints + // for the container + Resources *LinuxResources `json:"resources,omitempty"` + // CgroupsPath specifies the path to cgroups that are created and/or joined by the container. + // The path is expected to be relative to the cgroups mountpoint. + // If resources are specified, the cgroups at CgroupsPath will be updated based on resources. + CgroupsPath string `json:"cgroupsPath,omitempty"` + // Namespaces contains the namespaces that are created and/or joined by the container + Namespaces []LinuxNamespace `json:"namespaces,omitempty"` + // Devices are a list of device nodes that are created for the container + Devices []LinuxDevice `json:"devices,omitempty"` + // Seccomp specifies the seccomp security settings for the container. + Seccomp *LinuxSeccomp `json:"seccomp,omitempty"` + // RootfsPropagation is the rootfs mount propagation mode for the container. + RootfsPropagation string `json:"rootfsPropagation,omitempty"` + // MaskedPaths masks over the provided paths inside the container. + MaskedPaths []string `json:"maskedPaths,omitempty"` + // ReadonlyPaths sets the provided paths as RO inside the container. + ReadonlyPaths []string `json:"readonlyPaths,omitempty"` + // MountLabel specifies the selinux context for the mounts in the container. + MountLabel string `json:"mountLabel,omitempty"` + // IntelRdt contains Intel Resource Director Technology (RDT) information + // for handling resource constraints (e.g., L3 cache) for the container + IntelRdt *LinuxIntelRdt `json:"intelRdt,omitempty"` +} + +// LinuxNamespace is the configuration for a Linux namespace +type LinuxNamespace struct { + // Type is the type of namespace + Type LinuxNamespaceType `json:"type"` + // Path is a path to an existing namespace persisted on disk that can be joined + // and is of the same type + Path string `json:"path,omitempty"` +} + +// LinuxNamespaceType is one of the Linux namespaces +type LinuxNamespaceType string + +const ( + // PIDNamespace for isolating process IDs + PIDNamespace LinuxNamespaceType = "pid" + // NetworkNamespace for isolating network devices, stacks, ports, etc + NetworkNamespace = "network" + // MountNamespace for isolating mount points + MountNamespace = "mount" + // IPCNamespace for isolating System V IPC, POSIX message queues + IPCNamespace = "ipc" + // UTSNamespace for isolating hostname and NIS domain name + UTSNamespace = "uts" + // UserNamespace for isolating user and group IDs + UserNamespace = "user" + // CgroupNamespace for isolating cgroup hierarchies + CgroupNamespace = "cgroup" +) + +// LinuxIDMapping specifies UID/GID mappings +type LinuxIDMapping struct { + // ContainerID is the starting UID/GID in the container + ContainerID uint32 `json:"containerID"` + // HostID is the starting UID/GID on the host to be mapped to 'ContainerID' + HostID uint32 `json:"hostID"` + // Size is the number of IDs to be mapped + Size uint32 `json:"size"` +} + +// POSIXRlimit type and restrictions +type POSIXRlimit struct { + // Type of the rlimit to set + Type string `json:"type"` + // Hard is the hard limit for the specified type + Hard uint64 `json:"hard"` + // Soft is the soft limit for the specified type + Soft uint64 `json:"soft"` +} + +// LinuxHugepageLimit structure corresponds to limiting kernel hugepages +type LinuxHugepageLimit struct { + // Pagesize is the hugepage size + Pagesize string `json:"pageSize"` + // Limit is the limit of "hugepagesize" hugetlb usage + Limit uint64 `json:"limit"` +} + +// LinuxInterfacePriority for network interfaces +type LinuxInterfacePriority struct { + // Name is the name of the network interface + Name string `json:"name"` + // Priority for the interface + Priority uint32 `json:"priority"` +} + +// linuxBlockIODevice holds major:minor format supported in blkio cgroup +type linuxBlockIODevice struct { + // Major is the device's major number. + Major int64 `json:"major"` + // Minor is the device's minor number. + Minor int64 `json:"minor"` +} + +// LinuxWeightDevice struct holds a `major:minor weight` pair for weightDevice +type LinuxWeightDevice struct { + linuxBlockIODevice + // Weight is the bandwidth rate for the device. + Weight *uint16 `json:"weight,omitempty"` + // LeafWeight is the bandwidth rate for the device while competing with the cgroup's child cgroups, CFQ scheduler only + LeafWeight *uint16 `json:"leafWeight,omitempty"` +} + +// LinuxThrottleDevice struct holds a `major:minor rate_per_second` pair +type LinuxThrottleDevice struct { + linuxBlockIODevice + // Rate is the IO rate limit per cgroup per device + Rate uint64 `json:"rate"` +} + +// LinuxBlockIO for Linux cgroup 'blkio' resource management +type LinuxBlockIO struct { + // Specifies per cgroup weight + Weight *uint16 `json:"weight,omitempty"` + // Specifies tasks' weight in the given cgroup while competing with the cgroup's child cgroups, CFQ scheduler only + LeafWeight *uint16 `json:"leafWeight,omitempty"` + // Weight per cgroup per device, can override BlkioWeight + WeightDevice []LinuxWeightDevice `json:"weightDevice,omitempty"` + // IO read rate limit per cgroup per device, bytes per second + ThrottleReadBpsDevice []LinuxThrottleDevice `json:"throttleReadBpsDevice,omitempty"` + // IO write rate limit per cgroup per device, bytes per second + ThrottleWriteBpsDevice []LinuxThrottleDevice `json:"throttleWriteBpsDevice,omitempty"` + // IO read rate limit per cgroup per device, IO per second + ThrottleReadIOPSDevice []LinuxThrottleDevice `json:"throttleReadIOPSDevice,omitempty"` + // IO write rate limit per cgroup per device, IO per second + ThrottleWriteIOPSDevice []LinuxThrottleDevice `json:"throttleWriteIOPSDevice,omitempty"` +} + +// LinuxMemory for Linux cgroup 'memory' resource management +type LinuxMemory struct { + // Memory limit (in bytes). + Limit *int64 `json:"limit,omitempty"` + // Memory reservation or soft_limit (in bytes). + Reservation *int64 `json:"reservation,omitempty"` + // Total memory limit (memory + swap). + Swap *int64 `json:"swap,omitempty"` + // Kernel memory limit (in bytes). + Kernel *int64 `json:"kernel,omitempty"` + // Kernel memory limit for tcp (in bytes) + KernelTCP *int64 `json:"kernelTCP,omitempty"` + // How aggressive the kernel will swap memory pages. + Swappiness *uint64 `json:"swappiness,omitempty"` + // DisableOOMKiller disables the OOM killer for out of memory conditions + DisableOOMKiller *bool `json:"disableOOMKiller,omitempty"` +} + +// LinuxCPU for Linux cgroup 'cpu' resource management +type LinuxCPU struct { + // CPU shares (relative weight (ratio) vs. other cgroups with cpu shares). + Shares *uint64 `json:"shares,omitempty"` + // CPU hardcap limit (in usecs). Allowed cpu time in a given period. + Quota *int64 `json:"quota,omitempty"` + // CPU period to be used for hardcapping (in usecs). + Period *uint64 `json:"period,omitempty"` + // How much time realtime scheduling may use (in usecs). + RealtimeRuntime *int64 `json:"realtimeRuntime,omitempty"` + // CPU period to be used for realtime scheduling (in usecs). + RealtimePeriod *uint64 `json:"realtimePeriod,omitempty"` + // CPUs to use within the cpuset. Default is to use any CPU available. + Cpus string `json:"cpus,omitempty"` + // List of memory nodes in the cpuset. Default is to use any available memory node. + Mems string `json:"mems,omitempty"` +} + +// LinuxPids for Linux cgroup 'pids' resource management (Linux 4.3) +type LinuxPids struct { + // Maximum number of PIDs. Default is "no limit". + Limit int64 `json:"limit"` +} + +// LinuxNetwork identification and priority configuration +type LinuxNetwork struct { + // Set class identifier for container's network packets + ClassID *uint32 `json:"classID,omitempty"` + // Set priority of network traffic for container + Priorities []LinuxInterfacePriority `json:"priorities,omitempty"` +} + +// LinuxRdma for Linux cgroup 'rdma' resource management (Linux 4.11) +type LinuxRdma struct { + // Maximum number of HCA handles that can be opened. Default is "no limit". + HcaHandles *uint32 `json:"hcaHandles,omitempty"` + // Maximum number of HCA objects that can be created. Default is "no limit". + HcaObjects *uint32 `json:"hcaObjects,omitempty"` +} + +// LinuxResources has container runtime resource constraints +type LinuxResources struct { + // Devices configures the device whitelist. + Devices []LinuxDeviceCgroup `json:"devices,omitempty"` + // Memory restriction configuration + Memory *LinuxMemory `json:"memory,omitempty"` + // CPU resource restriction configuration + CPU *LinuxCPU `json:"cpu,omitempty"` + // Task resource restriction configuration. + Pids *LinuxPids `json:"pids,omitempty"` + // BlockIO restriction configuration + BlockIO *LinuxBlockIO `json:"blockIO,omitempty"` + // Hugetlb limit (in bytes) + HugepageLimits []LinuxHugepageLimit `json:"hugepageLimits,omitempty"` + // Network restriction configuration + Network *LinuxNetwork `json:"network,omitempty"` + // Rdma resource restriction configuration. + // Limits are a set of key value pairs that define RDMA resource limits, + // where the key is device name and value is resource limits. + Rdma map[string]LinuxRdma `json:"rdma,omitempty"` +} + +// LinuxDevice represents the mknod information for a Linux special device file +type LinuxDevice struct { + // Path to the device. + Path string `json:"path"` + // Device type, block, char, etc. + Type string `json:"type"` + // Major is the device's major number. + Major int64 `json:"major"` + // Minor is the device's minor number. + Minor int64 `json:"minor"` + // FileMode permission bits for the device. + FileMode *os.FileMode `json:"fileMode,omitempty"` + // UID of the device. + UID *uint32 `json:"uid,omitempty"` + // Gid of the device. + GID *uint32 `json:"gid,omitempty"` +} + +// LinuxDeviceCgroup represents a device rule for the whitelist controller +type LinuxDeviceCgroup struct { + // Allow or deny + Allow bool `json:"allow"` + // Device type, block, char, etc. + Type string `json:"type,omitempty"` + // Major is the device's major number. + Major *int64 `json:"major,omitempty"` + // Minor is the device's minor number. + Minor *int64 `json:"minor,omitempty"` + // Cgroup access permissions format, rwm. + Access string `json:"access,omitempty"` +} + +// Solaris contains platform-specific configuration for Solaris application containers. +type Solaris struct { + // SMF FMRI which should go "online" before we start the container process. + Milestone string `json:"milestone,omitempty"` + // Maximum set of privileges any process in this container can obtain. + LimitPriv string `json:"limitpriv,omitempty"` + // The maximum amount of shared memory allowed for this container. + MaxShmMemory string `json:"maxShmMemory,omitempty"` + // Specification for automatic creation of network resources for this container. + Anet []SolarisAnet `json:"anet,omitempty"` + // Set limit on the amount of CPU time that can be used by container. + CappedCPU *SolarisCappedCPU `json:"cappedCPU,omitempty"` + // The physical and swap caps on the memory that can be used by this container. + CappedMemory *SolarisCappedMemory `json:"cappedMemory,omitempty"` +} + +// SolarisCappedCPU allows users to set limit on the amount of CPU time that can be used by container. +type SolarisCappedCPU struct { + Ncpus string `json:"ncpus,omitempty"` +} + +// SolarisCappedMemory allows users to set the physical and swap caps on the memory that can be used by this container. +type SolarisCappedMemory struct { + Physical string `json:"physical,omitempty"` + Swap string `json:"swap,omitempty"` +} + +// SolarisAnet provides the specification for automatic creation of network resources for this container. +type SolarisAnet struct { + // Specify a name for the automatically created VNIC datalink. + Linkname string `json:"linkname,omitempty"` + // Specify the link over which the VNIC will be created. + Lowerlink string `json:"lowerLink,omitempty"` + // The set of IP addresses that the container can use. + Allowedaddr string `json:"allowedAddress,omitempty"` + // Specifies whether allowedAddress limitation is to be applied to the VNIC. + Configallowedaddr string `json:"configureAllowedAddress,omitempty"` + // The value of the optional default router. + Defrouter string `json:"defrouter,omitempty"` + // Enable one or more types of link protection. + Linkprotection string `json:"linkProtection,omitempty"` + // Set the VNIC's macAddress + Macaddress string `json:"macAddress,omitempty"` +} + +// Windows defines the runtime configuration for Windows based containers, including Hyper-V containers. +type Windows struct { + // LayerFolders contains a list of absolute paths to directories containing image layers. + LayerFolders []string `json:"layerFolders"` + // Devices are the list of devices to be mapped into the container. + Devices []WindowsDevice `json:"devices,omitempty"` + // Resources contains information for handling resource constraints for the container. + Resources *WindowsResources `json:"resources,omitempty"` + // CredentialSpec contains a JSON object describing a group Managed Service Account (gMSA) specification. + CredentialSpec interface{} `json:"credentialSpec,omitempty"` + // Servicing indicates if the container is being started in a mode to apply a Windows Update servicing operation. + Servicing bool `json:"servicing,omitempty"` + // IgnoreFlushesDuringBoot indicates if the container is being started in a mode where disk writes are not flushed during its boot process. + IgnoreFlushesDuringBoot bool `json:"ignoreFlushesDuringBoot,omitempty"` + // HyperV contains information for running a container with Hyper-V isolation. + HyperV *WindowsHyperV `json:"hyperv,omitempty"` + // Network restriction configuration. + Network *WindowsNetwork `json:"network,omitempty"` +} + +// WindowsDevice represents information about a host device to be mapped into the container. +type WindowsDevice struct { + // Device identifier: interface class GUID, etc. + ID string `json:"id"` + // Device identifier type: "class", etc. + IDType string `json:"idType"` +} + +// WindowsResources has container runtime resource constraints for containers running on Windows. +type WindowsResources struct { + // Memory restriction configuration. + Memory *WindowsMemoryResources `json:"memory,omitempty"` + // CPU resource restriction configuration. + CPU *WindowsCPUResources `json:"cpu,omitempty"` + // Storage restriction configuration. + Storage *WindowsStorageResources `json:"storage,omitempty"` +} + +// WindowsMemoryResources contains memory resource management settings. +type WindowsMemoryResources struct { + // Memory limit in bytes. + Limit *uint64 `json:"limit,omitempty"` +} + +// WindowsCPUResources contains CPU resource management settings. +type WindowsCPUResources struct { + // Number of CPUs available to the container. + Count *uint64 `json:"count,omitempty"` + // CPU shares (relative weight to other containers with cpu shares). + Shares *uint16 `json:"shares,omitempty"` + // Specifies the portion of processor cycles that this container can use as a percentage times 100. + Maximum *uint16 `json:"maximum,omitempty"` +} + +// WindowsStorageResources contains storage resource management settings. +type WindowsStorageResources struct { + // Specifies maximum Iops for the system drive. + Iops *uint64 `json:"iops,omitempty"` + // Specifies maximum bytes per second for the system drive. + Bps *uint64 `json:"bps,omitempty"` + // Sandbox size specifies the minimum size of the system drive in bytes. + SandboxSize *uint64 `json:"sandboxSize,omitempty"` +} + +// WindowsNetwork contains network settings for Windows containers. +type WindowsNetwork struct { + // List of HNS endpoints that the container should connect to. + EndpointList []string `json:"endpointList,omitempty"` + // Specifies if unqualified DNS name resolution is allowed. + AllowUnqualifiedDNSQuery bool `json:"allowUnqualifiedDNSQuery,omitempty"` + // Comma separated list of DNS suffixes to use for name resolution. + DNSSearchList []string `json:"DNSSearchList,omitempty"` + // Name (ID) of the container that we will share with the network stack. + NetworkSharedContainerName string `json:"networkSharedContainerName,omitempty"` + // name (ID) of the network namespace that will be used for the container. + NetworkNamespace string `json:"networkNamespace,omitempty"` +} + +// WindowsHyperV contains information for configuring a container to run with Hyper-V isolation. +type WindowsHyperV struct { + // UtilityVMPath is an optional path to the image used for the Utility VM. + UtilityVMPath string `json:"utilityVMPath,omitempty"` +} + +// VM contains information for virtual-machine-based containers. +type VM struct { + // Hypervisor specifies hypervisor-related configuration for virtual-machine-based containers. + Hypervisor VMHypervisor `json:"hypervisor,omitempty"` + // Kernel specifies kernel-related configuration for virtual-machine-based containers. + Kernel VMKernel `json:"kernel"` + // Image specifies guest image related configuration for virtual-machine-based containers. + Image VMImage `json:"image,omitempty"` +} + +// VMHypervisor contains information about the hypervisor to use for a virtual machine. +type VMHypervisor struct { + // Path is the host path to the hypervisor used to manage the virtual machine. + Path string `json:"path"` + // Parameters specifies parameters to pass to the hypervisor. + Parameters string `json:"parameters,omitempty"` +} + +// VMKernel contains information about the kernel to use for a virtual machine. +type VMKernel struct { + // Path is the host path to the kernel used to boot the virtual machine. + Path string `json:"path"` + // Parameters specifies parameters to pass to the kernel. + Parameters string `json:"parameters,omitempty"` + // InitRD is the host path to an initial ramdisk to be used by the kernel. + InitRD string `json:"initrd,omitempty"` +} + +// VMImage contains information about the virtual machine root image. +type VMImage struct { + // Path is the host path to the root image that the VM kernel would boot into. + Path string `json:"path"` + // Format is the root image format type (e.g. "qcow2", "raw", "vhd", etc). + Format string `json:"format"` +} + +// LinuxSeccomp represents syscall restrictions +type LinuxSeccomp struct { + DefaultAction LinuxSeccompAction `json:"defaultAction"` + Architectures []Arch `json:"architectures,omitempty"` + Syscalls []LinuxSyscall `json:"syscalls,omitempty"` +} + +// Arch used for additional architectures +type Arch string + +// Additional architectures permitted to be used for system calls +// By default only the native architecture of the kernel is permitted +const ( + ArchX86 Arch = "SCMP_ARCH_X86" + ArchX86_64 Arch = "SCMP_ARCH_X86_64" + ArchX32 Arch = "SCMP_ARCH_X32" + ArchARM Arch = "SCMP_ARCH_ARM" + ArchAARCH64 Arch = "SCMP_ARCH_AARCH64" + ArchMIPS Arch = "SCMP_ARCH_MIPS" + ArchMIPS64 Arch = "SCMP_ARCH_MIPS64" + ArchMIPS64N32 Arch = "SCMP_ARCH_MIPS64N32" + ArchMIPSEL Arch = "SCMP_ARCH_MIPSEL" + ArchMIPSEL64 Arch = "SCMP_ARCH_MIPSEL64" + ArchMIPSEL64N32 Arch = "SCMP_ARCH_MIPSEL64N32" + ArchPPC Arch = "SCMP_ARCH_PPC" + ArchPPC64 Arch = "SCMP_ARCH_PPC64" + ArchPPC64LE Arch = "SCMP_ARCH_PPC64LE" + ArchS390 Arch = "SCMP_ARCH_S390" + ArchS390X Arch = "SCMP_ARCH_S390X" + ArchPARISC Arch = "SCMP_ARCH_PARISC" + ArchPARISC64 Arch = "SCMP_ARCH_PARISC64" +) + +// LinuxSeccompAction taken upon Seccomp rule match +type LinuxSeccompAction string + +// Define actions for Seccomp rules +const ( + ActKill LinuxSeccompAction = "SCMP_ACT_KILL" + ActTrap LinuxSeccompAction = "SCMP_ACT_TRAP" + ActErrno LinuxSeccompAction = "SCMP_ACT_ERRNO" + ActTrace LinuxSeccompAction = "SCMP_ACT_TRACE" + ActAllow LinuxSeccompAction = "SCMP_ACT_ALLOW" +) + +// LinuxSeccompOperator used to match syscall arguments in Seccomp +type LinuxSeccompOperator string + +// Define operators for syscall arguments in Seccomp +const ( + OpNotEqual LinuxSeccompOperator = "SCMP_CMP_NE" + OpLessThan LinuxSeccompOperator = "SCMP_CMP_LT" + OpLessEqual LinuxSeccompOperator = "SCMP_CMP_LE" + OpEqualTo LinuxSeccompOperator = "SCMP_CMP_EQ" + OpGreaterEqual LinuxSeccompOperator = "SCMP_CMP_GE" + OpGreaterThan LinuxSeccompOperator = "SCMP_CMP_GT" + OpMaskedEqual LinuxSeccompOperator = "SCMP_CMP_MASKED_EQ" +) + +// LinuxSeccompArg used for matching specific syscall arguments in Seccomp +type LinuxSeccompArg struct { + Index uint `json:"index"` + Value uint64 `json:"value"` + ValueTwo uint64 `json:"valueTwo,omitempty"` + Op LinuxSeccompOperator `json:"op"` +} + +// LinuxSyscall is used to match a syscall in Seccomp +type LinuxSyscall struct { + Names []string `json:"names"` + Action LinuxSeccompAction `json:"action"` + Args []LinuxSeccompArg `json:"args,omitempty"` +} + +// LinuxIntelRdt has container runtime resource constraints +// for Intel RDT/CAT which introduced in Linux 4.10 kernel +type LinuxIntelRdt struct { + // The schema for L3 cache id and capacity bitmask (CBM) + // Format: "L3:=;=;..." + L3CacheSchema string `json:"l3CacheSchema,omitempty"` +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-spec/specs-go/state.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-spec/specs-go/state.go new file mode 100644 index 0000000000..89dce34be2 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-spec/specs-go/state.go @@ -0,0 +1,17 @@ +package specs + +// State holds information about the runtime state of the container. +type State struct { + // Version is the version of the specification that is supported. + Version string `json:"ociVersion"` + // ID is the container ID + ID string `json:"id"` + // Status is the runtime status of the container. + Status string `json:"status"` + // Pid is the process ID for the container process. + Pid int `json:"pid,omitempty"` + // Bundle is the path to the container's bundle directory. + Bundle string `json:"bundle"` + // Annotations are key values associated with the container. + Annotations map[string]string `json:"annotations,omitempty"` +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-spec/specs-go/version.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-spec/specs-go/version.go new file mode 100644 index 0000000000..b920fc1b39 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-spec/specs-go/version.go @@ -0,0 +1,18 @@ +package specs + +import "fmt" + +const ( + // VersionMajor is for an API incompatible changes + VersionMajor = 1 + // VersionMinor is for functionality in a backwards-compatible manner + VersionMinor = 0 + // VersionPatch is for backwards-compatible bug fixes + VersionPatch = 1 + + // VersionDev indicates development branch. Releases will be empty string. + VersionDev = "-dev" +) + +// Version is the specification version that the package types support. +var Version = fmt.Sprintf("%d.%d.%d%s", VersionMajor, VersionMinor, VersionPatch, VersionDev) diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/LICENSE b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/LICENSE new file mode 100644 index 0000000000..bdc403653e --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/LICENSE @@ -0,0 +1,191 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + Copyright 2015 The Linux Foundation. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/README.md b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/README.md new file mode 100644 index 0000000000..c9974cab58 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/README.md @@ -0,0 +1,128 @@ +# oci-runtime-tool [![Build Status](https://travis-ci.org/opencontainers/runtime-tools.svg?branch=master)](https://travis-ci.org/opencontainers/runtime-tools) [![Go Report Card](https://goreportcard.com/badge/github.com/opencontainers/runtime-tools)](https://goreportcard.com/report/github.com/opencontainers/runtime-tools) + +oci-runtime-tool is a collection of tools for working with the [OCI runtime specification][runtime-spec]. +To build from source code, runtime-tools requires Go 1.7.x or above. + +## Generating an OCI runtime spec configuration files + +[`oci-runtime-tool generate`][generate.1] generates [configuration JSON][config.json] for an [OCI bundle][bundle]. +[OCI-compatible runtimes][runtime-spec] like [runC][] expect to read the configuration from `config.json`. + +```console +$ oci-runtime-tool generate --output config.json +$ cat config.json +{ + "ociVersion": "0.5.0", + … +} +``` + +## Validating an OCI bundle + +[`oci-runtime-tool validate`][validate.1] validates an OCI bundle. +The error message will be printed if the OCI bundle failed the validation procedure. + +```console +$ oci-runtime-tool generate +$ oci-runtime-tool validate +INFO[0000] Bundle validation succeeded. +``` + +## Testing OCI runtimes + +The runtime validation suite uses [node-tap][], which is packaged for some distributions (for example, it is in [Debian's `node-tap` package][debian-node-tap]). +If your distribution does not package node-tap, you can install [npm][] (for example, from [Gentoo's `nodejs` package][gentoo-nodejs]) and use it: + +```console +$ npm install tap +``` + +Build the validation executables: + +```console +$ make runtimetest validation-executables +``` + +Runtime validation currently [only supports](docs/runtime-compliance-testing.md) the [OCI Runtime Command Line Interface](docs/command-line-interface.md). +If we add support for alternative APIs in the future, runtime validation will gain an option to select the desired runtime API. +For the command line interface, the `RUNTIME` option selects the runtime command (`funC` in the [OCI Runtime Command Line Interface](docs/command-line-interface.md)). + +``` +$ sudo make RUNTIME=runc localvalidation +RUNTIME=runc tap validation/pidfile.t validation/linux_cgroups_hugetlb.t validation/linux_cgroups_memory.t validation/linux_rootfs_propagation_shared.t validation/kill.t validation/create.t validation/poststart.t validation/linux_cgroups_network.t validation/poststop_fail.t validation/linux_readonly_paths.t validation/prestart_fail.t validation/hooks_stdin.t validation/default.t validation/linux_masked_paths.t validation/poststop.t validation/misc_props.t validation/prestart.t validation/poststart_fail.t validation/mounts.t validation/linux_cgroups_relative_pids.t validation/process_user.t validation/process.t validation/hooks.t validation/process_capabilities_fail.t validation/process_rlimits_fail.t validation/linux_cgroups_relative_cpus.t validation/process_rlimits.t validation/linux_cgroups_relative_blkio.t validation/linux_sysctl.t validation/linux_seccomp.t validation/linux_devices.t validation/start.t validation/linux_cgroups_pids.t validation/process_capabilities.t validation/process_oom_score_adj.t validation/linux_cgroups_relative_hugetlb.t validation/linux_cgroups_cpus.t validation/linux_cgroups_relative_memory.t validation/state.t validation/root_readonly_true.t validation/linux_cgroups_blkio.t validation/linux_rootfs_propagation_unbindable.t validation/delete.t validation/linux_cgroups_relative_network.t validation/hostname.t validation/killsig.t validation/linux_uid_mappings.t +validation/pidfile.t .failed to create the container +container_linux.go:348: starting container process caused "process_linux.go:402: container init caused \"process_linux.go:367: setting cgroup config for procHooks process caused \\\"failed to write 56892210544640 to hugetlb.1GB.limit_in_bytes: open /sys/fs/cgroup/hugetlb/cgrouptest/hugetlb.1GB.limit_in_bytes: permission denied\\\"\"" +exit status 1 +validation/pidfile.t .................................. 1/1 315ms +validation/linux_cgroups_hugetlb.t .................... 0/1 + not ok validation/linux_cgroups_hugetlb.t + timeout: 30000 + file: validation/linux_cgroups_hugetlb.t + command: validation/linux_cgroups_hugetlb.t + args: [] + stdio: + - 0 + - pipe + - 2 + cwd: /…/go/src/github.com/opencontainers/runtime-tools + exitCode: 1 + +validation/linux_cgroups_memory.t ..................... 9/9 +validation/linux_rootfs_propagation_shared.t ...... 252/282 + not ok shared root propagation exposes "/target348456609/mount892511628/example376408222" + + Skipped: 29 + /dev/null (default device) has unconfigured permissions +… +total ........................................... 4381/4962 + + + 4381 passing (1m) + 567 pending + 14 failing + +make: *** [Makefile:44: localvalidation] Error 1 +``` + +You can also run an individual test executable directly: + +```console +$ sudo RUNTIME=runc validation/default/default.t +TAP version 13 +ok 1 - has expected hostname + --- + { + "actual": "mrsdalloway", + "expected": "mrsdalloway" + } + ... +… +ok 287 # SKIP linux.gidMappings not set +1..287 +``` + +If you cannot install node-tap, you can probably run the test suite with another [TAP consumer][tap-consumers]. +For example, with [`prove`][prove]: + +```console +$ sudo make TAP='prove -Q -j9' RUNTIME=runc VALIDATION_TESTS=validation/pidfile/pidfile.t localvalidation +RUNTIME=runc prove -Q -j9 validation/pidfile.t +All tests successful. +Files=1, Tests=1, 0 wallclock secs ( 0.01 usr 0.01 sys + 0.03 cusr 0.03 csys = 0.08 CPU) +Result: PASS +``` + +[bundle]: https://github.com/opencontainers/runtime-spec/blob/master/bundle.md +[config.json]: https://github.com/opencontainers/runtime-spec/blob/master/config.md +[debian-node-tap]: https://packages.debian.org/stretch/node-tap +[debian-nodejs]: https://packages.debian.org/stretch/nodejs +[gentoo-nodejs]: https://packages.gentoo.org/packages/net-libs/nodejs +[node-tap]: http://www.node-tap.org/ +[npm]: https://www.npmjs.com/ +[prove]: http://search.cpan.org/~leont/Test-Harness-3.39/bin/prove +[runC]: https://github.com/opencontainers/runc +[runtime-spec]: https://github.com/opencontainers/runtime-spec +[tap-consumers]: https://testanything.org/consumers.html + +[generate.1]: man/oci-runtime-tool-generate.1.md +[validate.1]: man/oci-runtime-tool-validate.1.md diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/error/error.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/error/error.go new file mode 100644 index 0000000000..f7eac6639f --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/error/error.go @@ -0,0 +1,122 @@ +// Package error implements generic tooling for tracking RFC 2119 +// violations and linking back to the appropriate specification section. +package error + +import ( + "fmt" + "strings" +) + +// Level represents the RFC 2119 compliance levels +type Level int + +const ( + // MAY-level + + // May represents 'MAY' in RFC 2119. + May Level = iota + // Optional represents 'OPTIONAL' in RFC 2119. + Optional + + // SHOULD-level + + // Should represents 'SHOULD' in RFC 2119. + Should + // ShouldNot represents 'SHOULD NOT' in RFC 2119. + ShouldNot + // Recommended represents 'RECOMMENDED' in RFC 2119. + Recommended + // NotRecommended represents 'NOT RECOMMENDED' in RFC 2119. + NotRecommended + + // MUST-level + + // Must represents 'MUST' in RFC 2119 + Must + // MustNot represents 'MUST NOT' in RFC 2119. + MustNot + // Shall represents 'SHALL' in RFC 2119. + Shall + // ShallNot represents 'SHALL NOT' in RFC 2119. + ShallNot + // Required represents 'REQUIRED' in RFC 2119. + Required +) + +// Error represents an error with compliance level and specification reference. +type Error struct { + // Level represents the RFC 2119 compliance level. + Level Level + + // Reference is a URL for the violated specification requirement. + Reference string + + // Err holds additional details about the violation. + Err error +} + +// ParseLevel takes a string level and returns the RFC 2119 compliance level constant. +func ParseLevel(level string) (Level, error) { + switch strings.ToUpper(level) { + case "MAY": + fallthrough + case "OPTIONAL": + return May, nil + case "SHOULD": + fallthrough + case "SHOULDNOT": + fallthrough + case "RECOMMENDED": + fallthrough + case "NOTRECOMMENDED": + return Should, nil + case "MUST": + fallthrough + case "MUSTNOT": + fallthrough + case "SHALL": + fallthrough + case "SHALLNOT": + fallthrough + case "REQUIRED": + return Must, nil + } + + var l Level + return l, fmt.Errorf("%q is not a valid compliance level", level) +} + +// String takes a RFC 2119 compliance level constant and returns a string representation. +func (level Level) String() string { + switch level { + case May: + return "MAY" + case Optional: + return "OPTIONAL" + case Should: + return "SHOULD" + case ShouldNot: + return "SHOULD NOT" + case Recommended: + return "RECOMMENDED" + case NotRecommended: + return "NOT RECOMMENDED" + case Must: + return "MUST" + case MustNot: + return "MUST NOT" + case Shall: + return "SHALL" + case ShallNot: + return "SHALL NOT" + case Required: + return "REQUIRED" + } + + panic(fmt.Sprintf("%d is not a valid compliance level", level)) +} + +// Error returns the error message with specification reference. +func (err *Error) Error() string { + return fmt.Sprintf("%s\nRefer to: %s", err.Err.Error(), err.Reference) +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/filepath/abs.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/filepath/abs.go new file mode 100644 index 0000000000..e4ab7453f3 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/filepath/abs.go @@ -0,0 +1,48 @@ +package filepath + +import ( + "regexp" + "strings" +) + +var windowsAbs = regexp.MustCompile(`^[a-zA-Z]:\\.*$`) + +// Abs is a version of path/filepath's Abs with an explicit operating +// system and current working directory. +func Abs(os, path, cwd string) (_ string, err error) { + if IsAbs(os, path) { + return Clean(os, path), nil + } + return Clean(os, Join(os, cwd, path)), nil +} + +// IsAbs is a version of path/filepath's IsAbs with an explicit +// operating system. +func IsAbs(os, path string) bool { + if os == "windows" { + // FIXME: copy hideous logic from Go's + // src/path/filepath/path_windows.go into somewhere where we can + // put 3-clause BSD licensed code. + return windowsAbs.MatchString(path) + } + sep := Separator(os) + + // POSIX has [1]: + // + // > If a pathname begins with two successive characters, + // > the first component following the leading characters + // > may be interpreted in an implementation-defined manner, + // > although more than two leading characters shall be + // > treated as a single character. + // + // And Boost treats // as non-absolute [2], but Linux [3,4], Python + // [5] and Go [6] all treat // as absolute. + // + // [1]: http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13 + // [2]: https://github.com/boostorg/filesystem/blob/boost-1.64.0/test/path_test.cpp#L861 + // [3]: http://man7.org/linux/man-pages/man7/path_resolution.7.html + // [4]: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/filesystems/path-lookup.md?h=v4.12#n41 + // [5]: https://github.com/python/cpython/blob/v3.6.1/Lib/posixpath.py#L64-L66 + // [6]: https://go.googlesource.com/go/+/go1.8.3/src/path/path.go#199 + return strings.HasPrefix(path, string(sep)) +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/filepath/ancestor.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/filepath/ancestor.go new file mode 100644 index 0000000000..896cd82061 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/filepath/ancestor.go @@ -0,0 +1,32 @@ +package filepath + +import ( + "fmt" + "strings" +) + +// IsAncestor returns true when pathB is an strict ancestor of pathA, +// and false where the paths are equal or pathB is outside of pathA. +// Paths that are not absolute will be made absolute with Abs. +func IsAncestor(os, pathA, pathB, cwd string) (_ bool, err error) { + if pathA == pathB { + return false, nil + } + + pathA, err = Abs(os, pathA, cwd) + if err != nil { + return false, err + } + pathB, err = Abs(os, pathB, cwd) + if err != nil { + return false, err + } + sep := Separator(os) + if !strings.HasSuffix(pathA, string(sep)) { + pathA = fmt.Sprintf("%s%c", pathA, sep) + } + if pathA == pathB { + return false, nil + } + return strings.HasPrefix(pathB, pathA), nil +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/filepath/clean.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/filepath/clean.go new file mode 100644 index 0000000000..d5dd65ae12 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/filepath/clean.go @@ -0,0 +1,74 @@ +package filepath + +import ( + "fmt" + "strings" +) + +// Clean is an explicit-OS version of path/filepath's Clean. +func Clean(os, path string) string { + abs := IsAbs(os, path) + sep := Separator(os) + elements := strings.Split(path, string(sep)) + + // Replace multiple Separator elements with a single one. + for i := 0; i < len(elements); i++ { + if len(elements[i]) == 0 { + elements = append(elements[:i], elements[i+1:]...) + i-- + } + } + + // Eliminate each . path name element (the current directory). + for i := 0; i < len(elements); i++ { + if elements[i] == "." && len(elements) > 1 { + elements = append(elements[:i], elements[i+1:]...) + i-- + } + } + + // Eliminate each inner .. path name element (the parent directory) + // along with the non-.. element that precedes it. + for i := 1; i < len(elements); i++ { + if i == 1 && abs && sep == '\\' { + continue + } + if i > 0 && elements[i] == ".." { + elements = append(elements[:i-1], elements[i+1:]...) + i -= 2 + } + } + + // Eliminate .. elements that begin a rooted path: + // that is, replace "/.." by "/" at the beginning of a path, + // assuming Separator is '/'. + offset := 0 + if sep == '\\' { + offset = 1 + } + if abs { + for len(elements) > offset && elements[offset] == ".." { + elements = append(elements[:offset], elements[offset+1:]...) + } + } + + cleaned := strings.Join(elements, string(sep)) + if abs { + if sep == '/' { + cleaned = fmt.Sprintf("%c%s", sep, cleaned) + } else if len(elements) == 1 { + cleaned = fmt.Sprintf("%s%c", cleaned, sep) + } + } + + // If the result of this process is an empty string, Clean returns + // the string ".". + if len(cleaned) == 0 { + cleaned = "." + } + + if cleaned == path { + return path + } + return Clean(os, cleaned) +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/filepath/doc.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/filepath/doc.go new file mode 100644 index 0000000000..7ee085bf4e --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/filepath/doc.go @@ -0,0 +1,6 @@ +// Package filepath implements Go's filepath package with explicit +// operating systems (and for some functions and explicit working +// directory). This allows tools built for one OS to operate on paths +// targeting another OS. For example, a Linux build can determine +// whether a path is absolute on Linux or on Windows. +package filepath diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/filepath/join.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/filepath/join.go new file mode 100644 index 0000000000..b865d237cc --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/filepath/join.go @@ -0,0 +1,9 @@ +package filepath + +import "strings" + +// Join is an explicit-OS version of path/filepath's Join. +func Join(os string, elem ...string) string { + sep := Separator(os) + return Clean(os, strings.Join(elem, string(sep))) +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/filepath/separator.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/filepath/separator.go new file mode 100644 index 0000000000..2c5e8905a1 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/filepath/separator.go @@ -0,0 +1,9 @@ +package filepath + +// Separator is an explicit-OS version of path/filepath's Separator. +func Separator(os string) rune { + if os == "windows" { + return '\\' + } + return '/' +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/generate/config.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/generate/config.go new file mode 100644 index 0000000000..2f899999c2 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/generate/config.go @@ -0,0 +1,180 @@ +package generate + +import ( + rspec "github.com/opencontainers/runtime-spec/specs-go" +) + +func (g *Generator) initConfig() { + if g.Config == nil { + g.Config = &rspec.Spec{} + } +} + +func (g *Generator) initConfigProcess() { + g.initConfig() + if g.Config.Process == nil { + g.Config.Process = &rspec.Process{} + } +} + +func (g *Generator) initConfigProcessConsoleSize() { + g.initConfigProcess() + if g.Config.Process.ConsoleSize == nil { + g.Config.Process.ConsoleSize = &rspec.Box{} + } +} + +func (g *Generator) initConfigProcessCapabilities() { + g.initConfigProcess() + if g.Config.Process.Capabilities == nil { + g.Config.Process.Capabilities = &rspec.LinuxCapabilities{} + } +} + +func (g *Generator) initConfigRoot() { + g.initConfig() + if g.Config.Root == nil { + g.Config.Root = &rspec.Root{} + } +} + +func (g *Generator) initConfigAnnotations() { + g.initConfig() + if g.Config.Annotations == nil { + g.Config.Annotations = make(map[string]string) + } +} + +func (g *Generator) initConfigHooks() { + g.initConfig() + if g.Config.Hooks == nil { + g.Config.Hooks = &rspec.Hooks{} + } +} + +func (g *Generator) initConfigLinux() { + g.initConfig() + if g.Config.Linux == nil { + g.Config.Linux = &rspec.Linux{} + } +} + +func (g *Generator) initConfigLinuxIntelRdt() { + g.initConfigLinux() + if g.Config.Linux.IntelRdt == nil { + g.Config.Linux.IntelRdt = &rspec.LinuxIntelRdt{} + } +} + +func (g *Generator) initConfigLinuxSysctl() { + g.initConfigLinux() + if g.Config.Linux.Sysctl == nil { + g.Config.Linux.Sysctl = make(map[string]string) + } +} + +func (g *Generator) initConfigLinuxSeccomp() { + g.initConfigLinux() + if g.Config.Linux.Seccomp == nil { + g.Config.Linux.Seccomp = &rspec.LinuxSeccomp{} + } +} + +func (g *Generator) initConfigLinuxResources() { + g.initConfigLinux() + if g.Config.Linux.Resources == nil { + g.Config.Linux.Resources = &rspec.LinuxResources{} + } +} + +func (g *Generator) initConfigLinuxResourcesBlockIO() { + g.initConfigLinuxResources() + if g.Config.Linux.Resources.BlockIO == nil { + g.Config.Linux.Resources.BlockIO = &rspec.LinuxBlockIO{} + } +} + +// InitConfigLinuxResourcesCPU initializes CPU of Linux resources +func (g *Generator) InitConfigLinuxResourcesCPU() { + g.initConfigLinuxResources() + if g.Config.Linux.Resources.CPU == nil { + g.Config.Linux.Resources.CPU = &rspec.LinuxCPU{} + } +} + +func (g *Generator) initConfigLinuxResourcesMemory() { + g.initConfigLinuxResources() + if g.Config.Linux.Resources.Memory == nil { + g.Config.Linux.Resources.Memory = &rspec.LinuxMemory{} + } +} + +func (g *Generator) initConfigLinuxResourcesNetwork() { + g.initConfigLinuxResources() + if g.Config.Linux.Resources.Network == nil { + g.Config.Linux.Resources.Network = &rspec.LinuxNetwork{} + } +} + +func (g *Generator) initConfigLinuxResourcesPids() { + g.initConfigLinuxResources() + if g.Config.Linux.Resources.Pids == nil { + g.Config.Linux.Resources.Pids = &rspec.LinuxPids{} + } +} + +func (g *Generator) initConfigSolaris() { + g.initConfig() + if g.Config.Solaris == nil { + g.Config.Solaris = &rspec.Solaris{} + } +} + +func (g *Generator) initConfigSolarisCappedCPU() { + g.initConfigSolaris() + if g.Config.Solaris.CappedCPU == nil { + g.Config.Solaris.CappedCPU = &rspec.SolarisCappedCPU{} + } +} + +func (g *Generator) initConfigSolarisCappedMemory() { + g.initConfigSolaris() + if g.Config.Solaris.CappedMemory == nil { + g.Config.Solaris.CappedMemory = &rspec.SolarisCappedMemory{} + } +} + +func (g *Generator) initConfigWindows() { + g.initConfig() + if g.Config.Windows == nil { + g.Config.Windows = &rspec.Windows{} + } +} + +func (g *Generator) initConfigWindowsNetwork() { + g.initConfigWindows() + if g.Config.Windows.Network == nil { + g.Config.Windows.Network = &rspec.WindowsNetwork{} + } +} + +func (g *Generator) initConfigWindowsHyperV() { + g.initConfigWindows() + if g.Config.Windows.HyperV == nil { + g.Config.Windows.HyperV = &rspec.WindowsHyperV{} + } +} + +func (g *Generator) initConfigWindowsResources() { + g.initConfigWindows() + if g.Config.Windows.Resources == nil { + g.Config.Windows.Resources = &rspec.WindowsResources{} + } +} + +func (g *Generator) initConfigWindowsResourcesMemory() { + g.initConfigWindowsResources() + if g.Config.Windows.Resources.Memory == nil { + g.Config.Windows.Resources.Memory = &rspec.WindowsMemoryResources{} + } +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/generate/generate.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/generate/generate.go new file mode 100644 index 0000000000..5eb114f0d6 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/generate/generate.go @@ -0,0 +1,1588 @@ +// Package generate implements functions generating container config files. +package generate + +import ( + "encoding/json" + "fmt" + "io" + "os" + "strings" + + rspec "github.com/opencontainers/runtime-spec/specs-go" + "github.com/opencontainers/runtime-tools/generate/seccomp" + "github.com/opencontainers/runtime-tools/validate" + "github.com/syndtr/gocapability/capability" +) + +var ( + // Namespaces include the names of supported namespaces. + Namespaces = []string{"network", "pid", "mount", "ipc", "uts", "user", "cgroup"} + + // we don't care about order...and this is way faster... + removeFunc = func(s []string, i int) []string { + s[i] = s[len(s)-1] + return s[:len(s)-1] + } +) + +// Generator represents a generator for a container config. +type Generator struct { + Config *rspec.Spec + HostSpecific bool +} + +// ExportOptions have toggles for exporting only certain parts of the specification +type ExportOptions struct { + Seccomp bool // seccomp toggles if only seccomp should be exported +} + +// New creates a configuration Generator with the default +// configuration for the target operating system. +func New(os string) (generator Generator, err error) { + if os != "linux" && os != "solaris" && os != "windows" { + return generator, fmt.Errorf("no defaults configured for %s", os) + } + + config := rspec.Spec{ + Version: rspec.Version, + Hostname: "mrsdalloway", + } + + if os == "windows" { + config.Process = &rspec.Process{ + Args: []string{ + "cmd", + }, + Cwd: `C:\`, + ConsoleSize: &rspec.Box{ + Width: 80, + Height: 20, + }, + } + config.Windows = &rspec.Windows{ + IgnoreFlushesDuringBoot: true, + Network: &rspec.WindowsNetwork{ + AllowUnqualifiedDNSQuery: true, + }, + } + } else { + config.Root = &rspec.Root{ + Path: "rootfs", + Readonly: false, + } + config.Process = &rspec.Process{ + Terminal: false, + Args: []string{ + "sh", + }, + } + } + + if os == "linux" || os == "solaris" { + config.Process.User = rspec.User{} + config.Process.Env = []string{ + "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "TERM=xterm", + } + config.Process.Cwd = "/" + config.Process.Rlimits = []rspec.POSIXRlimit{ + { + Type: "RLIMIT_NOFILE", + Hard: uint64(1024), + Soft: uint64(1024), + }, + } + } + + if os == "linux" { + config.Process.Capabilities = &rspec.LinuxCapabilities{ + Bounding: []string{ + "CAP_CHOWN", + "CAP_DAC_OVERRIDE", + "CAP_FSETID", + "CAP_FOWNER", + "CAP_MKNOD", + "CAP_NET_RAW", + "CAP_SETGID", + "CAP_SETUID", + "CAP_SETFCAP", + "CAP_SETPCAP", + "CAP_NET_BIND_SERVICE", + "CAP_SYS_CHROOT", + "CAP_KILL", + "CAP_AUDIT_WRITE", + }, + Permitted: []string{ + "CAP_CHOWN", + "CAP_DAC_OVERRIDE", + "CAP_FSETID", + "CAP_FOWNER", + "CAP_MKNOD", + "CAP_NET_RAW", + "CAP_SETGID", + "CAP_SETUID", + "CAP_SETFCAP", + "CAP_SETPCAP", + "CAP_NET_BIND_SERVICE", + "CAP_SYS_CHROOT", + "CAP_KILL", + "CAP_AUDIT_WRITE", + }, + Inheritable: []string{ + "CAP_CHOWN", + "CAP_DAC_OVERRIDE", + "CAP_FSETID", + "CAP_FOWNER", + "CAP_MKNOD", + "CAP_NET_RAW", + "CAP_SETGID", + "CAP_SETUID", + "CAP_SETFCAP", + "CAP_SETPCAP", + "CAP_NET_BIND_SERVICE", + "CAP_SYS_CHROOT", + "CAP_KILL", + "CAP_AUDIT_WRITE", + }, + Effective: []string{ + "CAP_CHOWN", + "CAP_DAC_OVERRIDE", + "CAP_FSETID", + "CAP_FOWNER", + "CAP_MKNOD", + "CAP_NET_RAW", + "CAP_SETGID", + "CAP_SETUID", + "CAP_SETFCAP", + "CAP_SETPCAP", + "CAP_NET_BIND_SERVICE", + "CAP_SYS_CHROOT", + "CAP_KILL", + "CAP_AUDIT_WRITE", + }, + Ambient: []string{ + "CAP_CHOWN", + "CAP_DAC_OVERRIDE", + "CAP_FSETID", + "CAP_FOWNER", + "CAP_MKNOD", + "CAP_NET_RAW", + "CAP_SETGID", + "CAP_SETUID", + "CAP_SETFCAP", + "CAP_SETPCAP", + "CAP_NET_BIND_SERVICE", + "CAP_SYS_CHROOT", + "CAP_KILL", + "CAP_AUDIT_WRITE", + }, + } + config.Mounts = []rspec.Mount{ + { + Destination: "/proc", + Type: "proc", + Source: "proc", + Options: []string{"nosuid", "noexec", "nodev"}, + }, + { + Destination: "/dev", + Type: "tmpfs", + Source: "tmpfs", + Options: []string{"nosuid", "strictatime", "mode=755", "size=65536k"}, + }, + { + Destination: "/dev/pts", + Type: "devpts", + Source: "devpts", + Options: []string{"nosuid", "noexec", "newinstance", "ptmxmode=0666", "mode=0620", "gid=5"}, + }, + { + Destination: "/dev/shm", + Type: "tmpfs", + Source: "shm", + Options: []string{"nosuid", "noexec", "nodev", "mode=1777", "size=65536k"}, + }, + { + Destination: "/dev/mqueue", + Type: "mqueue", + Source: "mqueue", + Options: []string{"nosuid", "noexec", "nodev"}, + }, + { + Destination: "/sys", + Type: "sysfs", + Source: "sysfs", + Options: []string{"nosuid", "noexec", "nodev", "ro"}, + }, + } + config.Linux = &rspec.Linux{ + Resources: &rspec.LinuxResources{ + Devices: []rspec.LinuxDeviceCgroup{ + { + Allow: false, + Access: "rwm", + }, + }, + }, + Namespaces: []rspec.LinuxNamespace{ + { + Type: "pid", + }, + { + Type: "network", + }, + { + Type: "ipc", + }, + { + Type: "uts", + }, + { + Type: "mount", + }, + }, + Seccomp: seccomp.DefaultProfile(&config), + } + } + + return Generator{Config: &config}, nil +} + +// NewFromSpec creates a configuration Generator from a given +// configuration. +// +// Deprecated: Replace with: +// +// generator := Generator{Config: config} +func NewFromSpec(config *rspec.Spec) Generator { + return Generator{ + Config: config, + } +} + +// NewFromFile loads the template specified in a file into a +// configuration Generator. +func NewFromFile(path string) (Generator, error) { + cf, err := os.Open(path) + if err != nil { + if os.IsNotExist(err) { + return Generator{}, fmt.Errorf("template configuration at %s not found", path) + } + return Generator{}, err + } + defer cf.Close() + + return NewFromTemplate(cf) +} + +// NewFromTemplate loads the template from io.Reader into a +// configuration Generator. +func NewFromTemplate(r io.Reader) (Generator, error) { + var config rspec.Spec + if err := json.NewDecoder(r).Decode(&config); err != nil { + return Generator{}, err + } + return Generator{ + Config: &config, + }, nil +} + +// SetSpec sets the configuration in the Generator g. +// +// Deprecated: Replace with: +// +// Use generator.Config = config +func (g *Generator) SetSpec(config *rspec.Spec) { + g.Config = config +} + +// Spec gets the configuration from the Generator g. +// +// Deprecated: Replace with generator.Config. +func (g *Generator) Spec() *rspec.Spec { + return g.Config +} + +// Save writes the configuration into w. +func (g *Generator) Save(w io.Writer, exportOpts ExportOptions) (err error) { + var data []byte + + if g.Config.Linux != nil { + buf, err := json.Marshal(g.Config.Linux) + if err != nil { + return err + } + if string(buf) == "{}" { + g.Config.Linux = nil + } + } + + if exportOpts.Seccomp { + data, err = json.MarshalIndent(g.Config.Linux.Seccomp, "", "\t") + } else { + data, err = json.MarshalIndent(g.Config, "", "\t") + } + if err != nil { + return err + } + + _, err = w.Write(data) + if err != nil { + return err + } + + return nil +} + +// SaveToFile writes the configuration into a file. +func (g *Generator) SaveToFile(path string, exportOpts ExportOptions) error { + f, err := os.Create(path) + if err != nil { + return err + } + defer f.Close() + return g.Save(f, exportOpts) +} + +// SetVersion sets g.Config.Version. +func (g *Generator) SetVersion(version string) { + g.initConfig() + g.Config.Version = version +} + +// SetRootPath sets g.Config.Root.Path. +func (g *Generator) SetRootPath(path string) { + g.initConfigRoot() + g.Config.Root.Path = path +} + +// SetRootReadonly sets g.Config.Root.Readonly. +func (g *Generator) SetRootReadonly(b bool) { + g.initConfigRoot() + g.Config.Root.Readonly = b +} + +// SetHostname sets g.Config.Hostname. +func (g *Generator) SetHostname(s string) { + g.initConfig() + g.Config.Hostname = s +} + +// ClearAnnotations clears g.Config.Annotations. +func (g *Generator) ClearAnnotations() { + if g.Config == nil { + return + } + g.Config.Annotations = make(map[string]string) +} + +// AddAnnotation adds an annotation into g.Config.Annotations. +func (g *Generator) AddAnnotation(key, value string) { + g.initConfigAnnotations() + g.Config.Annotations[key] = value +} + +// RemoveAnnotation remove an annotation from g.Config.Annotations. +func (g *Generator) RemoveAnnotation(key string) { + if g.Config == nil || g.Config.Annotations == nil { + return + } + delete(g.Config.Annotations, key) +} + +// RemoveHostname removes g.Config.Hostname, setting it to an empty string. +func (g *Generator) RemoveHostname() { + if g.Config == nil { + return + } + g.Config.Hostname = "" +} + +// SetProcessConsoleSize sets g.Config.Process.ConsoleSize. +func (g *Generator) SetProcessConsoleSize(width, height uint) { + g.initConfigProcessConsoleSize() + g.Config.Process.ConsoleSize.Width = width + g.Config.Process.ConsoleSize.Height = height +} + +// SetProcessUID sets g.Config.Process.User.UID. +func (g *Generator) SetProcessUID(uid uint32) { + g.initConfigProcess() + g.Config.Process.User.UID = uid +} + +// SetProcessUsername sets g.Config.Process.User.Username. +func (g *Generator) SetProcessUsername(username string) { + g.initConfigProcess() + g.Config.Process.User.Username = username +} + +// SetProcessGID sets g.Config.Process.User.GID. +func (g *Generator) SetProcessGID(gid uint32) { + g.initConfigProcess() + g.Config.Process.User.GID = gid +} + +// SetProcessCwd sets g.Config.Process.Cwd. +func (g *Generator) SetProcessCwd(cwd string) { + g.initConfigProcess() + g.Config.Process.Cwd = cwd +} + +// SetProcessNoNewPrivileges sets g.Config.Process.NoNewPrivileges. +func (g *Generator) SetProcessNoNewPrivileges(b bool) { + g.initConfigProcess() + g.Config.Process.NoNewPrivileges = b +} + +// SetProcessTerminal sets g.Config.Process.Terminal. +func (g *Generator) SetProcessTerminal(b bool) { + g.initConfigProcess() + g.Config.Process.Terminal = b +} + +// SetProcessApparmorProfile sets g.Config.Process.ApparmorProfile. +func (g *Generator) SetProcessApparmorProfile(prof string) { + g.initConfigProcess() + g.Config.Process.ApparmorProfile = prof +} + +// SetProcessArgs sets g.Config.Process.Args. +func (g *Generator) SetProcessArgs(args []string) { + g.initConfigProcess() + g.Config.Process.Args = args +} + +// ClearProcessEnv clears g.Config.Process.Env. +func (g *Generator) ClearProcessEnv() { + if g.Config == nil || g.Config.Process == nil { + return + } + g.Config.Process.Env = []string{} +} + +// AddProcessEnv adds name=value into g.Config.Process.Env, or replaces an +// existing entry with the given name. +func (g *Generator) AddProcessEnv(name, value string) { + g.initConfigProcess() + + env := fmt.Sprintf("%s=%s", name, value) + for idx := range g.Config.Process.Env { + if strings.HasPrefix(g.Config.Process.Env[idx], name+"=") { + g.Config.Process.Env[idx] = env + return + } + } + g.Config.Process.Env = append(g.Config.Process.Env, env) +} + +// AddProcessRlimits adds rlimit into g.Config.Process.Rlimits. +func (g *Generator) AddProcessRlimits(rType string, rHard uint64, rSoft uint64) { + g.initConfigProcess() + for i, rlimit := range g.Config.Process.Rlimits { + if rlimit.Type == rType { + g.Config.Process.Rlimits[i].Hard = rHard + g.Config.Process.Rlimits[i].Soft = rSoft + return + } + } + + newRlimit := rspec.POSIXRlimit{ + Type: rType, + Hard: rHard, + Soft: rSoft, + } + g.Config.Process.Rlimits = append(g.Config.Process.Rlimits, newRlimit) +} + +// RemoveProcessRlimits removes a rlimit from g.Config.Process.Rlimits. +func (g *Generator) RemoveProcessRlimits(rType string) { + if g.Config == nil || g.Config.Process == nil { + return + } + for i, rlimit := range g.Config.Process.Rlimits { + if rlimit.Type == rType { + g.Config.Process.Rlimits = append(g.Config.Process.Rlimits[:i], g.Config.Process.Rlimits[i+1:]...) + return + } + } +} + +// ClearProcessRlimits clear g.Config.Process.Rlimits. +func (g *Generator) ClearProcessRlimits() { + if g.Config == nil || g.Config.Process == nil { + return + } + g.Config.Process.Rlimits = []rspec.POSIXRlimit{} +} + +// ClearProcessAdditionalGids clear g.Config.Process.AdditionalGids. +func (g *Generator) ClearProcessAdditionalGids() { + if g.Config == nil || g.Config.Process == nil { + return + } + g.Config.Process.User.AdditionalGids = []uint32{} +} + +// AddProcessAdditionalGid adds an additional gid into g.Config.Process.AdditionalGids. +func (g *Generator) AddProcessAdditionalGid(gid uint32) { + g.initConfigProcess() + for _, group := range g.Config.Process.User.AdditionalGids { + if group == gid { + return + } + } + g.Config.Process.User.AdditionalGids = append(g.Config.Process.User.AdditionalGids, gid) +} + +// SetProcessSelinuxLabel sets g.Config.Process.SelinuxLabel. +func (g *Generator) SetProcessSelinuxLabel(label string) { + g.initConfigProcess() + g.Config.Process.SelinuxLabel = label +} + +// SetLinuxCgroupsPath sets g.Config.Linux.CgroupsPath. +func (g *Generator) SetLinuxCgroupsPath(path string) { + g.initConfigLinux() + g.Config.Linux.CgroupsPath = path +} + +// SetLinuxIntelRdtL3CacheSchema sets g.Config.Linux.IntelRdt.L3CacheSchema +func (g *Generator) SetLinuxIntelRdtL3CacheSchema(schema string) { + g.initConfigLinuxIntelRdt() + g.Config.Linux.IntelRdt.L3CacheSchema = schema +} + +// SetLinuxMountLabel sets g.Config.Linux.MountLabel. +func (g *Generator) SetLinuxMountLabel(label string) { + g.initConfigLinux() + g.Config.Linux.MountLabel = label +} + +// SetProcessOOMScoreAdj sets g.Config.Process.OOMScoreAdj. +func (g *Generator) SetProcessOOMScoreAdj(adj int) { + g.initConfigProcess() + g.Config.Process.OOMScoreAdj = &adj +} + +// SetLinuxResourcesBlockIOLeafWeight sets g.Config.Linux.Resources.BlockIO.LeafWeight. +func (g *Generator) SetLinuxResourcesBlockIOLeafWeight(weight uint16) { + g.initConfigLinuxResourcesBlockIO() + g.Config.Linux.Resources.BlockIO.LeafWeight = &weight +} + +// AddLinuxResourcesBlockIOLeafWeightDevice adds or sets g.Config.Linux.Resources.BlockIO.WeightDevice.LeafWeight. +func (g *Generator) AddLinuxResourcesBlockIOLeafWeightDevice(major int64, minor int64, weight uint16) { + g.initConfigLinuxResourcesBlockIO() + for i, weightDevice := range g.Config.Linux.Resources.BlockIO.WeightDevice { + if weightDevice.Major == major && weightDevice.Minor == minor { + g.Config.Linux.Resources.BlockIO.WeightDevice[i].LeafWeight = &weight + return + } + } + weightDevice := new(rspec.LinuxWeightDevice) + weightDevice.Major = major + weightDevice.Minor = minor + weightDevice.LeafWeight = &weight + g.Config.Linux.Resources.BlockIO.WeightDevice = append(g.Config.Linux.Resources.BlockIO.WeightDevice, *weightDevice) +} + +// DropLinuxResourcesBlockIOLeafWeightDevice drops a item form g.Config.Linux.Resources.BlockIO.WeightDevice.LeafWeight +func (g *Generator) DropLinuxResourcesBlockIOLeafWeightDevice(major int64, minor int64) { + if g.Config == nil || g.Config.Linux == nil || g.Config.Linux.Resources == nil || g.Config.Linux.Resources.BlockIO == nil { + return + } + + for i, weightDevice := range g.Config.Linux.Resources.BlockIO.WeightDevice { + if weightDevice.Major == major && weightDevice.Minor == minor { + if weightDevice.Weight != nil { + newWeightDevice := new(rspec.LinuxWeightDevice) + newWeightDevice.Major = major + newWeightDevice.Minor = minor + newWeightDevice.Weight = weightDevice.Weight + g.Config.Linux.Resources.BlockIO.WeightDevice[i] = *newWeightDevice + } else { + g.Config.Linux.Resources.BlockIO.WeightDevice = append(g.Config.Linux.Resources.BlockIO.WeightDevice[:i], g.Config.Linux.Resources.BlockIO.WeightDevice[i+1:]...) + } + return + } + } +} + +// SetLinuxResourcesBlockIOWeight sets g.Config.Linux.Resources.BlockIO.Weight. +func (g *Generator) SetLinuxResourcesBlockIOWeight(weight uint16) { + g.initConfigLinuxResourcesBlockIO() + g.Config.Linux.Resources.BlockIO.Weight = &weight +} + +// AddLinuxResourcesBlockIOWeightDevice adds or sets g.Config.Linux.Resources.BlockIO.WeightDevice.Weight. +func (g *Generator) AddLinuxResourcesBlockIOWeightDevice(major int64, minor int64, weight uint16) { + g.initConfigLinuxResourcesBlockIO() + for i, weightDevice := range g.Config.Linux.Resources.BlockIO.WeightDevice { + if weightDevice.Major == major && weightDevice.Minor == minor { + g.Config.Linux.Resources.BlockIO.WeightDevice[i].Weight = &weight + return + } + } + weightDevice := new(rspec.LinuxWeightDevice) + weightDevice.Major = major + weightDevice.Minor = minor + weightDevice.Weight = &weight + g.Config.Linux.Resources.BlockIO.WeightDevice = append(g.Config.Linux.Resources.BlockIO.WeightDevice, *weightDevice) +} + +// DropLinuxResourcesBlockIOWeightDevice drops a item form g.Config.Linux.Resources.BlockIO.WeightDevice.Weight +func (g *Generator) DropLinuxResourcesBlockIOWeightDevice(major int64, minor int64) { + if g.Config == nil || g.Config.Linux == nil || g.Config.Linux.Resources == nil || g.Config.Linux.Resources.BlockIO == nil { + return + } + + for i, weightDevice := range g.Config.Linux.Resources.BlockIO.WeightDevice { + if weightDevice.Major == major && weightDevice.Minor == minor { + if weightDevice.LeafWeight != nil { + newWeightDevice := new(rspec.LinuxWeightDevice) + newWeightDevice.Major = major + newWeightDevice.Minor = minor + newWeightDevice.LeafWeight = weightDevice.LeafWeight + g.Config.Linux.Resources.BlockIO.WeightDevice[i] = *newWeightDevice + } else { + g.Config.Linux.Resources.BlockIO.WeightDevice = append(g.Config.Linux.Resources.BlockIO.WeightDevice[:i], g.Config.Linux.Resources.BlockIO.WeightDevice[i+1:]...) + } + return + } + } +} + +// AddLinuxResourcesBlockIOThrottleReadBpsDevice adds or sets g.Config.Linux.Resources.BlockIO.ThrottleReadBpsDevice. +func (g *Generator) AddLinuxResourcesBlockIOThrottleReadBpsDevice(major int64, minor int64, rate uint64) { + g.initConfigLinuxResourcesBlockIO() + throttleDevices := addOrReplaceBlockIOThrottleDevice(g.Config.Linux.Resources.BlockIO.ThrottleReadBpsDevice, major, minor, rate) + g.Config.Linux.Resources.BlockIO.ThrottleReadBpsDevice = throttleDevices +} + +// DropLinuxResourcesBlockIOThrottleReadBpsDevice drops a item from g.Config.Linux.Resources.BlockIO.ThrottleReadBpsDevice. +func (g *Generator) DropLinuxResourcesBlockIOThrottleReadBpsDevice(major int64, minor int64) { + if g.Config == nil || g.Config.Linux == nil || g.Config.Linux.Resources == nil || g.Config.Linux.Resources.BlockIO == nil { + return + } + + throttleDevices := dropBlockIOThrottleDevice(g.Config.Linux.Resources.BlockIO.ThrottleReadBpsDevice, major, minor) + g.Config.Linux.Resources.BlockIO.ThrottleReadBpsDevice = throttleDevices +} + +// AddLinuxResourcesBlockIOThrottleReadIOPSDevice adds or sets g.Config.Linux.Resources.BlockIO.ThrottleReadIOPSDevice. +func (g *Generator) AddLinuxResourcesBlockIOThrottleReadIOPSDevice(major int64, minor int64, rate uint64) { + g.initConfigLinuxResourcesBlockIO() + throttleDevices := addOrReplaceBlockIOThrottleDevice(g.Config.Linux.Resources.BlockIO.ThrottleReadIOPSDevice, major, minor, rate) + g.Config.Linux.Resources.BlockIO.ThrottleReadIOPSDevice = throttleDevices +} + +// DropLinuxResourcesBlockIOThrottleReadIOPSDevice drops a item from g.Config.Linux.Resources.BlockIO.ThrottleReadIOPSDevice. +func (g *Generator) DropLinuxResourcesBlockIOThrottleReadIOPSDevice(major int64, minor int64) { + if g.Config == nil || g.Config.Linux == nil || g.Config.Linux.Resources == nil || g.Config.Linux.Resources.BlockIO == nil { + return + } + + throttleDevices := dropBlockIOThrottleDevice(g.Config.Linux.Resources.BlockIO.ThrottleReadIOPSDevice, major, minor) + g.Config.Linux.Resources.BlockIO.ThrottleReadIOPSDevice = throttleDevices +} + +// AddLinuxResourcesBlockIOThrottleWriteBpsDevice adds or sets g.Config.Linux.Resources.BlockIO.ThrottleWriteBpsDevice. +func (g *Generator) AddLinuxResourcesBlockIOThrottleWriteBpsDevice(major int64, minor int64, rate uint64) { + g.initConfigLinuxResourcesBlockIO() + throttleDevices := addOrReplaceBlockIOThrottleDevice(g.Config.Linux.Resources.BlockIO.ThrottleWriteBpsDevice, major, minor, rate) + g.Config.Linux.Resources.BlockIO.ThrottleWriteBpsDevice = throttleDevices +} + +// DropLinuxResourcesBlockIOThrottleWriteBpsDevice drops a item from g.Config.Linux.Resources.BlockIO.ThrottleWriteBpsDevice. +func (g *Generator) DropLinuxResourcesBlockIOThrottleWriteBpsDevice(major int64, minor int64) { + if g.Config == nil || g.Config.Linux == nil || g.Config.Linux.Resources == nil || g.Config.Linux.Resources.BlockIO == nil { + return + } + + throttleDevices := dropBlockIOThrottleDevice(g.Config.Linux.Resources.BlockIO.ThrottleWriteBpsDevice, major, minor) + g.Config.Linux.Resources.BlockIO.ThrottleWriteBpsDevice = throttleDevices +} + +// AddLinuxResourcesBlockIOThrottleWriteIOPSDevice adds or sets g.Config.Linux.Resources.BlockIO.ThrottleWriteIOPSDevice. +func (g *Generator) AddLinuxResourcesBlockIOThrottleWriteIOPSDevice(major int64, minor int64, rate uint64) { + g.initConfigLinuxResourcesBlockIO() + throttleDevices := addOrReplaceBlockIOThrottleDevice(g.Config.Linux.Resources.BlockIO.ThrottleWriteIOPSDevice, major, minor, rate) + g.Config.Linux.Resources.BlockIO.ThrottleWriteIOPSDevice = throttleDevices +} + +// DropLinuxResourcesBlockIOThrottleWriteIOPSDevice drops a item from g.Config.Linux.Resources.BlockIO.ThrottleWriteIOPSDevice. +func (g *Generator) DropLinuxResourcesBlockIOThrottleWriteIOPSDevice(major int64, minor int64) { + if g.Config == nil || g.Config.Linux == nil || g.Config.Linux.Resources == nil || g.Config.Linux.Resources.BlockIO == nil { + return + } + + throttleDevices := dropBlockIOThrottleDevice(g.Config.Linux.Resources.BlockIO.ThrottleWriteIOPSDevice, major, minor) + g.Config.Linux.Resources.BlockIO.ThrottleWriteIOPSDevice = throttleDevices +} + +// SetLinuxResourcesCPUShares sets g.Config.Linux.Resources.CPU.Shares. +func (g *Generator) SetLinuxResourcesCPUShares(shares uint64) { + g.InitConfigLinuxResourcesCPU() + g.Config.Linux.Resources.CPU.Shares = &shares +} + +// SetLinuxResourcesCPUQuota sets g.Config.Linux.Resources.CPU.Quota. +func (g *Generator) SetLinuxResourcesCPUQuota(quota int64) { + g.InitConfigLinuxResourcesCPU() + g.Config.Linux.Resources.CPU.Quota = "a +} + +// SetLinuxResourcesCPUPeriod sets g.Config.Linux.Resources.CPU.Period. +func (g *Generator) SetLinuxResourcesCPUPeriod(period uint64) { + g.InitConfigLinuxResourcesCPU() + g.Config.Linux.Resources.CPU.Period = &period +} + +// SetLinuxResourcesCPURealtimeRuntime sets g.Config.Linux.Resources.CPU.RealtimeRuntime. +func (g *Generator) SetLinuxResourcesCPURealtimeRuntime(time int64) { + g.InitConfigLinuxResourcesCPU() + g.Config.Linux.Resources.CPU.RealtimeRuntime = &time +} + +// SetLinuxResourcesCPURealtimePeriod sets g.Config.Linux.Resources.CPU.RealtimePeriod. +func (g *Generator) SetLinuxResourcesCPURealtimePeriod(period uint64) { + g.InitConfigLinuxResourcesCPU() + g.Config.Linux.Resources.CPU.RealtimePeriod = &period +} + +// SetLinuxResourcesCPUCpus sets g.Config.Linux.Resources.CPU.Cpus. +func (g *Generator) SetLinuxResourcesCPUCpus(cpus string) { + g.InitConfigLinuxResourcesCPU() + g.Config.Linux.Resources.CPU.Cpus = cpus +} + +// SetLinuxResourcesCPUMems sets g.Config.Linux.Resources.CPU.Mems. +func (g *Generator) SetLinuxResourcesCPUMems(mems string) { + g.InitConfigLinuxResourcesCPU() + g.Config.Linux.Resources.CPU.Mems = mems +} + +// AddLinuxResourcesHugepageLimit adds or sets g.Config.Linux.Resources.HugepageLimits. +func (g *Generator) AddLinuxResourcesHugepageLimit(pageSize string, limit uint64) { + hugepageLimit := rspec.LinuxHugepageLimit{ + Pagesize: pageSize, + Limit: limit, + } + + g.initConfigLinuxResources() + for i, pageLimit := range g.Config.Linux.Resources.HugepageLimits { + if pageLimit.Pagesize == pageSize { + g.Config.Linux.Resources.HugepageLimits[i].Limit = limit + return + } + } + g.Config.Linux.Resources.HugepageLimits = append(g.Config.Linux.Resources.HugepageLimits, hugepageLimit) +} + +// DropLinuxResourcesHugepageLimit drops a hugepage limit from g.Config.Linux.Resources.HugepageLimits. +func (g *Generator) DropLinuxResourcesHugepageLimit(pageSize string) { + if g.Config == nil || g.Config.Linux == nil || g.Config.Linux.Resources == nil { + return + } + + for i, pageLimit := range g.Config.Linux.Resources.HugepageLimits { + if pageLimit.Pagesize == pageSize { + g.Config.Linux.Resources.HugepageLimits = append(g.Config.Linux.Resources.HugepageLimits[:i], g.Config.Linux.Resources.HugepageLimits[i+1:]...) + return + } + } +} + +// SetLinuxResourcesMemoryLimit sets g.Config.Linux.Resources.Memory.Limit. +func (g *Generator) SetLinuxResourcesMemoryLimit(limit int64) { + g.initConfigLinuxResourcesMemory() + g.Config.Linux.Resources.Memory.Limit = &limit +} + +// SetLinuxResourcesMemoryReservation sets g.Config.Linux.Resources.Memory.Reservation. +func (g *Generator) SetLinuxResourcesMemoryReservation(reservation int64) { + g.initConfigLinuxResourcesMemory() + g.Config.Linux.Resources.Memory.Reservation = &reservation +} + +// SetLinuxResourcesMemorySwap sets g.Config.Linux.Resources.Memory.Swap. +func (g *Generator) SetLinuxResourcesMemorySwap(swap int64) { + g.initConfigLinuxResourcesMemory() + g.Config.Linux.Resources.Memory.Swap = &swap +} + +// SetLinuxResourcesMemoryKernel sets g.Config.Linux.Resources.Memory.Kernel. +func (g *Generator) SetLinuxResourcesMemoryKernel(kernel int64) { + g.initConfigLinuxResourcesMemory() + g.Config.Linux.Resources.Memory.Kernel = &kernel +} + +// SetLinuxResourcesMemoryKernelTCP sets g.Config.Linux.Resources.Memory.KernelTCP. +func (g *Generator) SetLinuxResourcesMemoryKernelTCP(kernelTCP int64) { + g.initConfigLinuxResourcesMemory() + g.Config.Linux.Resources.Memory.KernelTCP = &kernelTCP +} + +// SetLinuxResourcesMemorySwappiness sets g.Config.Linux.Resources.Memory.Swappiness. +func (g *Generator) SetLinuxResourcesMemorySwappiness(swappiness uint64) { + g.initConfigLinuxResourcesMemory() + g.Config.Linux.Resources.Memory.Swappiness = &swappiness +} + +// SetLinuxResourcesMemoryDisableOOMKiller sets g.Config.Linux.Resources.Memory.DisableOOMKiller. +func (g *Generator) SetLinuxResourcesMemoryDisableOOMKiller(disable bool) { + g.initConfigLinuxResourcesMemory() + g.Config.Linux.Resources.Memory.DisableOOMKiller = &disable +} + +// SetLinuxResourcesNetworkClassID sets g.Config.Linux.Resources.Network.ClassID. +func (g *Generator) SetLinuxResourcesNetworkClassID(classid uint32) { + g.initConfigLinuxResourcesNetwork() + g.Config.Linux.Resources.Network.ClassID = &classid +} + +// AddLinuxResourcesNetworkPriorities adds or sets g.Config.Linux.Resources.Network.Priorities. +func (g *Generator) AddLinuxResourcesNetworkPriorities(name string, prio uint32) { + g.initConfigLinuxResourcesNetwork() + for i, netPriority := range g.Config.Linux.Resources.Network.Priorities { + if netPriority.Name == name { + g.Config.Linux.Resources.Network.Priorities[i].Priority = prio + return + } + } + interfacePrio := new(rspec.LinuxInterfacePriority) + interfacePrio.Name = name + interfacePrio.Priority = prio + g.Config.Linux.Resources.Network.Priorities = append(g.Config.Linux.Resources.Network.Priorities, *interfacePrio) +} + +// DropLinuxResourcesNetworkPriorities drops one item from g.Config.Linux.Resources.Network.Priorities. +func (g *Generator) DropLinuxResourcesNetworkPriorities(name string) { + if g.Config == nil || g.Config.Linux == nil || g.Config.Linux.Resources == nil || g.Config.Linux.Resources.Network == nil { + return + } + + for i, netPriority := range g.Config.Linux.Resources.Network.Priorities { + if netPriority.Name == name { + g.Config.Linux.Resources.Network.Priorities = append(g.Config.Linux.Resources.Network.Priorities[:i], g.Config.Linux.Resources.Network.Priorities[i+1:]...) + return + } + } +} + +// SetLinuxResourcesPidsLimit sets g.Config.Linux.Resources.Pids.Limit. +func (g *Generator) SetLinuxResourcesPidsLimit(limit int64) { + g.initConfigLinuxResourcesPids() + g.Config.Linux.Resources.Pids.Limit = limit +} + +// ClearLinuxSysctl clears g.Config.Linux.Sysctl. +func (g *Generator) ClearLinuxSysctl() { + if g.Config == nil || g.Config.Linux == nil { + return + } + g.Config.Linux.Sysctl = make(map[string]string) +} + +// AddLinuxSysctl adds a new sysctl config into g.Config.Linux.Sysctl. +func (g *Generator) AddLinuxSysctl(key, value string) { + g.initConfigLinuxSysctl() + g.Config.Linux.Sysctl[key] = value +} + +// RemoveLinuxSysctl removes a sysctl config from g.Config.Linux.Sysctl. +func (g *Generator) RemoveLinuxSysctl(key string) { + if g.Config == nil || g.Config.Linux == nil || g.Config.Linux.Sysctl == nil { + return + } + delete(g.Config.Linux.Sysctl, key) +} + +// ClearLinuxUIDMappings clear g.Config.Linux.UIDMappings. +func (g *Generator) ClearLinuxUIDMappings() { + if g.Config == nil || g.Config.Linux == nil { + return + } + g.Config.Linux.UIDMappings = []rspec.LinuxIDMapping{} +} + +// AddLinuxUIDMapping adds uidMap into g.Config.Linux.UIDMappings. +func (g *Generator) AddLinuxUIDMapping(hid, cid, size uint32) { + idMapping := rspec.LinuxIDMapping{ + HostID: hid, + ContainerID: cid, + Size: size, + } + + g.initConfigLinux() + g.Config.Linux.UIDMappings = append(g.Config.Linux.UIDMappings, idMapping) +} + +// ClearLinuxGIDMappings clear g.Config.Linux.GIDMappings. +func (g *Generator) ClearLinuxGIDMappings() { + if g.Config == nil || g.Config.Linux == nil { + return + } + g.Config.Linux.GIDMappings = []rspec.LinuxIDMapping{} +} + +// AddLinuxGIDMapping adds gidMap into g.Config.Linux.GIDMappings. +func (g *Generator) AddLinuxGIDMapping(hid, cid, size uint32) { + idMapping := rspec.LinuxIDMapping{ + HostID: hid, + ContainerID: cid, + Size: size, + } + + g.initConfigLinux() + g.Config.Linux.GIDMappings = append(g.Config.Linux.GIDMappings, idMapping) +} + +// SetLinuxRootPropagation sets g.Config.Linux.RootfsPropagation. +func (g *Generator) SetLinuxRootPropagation(rp string) error { + switch rp { + case "": + case "private": + case "rprivate": + case "slave": + case "rslave": + case "shared": + case "rshared": + case "unbindable": + case "runbindable": + default: + return fmt.Errorf("rootfs-propagation %q must be empty or one of (r)private|(r)slave|(r)shared|(r)unbindable", rp) + } + g.initConfigLinux() + g.Config.Linux.RootfsPropagation = rp + return nil +} + +// ClearPreStartHooks clear g.Config.Hooks.Prestart. +func (g *Generator) ClearPreStartHooks() { + if g.Config == nil || g.Config.Hooks == nil { + return + } + g.Config.Hooks.Prestart = []rspec.Hook{} +} + +// AddPreStartHook add a prestart hook into g.Config.Hooks.Prestart. +func (g *Generator) AddPreStartHook(preStartHook rspec.Hook) error { + g.initConfigHooks() + g.Config.Hooks.Prestart = append(g.Config.Hooks.Prestart, preStartHook) + return nil +} + +// ClearPostStopHooks clear g.Config.Hooks.Poststop. +func (g *Generator) ClearPostStopHooks() { + if g.Config == nil || g.Config.Hooks == nil { + return + } + g.Config.Hooks.Poststop = []rspec.Hook{} +} + +// AddPostStopHook adds a poststop hook into g.Config.Hooks.Poststop. +func (g *Generator) AddPostStopHook(postStopHook rspec.Hook) error { + g.initConfigHooks() + g.Config.Hooks.Poststop = append(g.Config.Hooks.Poststop, postStopHook) + return nil +} + +// ClearPostStartHooks clear g.Config.Hooks.Poststart. +func (g *Generator) ClearPostStartHooks() { + if g.Config == nil || g.Config.Hooks == nil { + return + } + g.Config.Hooks.Poststart = []rspec.Hook{} +} + +// AddPostStartHook adds a poststart hook into g.Config.Hooks.Poststart. +func (g *Generator) AddPostStartHook(postStartHook rspec.Hook) error { + g.initConfigHooks() + g.Config.Hooks.Poststart = append(g.Config.Hooks.Poststart, postStartHook) + return nil +} + +// AddMount adds a mount into g.Config.Mounts. +func (g *Generator) AddMount(mnt rspec.Mount) { + g.initConfig() + + g.Config.Mounts = append(g.Config.Mounts, mnt) +} + +// RemoveMount removes a mount point on the dest directory +func (g *Generator) RemoveMount(dest string) { + g.initConfig() + + for index, mount := range g.Config.Mounts { + if mount.Destination == dest { + g.Config.Mounts = append(g.Config.Mounts[:index], g.Config.Mounts[index+1:]...) + return + } + } +} + +// Mounts returns the list of mounts +func (g *Generator) Mounts() []rspec.Mount { + g.initConfig() + + return g.Config.Mounts +} + +// ClearMounts clear g.Config.Mounts +func (g *Generator) ClearMounts() { + if g.Config == nil { + return + } + g.Config.Mounts = []rspec.Mount{} +} + +// SetupPrivileged sets up the privilege-related fields inside g.Config. +func (g *Generator) SetupPrivileged(privileged bool) { + if privileged { // Add all capabilities in privileged mode. + var finalCapList []string + for _, cap := range capability.List() { + if g.HostSpecific && cap > validate.LastCap() { + continue + } + finalCapList = append(finalCapList, fmt.Sprintf("CAP_%s", strings.ToUpper(cap.String()))) + } + g.initConfigLinux() + g.initConfigProcessCapabilities() + g.ClearProcessCapabilities() + g.Config.Process.Capabilities.Bounding = append(g.Config.Process.Capabilities.Bounding, finalCapList...) + g.Config.Process.Capabilities.Effective = append(g.Config.Process.Capabilities.Effective, finalCapList...) + g.Config.Process.Capabilities.Inheritable = append(g.Config.Process.Capabilities.Inheritable, finalCapList...) + g.Config.Process.Capabilities.Permitted = append(g.Config.Process.Capabilities.Permitted, finalCapList...) + g.Config.Process.Capabilities.Ambient = append(g.Config.Process.Capabilities.Ambient, finalCapList...) + g.Config.Process.SelinuxLabel = "" + g.Config.Process.ApparmorProfile = "" + g.Config.Linux.Seccomp = nil + } +} + +// ClearProcessCapabilities clear g.Config.Process.Capabilities. +func (g *Generator) ClearProcessCapabilities() { + if g.Config == nil || g.Config.Process == nil || g.Config.Process.Capabilities == nil { + return + } + g.Config.Process.Capabilities.Bounding = []string{} + g.Config.Process.Capabilities.Effective = []string{} + g.Config.Process.Capabilities.Inheritable = []string{} + g.Config.Process.Capabilities.Permitted = []string{} + g.Config.Process.Capabilities.Ambient = []string{} +} + +// AddProcessCapabilityAmbient adds a process capability into g.Config.Process.Capabilities.Ambient. +func (g *Generator) AddProcessCapabilityAmbient(c string) error { + cp := strings.ToUpper(c) + if err := validate.CapValid(cp, g.HostSpecific); err != nil { + return err + } + + g.initConfigProcessCapabilities() + + var foundAmbient bool + for _, cap := range g.Config.Process.Capabilities.Ambient { + if strings.ToUpper(cap) == cp { + foundAmbient = true + break + } + } + + if !foundAmbient { + g.Config.Process.Capabilities.Ambient = append(g.Config.Process.Capabilities.Ambient, cp) + } + + return nil +} + +// AddProcessCapabilityBounding adds a process capability into g.Config.Process.Capabilities.Bounding. +func (g *Generator) AddProcessCapabilityBounding(c string) error { + cp := strings.ToUpper(c) + if err := validate.CapValid(cp, g.HostSpecific); err != nil { + return err + } + + g.initConfigProcessCapabilities() + + var foundBounding bool + for _, cap := range g.Config.Process.Capabilities.Bounding { + if strings.ToUpper(cap) == cp { + foundBounding = true + break + } + } + if !foundBounding { + g.Config.Process.Capabilities.Bounding = append(g.Config.Process.Capabilities.Bounding, cp) + } + + return nil +} + +// AddProcessCapabilityEffective adds a process capability into g.Config.Process.Capabilities.Effective. +func (g *Generator) AddProcessCapabilityEffective(c string) error { + cp := strings.ToUpper(c) + if err := validate.CapValid(cp, g.HostSpecific); err != nil { + return err + } + + g.initConfigProcessCapabilities() + + var foundEffective bool + for _, cap := range g.Config.Process.Capabilities.Effective { + if strings.ToUpper(cap) == cp { + foundEffective = true + break + } + } + if !foundEffective { + g.Config.Process.Capabilities.Effective = append(g.Config.Process.Capabilities.Effective, cp) + } + + return nil +} + +// AddProcessCapabilityInheritable adds a process capability into g.Config.Process.Capabilities.Inheritable. +func (g *Generator) AddProcessCapabilityInheritable(c string) error { + cp := strings.ToUpper(c) + if err := validate.CapValid(cp, g.HostSpecific); err != nil { + return err + } + + g.initConfigProcessCapabilities() + + var foundInheritable bool + for _, cap := range g.Config.Process.Capabilities.Inheritable { + if strings.ToUpper(cap) == cp { + foundInheritable = true + break + } + } + if !foundInheritable { + g.Config.Process.Capabilities.Inheritable = append(g.Config.Process.Capabilities.Inheritable, cp) + } + + return nil +} + +// AddProcessCapabilityPermitted adds a process capability into g.Config.Process.Capabilities.Permitted. +func (g *Generator) AddProcessCapabilityPermitted(c string) error { + cp := strings.ToUpper(c) + if err := validate.CapValid(cp, g.HostSpecific); err != nil { + return err + } + + g.initConfigProcessCapabilities() + + var foundPermitted bool + for _, cap := range g.Config.Process.Capabilities.Permitted { + if strings.ToUpper(cap) == cp { + foundPermitted = true + break + } + } + if !foundPermitted { + g.Config.Process.Capabilities.Permitted = append(g.Config.Process.Capabilities.Permitted, cp) + } + + return nil +} + +// DropProcessCapabilityAmbient drops a process capability from g.Config.Process.Capabilities.Ambient. +func (g *Generator) DropProcessCapabilityAmbient(c string) error { + if g.Config == nil || g.Config.Process == nil || g.Config.Process.Capabilities == nil { + return nil + } + + cp := strings.ToUpper(c) + for i, cap := range g.Config.Process.Capabilities.Ambient { + if strings.ToUpper(cap) == cp { + g.Config.Process.Capabilities.Ambient = removeFunc(g.Config.Process.Capabilities.Ambient, i) + } + } + + return validate.CapValid(cp, false) +} + +// DropProcessCapabilityBounding drops a process capability from g.Config.Process.Capabilities.Bounding. +func (g *Generator) DropProcessCapabilityBounding(c string) error { + if g.Config == nil || g.Config.Process == nil || g.Config.Process.Capabilities == nil { + return nil + } + + cp := strings.ToUpper(c) + for i, cap := range g.Config.Process.Capabilities.Bounding { + if strings.ToUpper(cap) == cp { + g.Config.Process.Capabilities.Bounding = removeFunc(g.Config.Process.Capabilities.Bounding, i) + } + } + + return validate.CapValid(cp, false) +} + +// DropProcessCapabilityEffective drops a process capability from g.Config.Process.Capabilities.Effective. +func (g *Generator) DropProcessCapabilityEffective(c string) error { + if g.Config == nil || g.Config.Process == nil || g.Config.Process.Capabilities == nil { + return nil + } + + cp := strings.ToUpper(c) + for i, cap := range g.Config.Process.Capabilities.Effective { + if strings.ToUpper(cap) == cp { + g.Config.Process.Capabilities.Effective = removeFunc(g.Config.Process.Capabilities.Effective, i) + } + } + + return validate.CapValid(cp, false) +} + +// DropProcessCapabilityInheritable drops a process capability from g.Config.Process.Capabilities.Inheritable. +func (g *Generator) DropProcessCapabilityInheritable(c string) error { + if g.Config == nil || g.Config.Process == nil || g.Config.Process.Capabilities == nil { + return nil + } + + cp := strings.ToUpper(c) + for i, cap := range g.Config.Process.Capabilities.Inheritable { + if strings.ToUpper(cap) == cp { + g.Config.Process.Capabilities.Inheritable = removeFunc(g.Config.Process.Capabilities.Inheritable, i) + } + } + + return validate.CapValid(cp, false) +} + +// DropProcessCapabilityPermitted drops a process capability from g.Config.Process.Capabilities.Permitted. +func (g *Generator) DropProcessCapabilityPermitted(c string) error { + if g.Config == nil || g.Config.Process == nil || g.Config.Process.Capabilities == nil { + return nil + } + + cp := strings.ToUpper(c) + for i, cap := range g.Config.Process.Capabilities.Permitted { + if strings.ToUpper(cap) == cp { + g.Config.Process.Capabilities.Permitted = removeFunc(g.Config.Process.Capabilities.Permitted, i) + } + } + + return validate.CapValid(cp, false) +} + +func mapStrToNamespace(ns string, path string) (rspec.LinuxNamespace, error) { + switch ns { + case "network": + return rspec.LinuxNamespace{Type: rspec.NetworkNamespace, Path: path}, nil + case "pid": + return rspec.LinuxNamespace{Type: rspec.PIDNamespace, Path: path}, nil + case "mount": + return rspec.LinuxNamespace{Type: rspec.MountNamespace, Path: path}, nil + case "ipc": + return rspec.LinuxNamespace{Type: rspec.IPCNamespace, Path: path}, nil + case "uts": + return rspec.LinuxNamespace{Type: rspec.UTSNamespace, Path: path}, nil + case "user": + return rspec.LinuxNamespace{Type: rspec.UserNamespace, Path: path}, nil + case "cgroup": + return rspec.LinuxNamespace{Type: rspec.CgroupNamespace, Path: path}, nil + default: + return rspec.LinuxNamespace{}, fmt.Errorf("unrecognized namespace %q", ns) + } +} + +// ClearLinuxNamespaces clear g.Config.Linux.Namespaces. +func (g *Generator) ClearLinuxNamespaces() { + if g.Config == nil || g.Config.Linux == nil { + return + } + g.Config.Linux.Namespaces = []rspec.LinuxNamespace{} +} + +// AddOrReplaceLinuxNamespace adds or replaces a namespace inside +// g.Config.Linux.Namespaces. +func (g *Generator) AddOrReplaceLinuxNamespace(ns string, path string) error { + namespace, err := mapStrToNamespace(ns, path) + if err != nil { + return err + } + + g.initConfigLinux() + for i, ns := range g.Config.Linux.Namespaces { + if ns.Type == namespace.Type { + g.Config.Linux.Namespaces[i] = namespace + return nil + } + } + g.Config.Linux.Namespaces = append(g.Config.Linux.Namespaces, namespace) + return nil +} + +// RemoveLinuxNamespace removes a namespace from g.Config.Linux.Namespaces. +func (g *Generator) RemoveLinuxNamespace(ns string) error { + namespace, err := mapStrToNamespace(ns, "") + if err != nil { + return err + } + + if g.Config == nil || g.Config.Linux == nil { + return nil + } + for i, ns := range g.Config.Linux.Namespaces { + if ns.Type == namespace.Type { + g.Config.Linux.Namespaces = append(g.Config.Linux.Namespaces[:i], g.Config.Linux.Namespaces[i+1:]...) + return nil + } + } + return nil +} + +// AddDevice - add a device into g.Config.Linux.Devices +func (g *Generator) AddDevice(device rspec.LinuxDevice) { + g.initConfigLinux() + + for i, dev := range g.Config.Linux.Devices { + if dev.Path == device.Path { + g.Config.Linux.Devices[i] = device + return + } + if dev.Type == device.Type && dev.Major == device.Major && dev.Minor == device.Minor { + fmt.Fprintln(os.Stderr, "WARNING: The same type, major and minor should not be used for multiple devices.") + } + } + + g.Config.Linux.Devices = append(g.Config.Linux.Devices, device) +} + +// RemoveDevice remove a device from g.Config.Linux.Devices +func (g *Generator) RemoveDevice(path string) { + if g.Config == nil || g.Config.Linux == nil || g.Config.Linux.Devices == nil { + return + } + + for i, device := range g.Config.Linux.Devices { + if device.Path == path { + g.Config.Linux.Devices = append(g.Config.Linux.Devices[:i], g.Config.Linux.Devices[i+1:]...) + return + } + } +} + +// ClearLinuxDevices clears g.Config.Linux.Devices +func (g *Generator) ClearLinuxDevices() { + if g.Config == nil || g.Config.Linux == nil || g.Config.Linux.Devices == nil { + return + } + + g.Config.Linux.Devices = []rspec.LinuxDevice{} +} + +// AddLinuxResourcesDevice - add a device into g.Config.Linux.Resources.Devices +func (g *Generator) AddLinuxResourcesDevice(allow bool, devType string, major, minor *int64, access string) { + g.initConfigLinuxResources() + + device := rspec.LinuxDeviceCgroup{ + Allow: allow, + Type: devType, + Access: access, + Major: major, + Minor: minor, + } + g.Config.Linux.Resources.Devices = append(g.Config.Linux.Resources.Devices, device) +} + +// RemoveLinuxResourcesDevice - remove a device from g.Config.Linux.Resources.Devices +func (g *Generator) RemoveLinuxResourcesDevice(allow bool, devType string, major, minor *int64, access string) { + if g.Config == nil || g.Config.Linux == nil || g.Config.Linux.Resources == nil { + return + } + for i, device := range g.Config.Linux.Resources.Devices { + if device.Allow == allow && + (devType == device.Type || (devType != "" && device.Type != "" && devType == device.Type)) && + (access == device.Access || (access != "" && device.Access != "" && access == device.Access)) && + (major == device.Major || (major != nil && device.Major != nil && *major == *device.Major)) && + (minor == device.Minor || (minor != nil && device.Minor != nil && *minor == *device.Minor)) { + + g.Config.Linux.Resources.Devices = append(g.Config.Linux.Resources.Devices[:i], g.Config.Linux.Resources.Devices[i+1:]...) + return + } + } + return +} + +// strPtr returns the pointer pointing to the string s. +func strPtr(s string) *string { return &s } + +// SetSyscallAction adds rules for syscalls with the specified action +func (g *Generator) SetSyscallAction(arguments seccomp.SyscallOpts) error { + g.initConfigLinuxSeccomp() + return seccomp.ParseSyscallFlag(arguments, g.Config.Linux.Seccomp) +} + +// SetDefaultSeccompAction sets the default action for all syscalls not defined +// and then removes any syscall rules with this action already specified. +func (g *Generator) SetDefaultSeccompAction(action string) error { + g.initConfigLinuxSeccomp() + return seccomp.ParseDefaultAction(action, g.Config.Linux.Seccomp) +} + +// SetDefaultSeccompActionForce only sets the default action for all syscalls not defined +func (g *Generator) SetDefaultSeccompActionForce(action string) error { + g.initConfigLinuxSeccomp() + return seccomp.ParseDefaultActionForce(action, g.Config.Linux.Seccomp) +} + +// SetSeccompArchitecture sets the supported seccomp architectures +func (g *Generator) SetSeccompArchitecture(architecture string) error { + g.initConfigLinuxSeccomp() + return seccomp.ParseArchitectureFlag(architecture, g.Config.Linux.Seccomp) +} + +// RemoveSeccompRule removes rules for any specified syscalls +func (g *Generator) RemoveSeccompRule(arguments string) error { + g.initConfigLinuxSeccomp() + return seccomp.RemoveAction(arguments, g.Config.Linux.Seccomp) +} + +// RemoveAllSeccompRules removes all syscall rules +func (g *Generator) RemoveAllSeccompRules() error { + g.initConfigLinuxSeccomp() + return seccomp.RemoveAllSeccompRules(g.Config.Linux.Seccomp) +} + +// AddLinuxMaskedPaths adds masked paths into g.Config.Linux.MaskedPaths. +func (g *Generator) AddLinuxMaskedPaths(path string) { + g.initConfigLinux() + g.Config.Linux.MaskedPaths = append(g.Config.Linux.MaskedPaths, path) +} + +// AddLinuxReadonlyPaths adds readonly paths into g.Config.Linux.MaskedPaths. +func (g *Generator) AddLinuxReadonlyPaths(path string) { + g.initConfigLinux() + g.Config.Linux.ReadonlyPaths = append(g.Config.Linux.ReadonlyPaths, path) +} + +func addOrReplaceBlockIOThrottleDevice(tmpList []rspec.LinuxThrottleDevice, major int64, minor int64, rate uint64) []rspec.LinuxThrottleDevice { + throttleDevices := tmpList + for i, throttleDevice := range throttleDevices { + if throttleDevice.Major == major && throttleDevice.Minor == minor { + throttleDevices[i].Rate = rate + return throttleDevices + } + } + throttleDevice := new(rspec.LinuxThrottleDevice) + throttleDevice.Major = major + throttleDevice.Minor = minor + throttleDevice.Rate = rate + throttleDevices = append(throttleDevices, *throttleDevice) + + return throttleDevices +} + +func dropBlockIOThrottleDevice(tmpList []rspec.LinuxThrottleDevice, major int64, minor int64) []rspec.LinuxThrottleDevice { + throttleDevices := tmpList + for i, throttleDevice := range throttleDevices { + if throttleDevice.Major == major && throttleDevice.Minor == minor { + throttleDevices = append(throttleDevices[:i], throttleDevices[i+1:]...) + return throttleDevices + } + } + + return throttleDevices +} + +// AddSolarisAnet adds network into g.Config.Solaris.Anet +func (g *Generator) AddSolarisAnet(anet rspec.SolarisAnet) { + g.initConfigSolaris() + g.Config.Solaris.Anet = append(g.Config.Solaris.Anet, anet) +} + +// SetSolarisCappedCPUNcpus sets g.Config.Solaris.CappedCPU.Ncpus +func (g *Generator) SetSolarisCappedCPUNcpus(ncpus string) { + g.initConfigSolarisCappedCPU() + g.Config.Solaris.CappedCPU.Ncpus = ncpus +} + +// SetSolarisCappedMemoryPhysical sets g.Config.Solaris.CappedMemory.Physical +func (g *Generator) SetSolarisCappedMemoryPhysical(physical string) { + g.initConfigSolarisCappedMemory() + g.Config.Solaris.CappedMemory.Physical = physical +} + +// SetSolarisCappedMemorySwap sets g.Config.Solaris.CappedMemory.Swap +func (g *Generator) SetSolarisCappedMemorySwap(swap string) { + g.initConfigSolarisCappedMemory() + g.Config.Solaris.CappedMemory.Swap = swap +} + +// SetSolarisLimitPriv sets g.Config.Solaris.LimitPriv +func (g *Generator) SetSolarisLimitPriv(limitPriv string) { + g.initConfigSolaris() + g.Config.Solaris.LimitPriv = limitPriv +} + +// SetSolarisMaxShmMemory sets g.Config.Solaris.MaxShmMemory +func (g *Generator) SetSolarisMaxShmMemory(memory string) { + g.initConfigSolaris() + g.Config.Solaris.MaxShmMemory = memory +} + +// SetSolarisMilestone sets g.Config.Solaris.Milestone +func (g *Generator) SetSolarisMilestone(milestone string) { + g.initConfigSolaris() + g.Config.Solaris.Milestone = milestone +} + +// SetWindowsHypervUntilityVMPath sets g.Config.Windows.HyperV.UtilityVMPath. +func (g *Generator) SetWindowsHypervUntilityVMPath(path string) { + g.initConfigWindowsHyperV() + g.Config.Windows.HyperV.UtilityVMPath = path +} + +// SetWinodwsIgnoreFlushesDuringBoot sets g.Config.Winodws.IgnoreFlushesDuringBoot. +func (g *Generator) SetWinodwsIgnoreFlushesDuringBoot(ignore bool) { + g.initConfigWindows() + g.Config.Windows.IgnoreFlushesDuringBoot = ignore +} + +// AddWindowsLayerFolders adds layer folders into g.Config.Windows.LayerFolders. +func (g *Generator) AddWindowsLayerFolders(folder string) { + g.initConfigWindows() + g.Config.Windows.LayerFolders = append(g.Config.Windows.LayerFolders, folder) +} + +// SetWindowsNetwork sets g.Config.Windows.Network. +func (g *Generator) SetWindowsNetwork(network rspec.WindowsNetwork) { + g.initConfigWindows() + g.Config.Windows.Network = &network +} + +// SetWindowsNetworkNamespace sets g.Config.Windows.Network.NetworkNamespace +func (g *Generator) SetWindowsNetworkNamespace(path string) { + g.initConfigWindowsNetwork() + g.Config.Windows.Network.NetworkNamespace = path +} + +// SetWindowsResourcesCPU sets g.Config.Windows.Resources.CPU. +func (g *Generator) SetWindowsResourcesCPU(cpu rspec.WindowsCPUResources) { + g.initConfigWindowsResources() + g.Config.Windows.Resources.CPU = &cpu +} + +// SetWindowsResourcesMemoryLimit sets g.Config.Windows.Resources.Memory.Limit. +func (g *Generator) SetWindowsResourcesMemoryLimit(limit uint64) { + g.initConfigWindowsResourcesMemory() + g.Config.Windows.Resources.Memory.Limit = &limit +} + +// SetWindowsResourcesStorage sets g.Config.Windows.Resources.Storage. +func (g *Generator) SetWindowsResourcesStorage(storage rspec.WindowsStorageResources) { + g.initConfigWindowsResources() + g.Config.Windows.Resources.Storage = &storage +} + +// SetWinodwsServicing sets g.Config.Winodws.Servicing. +func (g *Generator) SetWinodwsServicing(servicing bool) { + g.initConfigWindows() + g.Config.Windows.Servicing = servicing +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/consts.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/consts.go new file mode 100644 index 0000000000..eade5718e0 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/consts.go @@ -0,0 +1,12 @@ +package seccomp + +const ( + seccompOverwrite = "overwrite" + seccompAppend = "append" + nothing = "nothing" + kill = "kill" + trap = "trap" + trace = "trace" + allow = "allow" + errno = "errno" +) diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/parse_action.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/parse_action.go new file mode 100644 index 0000000000..25daf0752d --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/parse_action.go @@ -0,0 +1,135 @@ +package seccomp + +import ( + "fmt" + "strconv" + "strings" + + rspec "github.com/opencontainers/runtime-spec/specs-go" +) + +// SyscallOpts contain options for parsing syscall rules +type SyscallOpts struct { + Action string + Syscall string + Index string + Value string + ValueTwo string + Operator string +} + +// ParseSyscallFlag takes a SyscallOpts struct and the seccomp configuration +// and sets the new syscall rule accordingly +func ParseSyscallFlag(args SyscallOpts, config *rspec.LinuxSeccomp) error { + var arguments []string + if args.Index != "" && args.Value != "" && args.ValueTwo != "" && args.Operator != "" { + arguments = []string{args.Action, args.Syscall, args.Index, args.Value, + args.ValueTwo, args.Operator} + } else { + arguments = []string{args.Action, args.Syscall} + } + + action, _ := parseAction(arguments[0]) + if action == config.DefaultAction && args.argsAreEmpty() { + // default already set, no need to make changes + return nil + } + + var newSyscall rspec.LinuxSyscall + numOfArgs := len(arguments) + if numOfArgs == 6 || numOfArgs == 2 { + argStruct, err := parseArguments(arguments[1:]) + if err != nil { + return err + } + newSyscall = newSyscallStruct(arguments[1], action, argStruct) + } else { + return fmt.Errorf("incorrect number of arguments to ParseSyscall: %d", numOfArgs) + } + + descison, err := decideCourseOfAction(&newSyscall, config.Syscalls) + if err != nil { + return err + } + delimDescison := strings.Split(descison, ":") + + if delimDescison[0] == seccompAppend { + config.Syscalls = append(config.Syscalls, newSyscall) + } + + if delimDescison[0] == seccompOverwrite { + indexForOverwrite, err := strconv.ParseInt(delimDescison[1], 10, 32) + if err != nil { + return err + } + config.Syscalls[indexForOverwrite] = newSyscall + } + + return nil +} + +var actions = map[string]rspec.LinuxSeccompAction{ + "allow": rspec.ActAllow, + "errno": rspec.ActErrno, + "kill": rspec.ActKill, + "trace": rspec.ActTrace, + "trap": rspec.ActTrap, +} + +// Take passed action, return the SCMP_ACT_ version of it +func parseAction(action string) (rspec.LinuxSeccompAction, error) { + a, ok := actions[action] + if !ok { + return "", fmt.Errorf("unrecognized action: %s", action) + } + return a, nil +} + +// ParseDefaultAction sets the default action of the seccomp configuration +// and then removes any rules that were already specified with this action +func ParseDefaultAction(action string, config *rspec.LinuxSeccomp) error { + if action == "" { + return nil + } + + defaultAction, err := parseAction(action) + if err != nil { + return err + } + config.DefaultAction = defaultAction + err = RemoveAllMatchingRules(config, defaultAction) + if err != nil { + return err + } + return nil +} + +// ParseDefaultActionForce simply sets the default action of the seccomp configuration +func ParseDefaultActionForce(action string, config *rspec.LinuxSeccomp) error { + if action == "" { + return nil + } + + defaultAction, err := parseAction(action) + if err != nil { + return err + } + config.DefaultAction = defaultAction + return nil +} + +func newSyscallStruct(name string, action rspec.LinuxSeccompAction, args []rspec.LinuxSeccompArg) rspec.LinuxSyscall { + syscallStruct := rspec.LinuxSyscall{ + Names: []string{name}, + Action: action, + Args: args, + } + return syscallStruct +} + +func (s SyscallOpts) argsAreEmpty() bool { + return (s.Index == "" && + s.Value == "" && + s.ValueTwo == "" && + s.Operator == "") +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/parse_architecture.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/parse_architecture.go new file mode 100644 index 0000000000..9b2bdfd2fa --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/parse_architecture.go @@ -0,0 +1,55 @@ +package seccomp + +import ( + "fmt" + + rspec "github.com/opencontainers/runtime-spec/specs-go" +) + +// ParseArchitectureFlag takes the raw string passed with the --arch flag, parses it +// and updates the Seccomp config accordingly +func ParseArchitectureFlag(architectureArg string, config *rspec.LinuxSeccomp) error { + correctedArch, err := parseArch(architectureArg) + if err != nil { + return err + } + + shouldAppend := true + for _, alreadySpecified := range config.Architectures { + if correctedArch == alreadySpecified { + shouldAppend = false + } + } + if shouldAppend { + config.Architectures = append(config.Architectures, correctedArch) + } + return nil +} + +func parseArch(arch string) (rspec.Arch, error) { + arches := map[string]rspec.Arch{ + "x86": rspec.ArchX86, + "amd64": rspec.ArchX86_64, + "x32": rspec.ArchX32, + "arm": rspec.ArchARM, + "arm64": rspec.ArchAARCH64, + "mips": rspec.ArchMIPS, + "mips64": rspec.ArchMIPS64, + "mips64n32": rspec.ArchMIPS64N32, + "mipsel": rspec.ArchMIPSEL, + "mipsel64": rspec.ArchMIPSEL64, + "mipsel64n32": rspec.ArchMIPSEL64N32, + "parisc": rspec.ArchPARISC, + "parisc64": rspec.ArchPARISC64, + "ppc": rspec.ArchPPC, + "ppc64": rspec.ArchPPC64, + "ppc64le": rspec.ArchPPC64LE, + "s390": rspec.ArchS390, + "s390x": rspec.ArchS390X, + } + a, ok := arches[arch] + if !ok { + return "", fmt.Errorf("unrecognized architecture: %s", arch) + } + return a, nil +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/parse_arguments.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/parse_arguments.go new file mode 100644 index 0000000000..2b4c394e67 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/parse_arguments.go @@ -0,0 +1,73 @@ +package seccomp + +import ( + "fmt" + "strconv" + + rspec "github.com/opencontainers/runtime-spec/specs-go" +) + +// parseArguments takes a list of arguments (delimArgs). It parses and fills out +// the argument information and returns a slice of arg structs +func parseArguments(delimArgs []string) ([]rspec.LinuxSeccompArg, error) { + nilArgSlice := []rspec.LinuxSeccompArg{} + numberOfArgs := len(delimArgs) + + // No parameters passed with syscall + if numberOfArgs == 1 { + return nilArgSlice, nil + } + + // Correct number of parameters passed with syscall + if numberOfArgs == 5 { + syscallIndex, err := strconv.ParseUint(delimArgs[1], 10, 0) + if err != nil { + return nilArgSlice, err + } + + syscallValue, err := strconv.ParseUint(delimArgs[2], 10, 64) + if err != nil { + return nilArgSlice, err + } + + syscallValueTwo, err := strconv.ParseUint(delimArgs[3], 10, 64) + if err != nil { + return nilArgSlice, err + } + + syscallOp, err := parseOperator(delimArgs[4]) + if err != nil { + return nilArgSlice, err + } + + argStruct := rspec.LinuxSeccompArg{ + Index: uint(syscallIndex), + Value: syscallValue, + ValueTwo: syscallValueTwo, + Op: syscallOp, + } + + argSlice := []rspec.LinuxSeccompArg{} + argSlice = append(argSlice, argStruct) + return argSlice, nil + } + + return nilArgSlice, fmt.Errorf("incorrect number of arguments passed with syscall: %d", numberOfArgs) +} + +func parseOperator(operator string) (rspec.LinuxSeccompOperator, error) { + operators := map[string]rspec.LinuxSeccompOperator{ + "NE": rspec.OpNotEqual, + "LT": rspec.OpLessThan, + "LE": rspec.OpLessEqual, + "EQ": rspec.OpEqualTo, + "GE": rspec.OpGreaterEqual, + "GT": rspec.OpGreaterThan, + "ME": rspec.OpMaskedEqual, + } + o, ok := operators[operator] + if !ok { + return "", fmt.Errorf("unrecognized operator: %s", operator) + } + return o, nil +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/parse_remove.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/parse_remove.go new file mode 100644 index 0000000000..59537d49c4 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/parse_remove.go @@ -0,0 +1,52 @@ +package seccomp + +import ( + "fmt" + "reflect" + "strings" + + rspec "github.com/opencontainers/runtime-spec/specs-go" +) + +// RemoveAction takes the argument string that was passed with the --remove flag, +// parses it, and updates the Seccomp config accordingly +func RemoveAction(arguments string, config *rspec.LinuxSeccomp) error { + if config == nil { + return fmt.Errorf("Cannot remove action from nil Seccomp pointer") + } + + syscallsToRemove := strings.Split(arguments, ",") + + for counter, syscallStruct := range config.Syscalls { + if reflect.DeepEqual(syscallsToRemove, syscallStruct.Names) { + config.Syscalls = append(config.Syscalls[:counter], config.Syscalls[counter+1:]...) + } + } + + return nil +} + +// RemoveAllSeccompRules removes all seccomp syscall rules +func RemoveAllSeccompRules(config *rspec.LinuxSeccomp) error { + if config == nil { + return fmt.Errorf("Cannot remove action from nil Seccomp pointer") + } + newSyscallSlice := []rspec.LinuxSyscall{} + config.Syscalls = newSyscallSlice + return nil +} + +// RemoveAllMatchingRules will remove any syscall rules that match the specified action +func RemoveAllMatchingRules(config *rspec.LinuxSeccomp, seccompAction rspec.LinuxSeccompAction) error { + if config == nil { + return fmt.Errorf("Cannot remove action from nil Seccomp pointer") + } + + for _, syscall := range config.Syscalls { + if reflect.DeepEqual(syscall.Action, seccompAction) { + RemoveAction(strings.Join(syscall.Names, ","), config) + } + } + + return nil +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/seccomp_default.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/seccomp_default.go new file mode 100644 index 0000000000..5fee5a3b2e --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/seccomp_default.go @@ -0,0 +1,576 @@ +package seccomp + +import ( + "runtime" + + "github.com/opencontainers/runtime-spec/specs-go" + rspec "github.com/opencontainers/runtime-spec/specs-go" +) + +func arches() []rspec.Arch { + native := runtime.GOARCH + + switch native { + case "amd64": + return []rspec.Arch{rspec.ArchX86_64, rspec.ArchX86, rspec.ArchX32} + case "arm64": + return []rspec.Arch{rspec.ArchARM, rspec.ArchAARCH64} + case "mips64": + return []rspec.Arch{rspec.ArchMIPS, rspec.ArchMIPS64, rspec.ArchMIPS64N32} + case "mips64n32": + return []rspec.Arch{rspec.ArchMIPS, rspec.ArchMIPS64, rspec.ArchMIPS64N32} + case "mipsel64": + return []rspec.Arch{rspec.ArchMIPSEL, rspec.ArchMIPSEL64, rspec.ArchMIPSEL64N32} + case "mipsel64n32": + return []rspec.Arch{rspec.ArchMIPSEL, rspec.ArchMIPSEL64, rspec.ArchMIPSEL64N32} + case "s390x": + return []rspec.Arch{rspec.ArchS390, rspec.ArchS390X} + default: + return []rspec.Arch{} + } +} + +// DefaultProfile defines the whitelist for the default seccomp profile. +func DefaultProfile(rs *specs.Spec) *rspec.LinuxSeccomp { + + syscalls := []rspec.LinuxSyscall{ + { + Names: []string{ + "accept", + "accept4", + "access", + "alarm", + "bind", + "brk", + "capget", + "capset", + "chdir", + "chmod", + "chown", + "chown32", + "clock_getres", + "clock_gettime", + "clock_nanosleep", + "close", + "connect", + "copy_file_range", + "creat", + "dup", + "dup2", + "dup3", + "epoll_create", + "epoll_create1", + "epoll_ctl", + "epoll_ctl_old", + "epoll_pwait", + "epoll_wait", + "epoll_wait_old", + "eventfd", + "eventfd2", + "execve", + "execveat", + "exit", + "exit_group", + "faccessat", + "fadvise64", + "fadvise64_64", + "fallocate", + "fanotify_mark", + "fchdir", + "fchmod", + "fchmodat", + "fchown", + "fchown32", + "fchownat", + "fcntl", + "fcntl64", + "fdatasync", + "fgetxattr", + "flistxattr", + "flock", + "fork", + "fremovexattr", + "fsetxattr", + "fstat", + "fstat64", + "fstatat64", + "fstatfs", + "fstatfs64", + "fsync", + "ftruncate", + "ftruncate64", + "futex", + "futimesat", + "getcpu", + "getcwd", + "getdents", + "getdents64", + "getegid", + "getegid32", + "geteuid", + "geteuid32", + "getgid", + "getgid32", + "getgroups", + "getgroups32", + "getitimer", + "getpeername", + "getpgid", + "getpgrp", + "getpid", + "getppid", + "getpriority", + "getrandom", + "getresgid", + "getresgid32", + "getresuid", + "getresuid32", + "getrlimit", + "get_robust_list", + "getrusage", + "getsid", + "getsockname", + "getsockopt", + "get_thread_area", + "gettid", + "gettimeofday", + "getuid", + "getuid32", + "getxattr", + "inotify_add_watch", + "inotify_init", + "inotify_init1", + "inotify_rm_watch", + "io_cancel", + "ioctl", + "io_destroy", + "io_getevents", + "ioprio_get", + "ioprio_set", + "io_setup", + "io_submit", + "ipc", + "kill", + "lchown", + "lchown32", + "lgetxattr", + "link", + "linkat", + "listen", + "listxattr", + "llistxattr", + "_llseek", + "lremovexattr", + "lseek", + "lsetxattr", + "lstat", + "lstat64", + "madvise", + "memfd_create", + "mincore", + "mkdir", + "mkdirat", + "mknod", + "mknodat", + "mlock", + "mlock2", + "mlockall", + "mmap", + "mmap2", + "mprotect", + "mq_getsetattr", + "mq_notify", + "mq_open", + "mq_timedreceive", + "mq_timedsend", + "mq_unlink", + "mremap", + "msgctl", + "msgget", + "msgrcv", + "msgsnd", + "msync", + "munlock", + "munlockall", + "munmap", + "nanosleep", + "newfstatat", + "_newselect", + "open", + "openat", + "pause", + "pipe", + "pipe2", + "poll", + "ppoll", + "prctl", + "pread64", + "preadv", + "prlimit64", + "pselect6", + "pwrite64", + "pwritev", + "read", + "readahead", + "readlink", + "readlinkat", + "readv", + "recv", + "recvfrom", + "recvmmsg", + "recvmsg", + "remap_file_pages", + "removexattr", + "rename", + "renameat", + "renameat2", + "restart_syscall", + "rmdir", + "rt_sigaction", + "rt_sigpending", + "rt_sigprocmask", + "rt_sigqueueinfo", + "rt_sigreturn", + "rt_sigsuspend", + "rt_sigtimedwait", + "rt_tgsigqueueinfo", + "sched_getaffinity", + "sched_getattr", + "sched_getparam", + "sched_get_priority_max", + "sched_get_priority_min", + "sched_getscheduler", + "sched_rr_get_interval", + "sched_setaffinity", + "sched_setattr", + "sched_setparam", + "sched_setscheduler", + "sched_yield", + "seccomp", + "select", + "semctl", + "semget", + "semop", + "semtimedop", + "send", + "sendfile", + "sendfile64", + "sendmmsg", + "sendmsg", + "sendto", + "setfsgid", + "setfsgid32", + "setfsuid", + "setfsuid32", + "setgid", + "setgid32", + "setgroups", + "setgroups32", + "setitimer", + "setpgid", + "setpriority", + "setregid", + "setregid32", + "setresgid", + "setresgid32", + "setresuid", + "setresuid32", + "setreuid", + "setreuid32", + "setrlimit", + "set_robust_list", + "setsid", + "setsockopt", + "set_thread_area", + "set_tid_address", + "setuid", + "setuid32", + "setxattr", + "shmat", + "shmctl", + "shmdt", + "shmget", + "shutdown", + "sigaltstack", + "signalfd", + "signalfd4", + "sigreturn", + "socket", + "socketcall", + "socketpair", + "splice", + "stat", + "stat64", + "statfs", + "statfs64", + "symlink", + "symlinkat", + "sync", + "sync_file_range", + "syncfs", + "sysinfo", + "syslog", + "tee", + "tgkill", + "time", + "timer_create", + "timer_delete", + "timerfd_create", + "timerfd_gettime", + "timerfd_settime", + "timer_getoverrun", + "timer_gettime", + "timer_settime", + "times", + "tkill", + "truncate", + "truncate64", + "ugetrlimit", + "umask", + "uname", + "unlink", + "unlinkat", + "utime", + "utimensat", + "utimes", + "vfork", + "vmsplice", + "wait4", + "waitid", + "waitpid", + "write", + "writev", + }, + Action: rspec.ActAllow, + Args: []rspec.LinuxSeccompArg{}, + }, + { + Names: []string{"personality"}, + Action: rspec.ActAllow, + Args: []rspec.LinuxSeccompArg{ + { + Index: 0, + Value: 0x0, + Op: rspec.OpEqualTo, + }, + { + Index: 0, + Value: 0x0008, + Op: rspec.OpEqualTo, + }, + { + Index: 0, + Value: 0xffffffff, + Op: rspec.OpEqualTo, + }, + }, + }, + } + var sysCloneFlagsIndex uint + + capSysAdmin := false + caps := make(map[string]bool) + + for _, cap := range rs.Process.Capabilities.Bounding { + caps[cap] = true + } + for _, cap := range rs.Process.Capabilities.Effective { + caps[cap] = true + } + for _, cap := range rs.Process.Capabilities.Inheritable { + caps[cap] = true + } + for _, cap := range rs.Process.Capabilities.Permitted { + caps[cap] = true + } + for _, cap := range rs.Process.Capabilities.Ambient { + caps[cap] = true + } + + for cap := range caps { + switch cap { + case "CAP_DAC_READ_SEARCH": + syscalls = append(syscalls, []rspec.LinuxSyscall{ + { + Names: []string{"open_by_handle_at"}, + Action: rspec.ActAllow, + Args: []rspec.LinuxSeccompArg{}, + }, + }...) + case "CAP_SYS_ADMIN": + capSysAdmin = true + syscalls = append(syscalls, []rspec.LinuxSyscall{ + { + Names: []string{ + "bpf", + "clone", + "fanotify_init", + "lookup_dcookie", + "mount", + "name_to_handle_at", + "perf_event_open", + "setdomainname", + "sethostname", + "setns", + "umount", + "umount2", + "unshare", + }, + Action: rspec.ActAllow, + Args: []rspec.LinuxSeccompArg{}, + }, + }...) + case "CAP_SYS_BOOT": + syscalls = append(syscalls, []rspec.LinuxSyscall{ + { + Names: []string{"reboot"}, + Action: rspec.ActAllow, + Args: []rspec.LinuxSeccompArg{}, + }, + }...) + case "CAP_SYS_CHROOT": + syscalls = append(syscalls, []rspec.LinuxSyscall{ + { + Names: []string{"chroot"}, + Action: rspec.ActAllow, + Args: []rspec.LinuxSeccompArg{}, + }, + }...) + case "CAP_SYS_MODULE": + syscalls = append(syscalls, []rspec.LinuxSyscall{ + { + Names: []string{ + "delete_module", + "init_module", + "finit_module", + "query_module", + }, + Action: rspec.ActAllow, + Args: []rspec.LinuxSeccompArg{}, + }, + }...) + case "CAP_SYS_PACCT": + syscalls = append(syscalls, []rspec.LinuxSyscall{ + { + Names: []string{"acct"}, + Action: rspec.ActAllow, + Args: []rspec.LinuxSeccompArg{}, + }, + }...) + case "CAP_SYS_PTRACE": + syscalls = append(syscalls, []rspec.LinuxSyscall{ + { + Names: []string{ + "kcmp", + "process_vm_readv", + "process_vm_writev", + "ptrace", + }, + Action: rspec.ActAllow, + Args: []rspec.LinuxSeccompArg{}, + }, + }...) + case "CAP_SYS_RAWIO": + syscalls = append(syscalls, []rspec.LinuxSyscall{ + { + Names: []string{ + "iopl", + "ioperm", + }, + Action: rspec.ActAllow, + Args: []rspec.LinuxSeccompArg{}, + }, + }...) + case "CAP_SYS_TIME": + syscalls = append(syscalls, []rspec.LinuxSyscall{ + { + Names: []string{ + "settimeofday", + "stime", + "adjtimex", + }, + Action: rspec.ActAllow, + Args: []rspec.LinuxSeccompArg{}, + }, + }...) + case "CAP_SYS_TTY_CONFIG": + syscalls = append(syscalls, []rspec.LinuxSyscall{ + { + Names: []string{"vhangup"}, + Action: rspec.ActAllow, + Args: []rspec.LinuxSeccompArg{}, + }, + }...) + } + } + + if !capSysAdmin { + syscalls = append(syscalls, []rspec.LinuxSyscall{ + { + Names: []string{"clone"}, + Action: rspec.ActAllow, + Args: []rspec.LinuxSeccompArg{ + { + Index: sysCloneFlagsIndex, + Value: CloneNewNS | CloneNewUTS | CloneNewIPC | CloneNewUser | CloneNewPID | CloneNewNet, + ValueTwo: 0, + Op: rspec.OpMaskedEqual, + }, + }, + }, + }...) + + } + + arch := runtime.GOARCH + switch arch { + case "arm", "arm64": + syscalls = append(syscalls, []rspec.LinuxSyscall{ + { + Names: []string{ + "breakpoint", + "cacheflush", + "set_tls", + }, + Action: rspec.ActAllow, + Args: []rspec.LinuxSeccompArg{}, + }, + }...) + case "amd64", "x32": + syscalls = append(syscalls, []rspec.LinuxSyscall{ + { + Names: []string{"arch_prctl"}, + Action: rspec.ActAllow, + Args: []rspec.LinuxSeccompArg{}, + }, + }...) + fallthrough + case "x86": + syscalls = append(syscalls, []rspec.LinuxSyscall{ + { + Names: []string{"modify_ldt"}, + Action: rspec.ActAllow, + Args: []rspec.LinuxSeccompArg{}, + }, + }...) + case "s390", "s390x": + syscalls = append(syscalls, []rspec.LinuxSyscall{ + { + Names: []string{ + "s390_pci_mmio_read", + "s390_pci_mmio_write", + "s390_runtime_instr", + }, + Action: rspec.ActAllow, + Args: []rspec.LinuxSeccompArg{}, + }, + }...) + /* Flags parameter of the clone syscall is the 2nd on s390 */ + } + + return &rspec.LinuxSeccomp{ + DefaultAction: rspec.ActErrno, + Architectures: arches(), + Syscalls: syscalls, + } +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/seccomp_default_linux.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/seccomp_default_linux.go new file mode 100644 index 0000000000..311587437f --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/seccomp_default_linux.go @@ -0,0 +1,15 @@ +// +build linux + +package seccomp + +import "syscall" + +// System values passed through on linux +const ( + CloneNewIPC = syscall.CLONE_NEWIPC + CloneNewNet = syscall.CLONE_NEWNET + CloneNewNS = syscall.CLONE_NEWNS + CloneNewPID = syscall.CLONE_NEWPID + CloneNewUser = syscall.CLONE_NEWUSER + CloneNewUTS = syscall.CLONE_NEWUTS +) diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/seccomp_default_unsupported.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/seccomp_default_unsupported.go new file mode 100644 index 0000000000..589b81c168 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/seccomp_default_unsupported.go @@ -0,0 +1,15 @@ +// +build !linux + +package seccomp + +// These are copied from linux/amd64 syscall values, as a reference for other +// platforms to have access to +const ( + CloneNewIPC = 0x8000000 + CloneNewNet = 0x40000000 + CloneNewNS = 0x20000 + CloneNewPID = 0x20000000 + CloneNewUser = 0x10000000 + CloneNewUTS = 0x4000000 + CloneNewCgroup = 0x02000000 +) diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/syscall_compare.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/syscall_compare.go new file mode 100644 index 0000000000..dbf2aec1c0 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/syscall_compare.go @@ -0,0 +1,140 @@ +package seccomp + +import ( + "fmt" + "reflect" + "strconv" + "strings" + + rspec "github.com/opencontainers/runtime-spec/specs-go" +) + +// Determine if a new syscall rule should be appended, overwrite an existing rule +// or if no action should be taken at all +func decideCourseOfAction(newSyscall *rspec.LinuxSyscall, syscalls []rspec.LinuxSyscall) (string, error) { + ruleForSyscallAlreadyExists := false + + var sliceOfDeterminedActions []string + for i, syscall := range syscalls { + if sameName(&syscall, newSyscall) { + ruleForSyscallAlreadyExists = true + + if identical(newSyscall, &syscall) { + sliceOfDeterminedActions = append(sliceOfDeterminedActions, nothing) + } + + if sameAction(newSyscall, &syscall) { + if bothHaveArgs(newSyscall, &syscall) { + sliceOfDeterminedActions = append(sliceOfDeterminedActions, seccompAppend) + } + if onlyOneHasArgs(newSyscall, &syscall) { + if firstParamOnlyHasArgs(newSyscall, &syscall) { + sliceOfDeterminedActions = append(sliceOfDeterminedActions, "overwrite:"+strconv.Itoa(i)) + } else { + sliceOfDeterminedActions = append(sliceOfDeterminedActions, nothing) + } + } + } + + if !sameAction(newSyscall, &syscall) { + if bothHaveArgs(newSyscall, &syscall) { + if sameArgs(newSyscall, &syscall) { + sliceOfDeterminedActions = append(sliceOfDeterminedActions, "overwrite:"+strconv.Itoa(i)) + } + if !sameArgs(newSyscall, &syscall) { + sliceOfDeterminedActions = append(sliceOfDeterminedActions, seccompAppend) + } + } + if onlyOneHasArgs(newSyscall, &syscall) { + sliceOfDeterminedActions = append(sliceOfDeterminedActions, seccompAppend) + } + if neitherHasArgs(newSyscall, &syscall) { + sliceOfDeterminedActions = append(sliceOfDeterminedActions, "overwrite:"+strconv.Itoa(i)) + } + } + } + } + + if !ruleForSyscallAlreadyExists { + sliceOfDeterminedActions = append(sliceOfDeterminedActions, seccompAppend) + } + + // Nothing has highest priority + for _, determinedAction := range sliceOfDeterminedActions { + if determinedAction == nothing { + return determinedAction, nil + } + } + + // Overwrite has second highest priority + for _, determinedAction := range sliceOfDeterminedActions { + if strings.Contains(determinedAction, seccompOverwrite) { + return determinedAction, nil + } + } + + // Append has the lowest priority + for _, determinedAction := range sliceOfDeterminedActions { + if determinedAction == seccompAppend { + return determinedAction, nil + } + } + + return "", fmt.Errorf("Trouble determining action: %s", sliceOfDeterminedActions) +} + +func hasArguments(config *rspec.LinuxSyscall) bool { + nilSyscall := new(rspec.LinuxSyscall) + return !sameArgs(nilSyscall, config) +} + +func identical(config1, config2 *rspec.LinuxSyscall) bool { + return reflect.DeepEqual(config1, config2) +} + +func identicalExceptAction(config1, config2 *rspec.LinuxSyscall) bool { + samename := sameName(config1, config2) + sameAction := sameAction(config1, config2) + sameArgs := sameArgs(config1, config2) + + return samename && !sameAction && sameArgs +} + +func identicalExceptArgs(config1, config2 *rspec.LinuxSyscall) bool { + samename := sameName(config1, config2) + sameAction := sameAction(config1, config2) + sameArgs := sameArgs(config1, config2) + + return samename && sameAction && !sameArgs +} + +func sameName(config1, config2 *rspec.LinuxSyscall) bool { + return reflect.DeepEqual(config1.Names, config2.Names) +} + +func sameAction(config1, config2 *rspec.LinuxSyscall) bool { + return config1.Action == config2.Action +} + +func sameArgs(config1, config2 *rspec.LinuxSyscall) bool { + return reflect.DeepEqual(config1.Args, config2.Args) +} + +func bothHaveArgs(config1, config2 *rspec.LinuxSyscall) bool { + return hasArguments(config1) && hasArguments(config2) +} + +func onlyOneHasArgs(config1, config2 *rspec.LinuxSyscall) bool { + conf1 := hasArguments(config1) + conf2 := hasArguments(config2) + + return (conf1 && !conf2) || (!conf1 && conf2) +} + +func neitherHasArgs(config1, config2 *rspec.LinuxSyscall) bool { + return !hasArguments(config1) && !hasArguments(config2) +} + +func firstParamOnlyHasArgs(config1, config2 *rspec.LinuxSyscall) bool { + return !hasArguments(config1) && hasArguments(config2) +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/specerror/bundle.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/specerror/bundle.go new file mode 100644 index 0000000000..dbe32af3df --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/specerror/bundle.go @@ -0,0 +1,29 @@ +package specerror + +import ( + "fmt" + + rfc2119 "github.com/opencontainers/runtime-tools/error" +) + +// define error codes +const ( + // ConfigInRootBundleDir represents "This REQUIRED file MUST reside in the root of the bundle directory" + ConfigInRootBundleDir Code = 0xa001 + iota + // ConfigConstName represents "This REQUIRED file MUST be named `config.json`." + ConfigConstName + // ArtifactsInSingleDir represents "When supplied, while these artifacts MUST all be present in a single directory on the local filesystem, that directory itself is not part of the bundle." + ArtifactsInSingleDir +) + +var ( + containerFormatRef = func(version string) (reference string, err error) { + return fmt.Sprintf(referenceTemplate, version, "bundle.md#container-format"), nil + } +) + +func init() { + register(ConfigInRootBundleDir, rfc2119.Must, containerFormatRef) + register(ConfigConstName, rfc2119.Must, containerFormatRef) + register(ArtifactsInSingleDir, rfc2119.Must, containerFormatRef) +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/specerror/config-linux.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/specerror/config-linux.go new file mode 100644 index 0000000000..aa2a284ce4 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/specerror/config-linux.go @@ -0,0 +1,134 @@ +package specerror + +import ( + "fmt" + + rfc2119 "github.com/opencontainers/runtime-tools/error" +) + +// define error codes +const ( + // DefaultFilesystems represents "The following filesystems SHOULD be made available in each container's filesystem:" + DefaultFilesystems Code = 0xc001 + iota + // NSPathAbs represents "This value MUST be an absolute path in the runtime mount namespace." + NSPathAbs + // NSProcInPath represents "The runtime MUST place the container process in the namespace associated with that `path`." + NSProcInPath + // NSPathMatchTypeError represents "The runtime MUST generate an error if `path` is not associated with a namespace of type `type`." + NSPathMatchTypeError + // NSNewNSWithoutPath represents "If `path` is not specified, the runtime MUST create a new container namespace of type `type`." + NSNewNSWithoutPath + // NSInheritWithoutType represents "If a namespace type is not specified in the `namespaces` array, the container MUST inherit the runtime namespace of that type." + NSInheritWithoutType + // NSErrorOnDup represents "If a `namespaces` field contains duplicated namespaces with same `type`, the runtime MUST generate an error." + NSErrorOnDup + // UserNSMapOwnershipRO represents "The runtime SHOULD NOT modify the ownership of referenced filesystems to realize the mapping." + UserNSMapOwnershipRO + // DevicesAvailable represents "devices (array of objects, OPTIONAL) lists devices that MUST be available in the container." + DevicesAvailable + // DevicesFileNotMatch represents "If a file already exists at `path` that does not match the requested device, the runtime MUST generate an error." + DevicesFileNotMatch + // DevicesMajMinRequired represents "`major, minor` (int64, REQUIRED unless `type` is `p`) - major, minor numbers for the device." + DevicesMajMinRequired + // DevicesErrorOnDup represents "The same `type`, `major` and `minor` SHOULD NOT be used for multiple devices." + DevicesErrorOnDup + // DefaultDevices represents "In addition to any devices configured with this setting, the runtime MUST also supply default devices." + DefaultDevices + // CgroupsPathAbsOrRel represents "The value of `cgroupsPath` MUST be either an absolute path or a relative path." + CgroupsPathAbsOrRel + // CgroupsAbsPathRelToMount represents "In the case of an absolute path (starting with `/`), the runtime MUST take the path to be relative to the cgroups mount point." + CgroupsAbsPathRelToMount + // CgroupsPathAttach represents "If the value is specified, the runtime MUST consistently attach to the same place in the cgroups hierarchy given the same value of `cgroupsPath`." + CgroupsPathAttach + // CgroupsPathError represents "Runtimes MAY consider certain `cgroupsPath` values to be invalid, and MUST generate an error if this is the case." + CgroupsPathError + // DevicesApplyInOrder represents "The runtime MUST apply entries in the listed order." + DevicesApplyInOrder + // BlkIOWeightOrLeafWeightExist represents "You MUST specify at least one of `weight` or `leafWeight` in a given entry, and MAY specify both." + BlkIOWeightOrLeafWeightExist + // IntelRdtPIDWrite represents "If `intelRdt` is set, the runtime MUST write the container process ID to the `/tasks` file in a mounted `resctrl` pseudo-filesystem, using the container ID from `start` and creating the `container-id` directory if necessary." + IntelRdtPIDWrite + // IntelRdtNoMountedResctrlError represents "If no mounted `resctrl` pseudo-filesystem is available in the runtime mount namespace, the runtime MUST generate an error." + IntelRdtNoMountedResctrlError + // NotManipResctrlWithoutIntelRdt represents "If `intelRdt` is not set, the runtime MUST NOT manipulate any `resctrl` pseudo-filesystems." + NotManipResctrlWithoutIntelRdt + // IntelRdtL3CacheSchemaWrite represents "If `l3CacheSchema` is set, runtimes MUST write the value to the `schemata` file in the `` directory discussed in `intelRdt`." + IntelRdtL3CacheSchemaWrite + // IntelRdtL3CacheSchemaNotWrite represents "If `l3CacheSchema` is not set, runtimes MUST NOT write to `schemata` files in any `resctrl` pseudo-filesystems." + IntelRdtL3CacheSchemaNotWrite + // SeccSyscallsNamesRequired represents "`names` MUST contain at least one entry." + SeccSyscallsNamesRequired + // MaskedPathsAbs represents "maskedPaths (array of strings, OPTIONAL) will mask over the provided paths inside the container so that they cannot be read. The values MUST be absolute paths in the container namespace." + MaskedPathsAbs + // ReadonlyPathsAbs represents "readonlyPaths (array of strings, OPTIONAL) will set the provided paths as readonly inside the container. The values MUST be absolute paths in the container namespace." + ReadonlyPathsAbs +) + +var ( + defaultFilesystemsRef = func(version string) (reference string, err error) { + return fmt.Sprintf(referenceTemplate, version, "config-linux.md#default-filesystems"), nil + } + namespacesRef = func(version string) (reference string, err error) { + return fmt.Sprintf(referenceTemplate, version, "config-linux.md#namespaces"), nil + } + userNamespaceMappingsRef = func(version string) (reference string, err error) { + return fmt.Sprintf(referenceTemplate, version, "config-linux.md#user-namespace-mappings"), nil + } + devicesRef = func(version string) (reference string, err error) { + return fmt.Sprintf(referenceTemplate, version, "config-linux.md#devices"), nil + } + defaultDevicesRef = func(version string) (reference string, err error) { + return fmt.Sprintf(referenceTemplate, version, "config-linux.md#default-devices"), nil + } + cgroupsPathRef = func(version string) (reference string, err error) { + return fmt.Sprintf(referenceTemplate, version, "config-linux.md#cgroups-path"), nil + } + deviceWhitelistRef = func(version string) (reference string, err error) { + return fmt.Sprintf(referenceTemplate, version, "config-linux.md#device-whitelist"), nil + } + blockIoRef = func(version string) (reference string, err error) { + return fmt.Sprintf(referenceTemplate, version, "config-linux.md#block-io"), nil + } + intelrdtRef = func(version string) (reference string, err error) { + return fmt.Sprintf(referenceTemplate, version, "config-linux.md#intelrdt"), nil + } + seccompRef = func(version string) (reference string, err error) { + return fmt.Sprintf(referenceTemplate, version, "config-linux.md#seccomp"), nil + } + maskedPathsRef = func(version string) (reference string, err error) { + return fmt.Sprintf(referenceTemplate, version, "config-linux.md#masked-paths"), nil + } + readonlyPathsRef = func(version string) (reference string, err error) { + return fmt.Sprintf(referenceTemplate, version, "config-linux.md#readonly-paths"), nil + } +) + +func init() { + register(DefaultFilesystems, rfc2119.Should, defaultFilesystemsRef) + register(NSPathAbs, rfc2119.Must, namespacesRef) + register(NSProcInPath, rfc2119.Must, namespacesRef) + register(NSPathMatchTypeError, rfc2119.Must, namespacesRef) + register(NSNewNSWithoutPath, rfc2119.Must, namespacesRef) + register(NSInheritWithoutType, rfc2119.Must, namespacesRef) + register(NSErrorOnDup, rfc2119.Must, namespacesRef) + register(UserNSMapOwnershipRO, rfc2119.Should, userNamespaceMappingsRef) + register(DevicesAvailable, rfc2119.Must, devicesRef) + register(DevicesFileNotMatch, rfc2119.Must, devicesRef) + register(DevicesMajMinRequired, rfc2119.Required, devicesRef) + register(DevicesErrorOnDup, rfc2119.Should, devicesRef) + register(DefaultDevices, rfc2119.Must, defaultDevicesRef) + register(CgroupsPathAbsOrRel, rfc2119.Must, cgroupsPathRef) + register(CgroupsAbsPathRelToMount, rfc2119.Must, cgroupsPathRef) + register(CgroupsPathAttach, rfc2119.Must, cgroupsPathRef) + register(CgroupsPathError, rfc2119.Must, cgroupsPathRef) + register(DevicesApplyInOrder, rfc2119.Must, deviceWhitelistRef) + register(BlkIOWeightOrLeafWeightExist, rfc2119.Must, blockIoRef) + register(IntelRdtPIDWrite, rfc2119.Must, intelrdtRef) + register(IntelRdtNoMountedResctrlError, rfc2119.Must, intelrdtRef) + register(NotManipResctrlWithoutIntelRdt, rfc2119.Must, intelrdtRef) + register(IntelRdtL3CacheSchemaWrite, rfc2119.Must, intelrdtRef) + register(IntelRdtL3CacheSchemaNotWrite, rfc2119.Must, intelrdtRef) + register(SeccSyscallsNamesRequired, rfc2119.Must, seccompRef) + register(MaskedPathsAbs, rfc2119.Must, maskedPathsRef) + register(ReadonlyPathsAbs, rfc2119.Must, readonlyPathsRef) +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/specerror/config-windows.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/specerror/config-windows.go new file mode 100644 index 0000000000..c8134867d6 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/specerror/config-windows.go @@ -0,0 +1,32 @@ +package specerror + +import ( + "fmt" + + rfc2119 "github.com/opencontainers/runtime-tools/error" +) + +// define error codes +const ( + // WindowsLayerFoldersRequired represents "`layerFolders` MUST contain at least one entry." + WindowsLayerFoldersRequired Code = 0xd001 + iota + // WindowsHyperVPresent represents "If present, the container MUST be run with Hyper-V isolation." + WindowsHyperVPresent + // WindowsHyperVOmit represents "If omitted, the container MUST be run as a Windows Server container." + WindowsHyperVOmit +) + +var ( + layerfoldersRef = func(version string) (reference string, err error) { + return fmt.Sprintf(referenceTemplate, version, "config-windows.md#layerfolders"), nil + } + hypervRef = func(version string) (reference string, err error) { + return fmt.Sprintf(referenceTemplate, version, "config-windows.md#hyperv"), nil + } +) + +func init() { + register(WindowsLayerFoldersRequired, rfc2119.Must, layerfoldersRef) + register(WindowsHyperVPresent, rfc2119.Must, hypervRef) + register(WindowsHyperVOmit, rfc2119.Must, hypervRef) +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/specerror/config.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/specerror/config.go new file mode 100644 index 0000000000..5357ab59f6 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/specerror/config.go @@ -0,0 +1,188 @@ +package specerror + +import ( + "fmt" + + rfc2119 "github.com/opencontainers/runtime-tools/error" +) + +// define error codes +const ( + // SpecVersionInSemVer represents "`ociVersion` (string, REQUIRED) MUST be in SemVer v2.0.0 format and specifies the version of the Open Container Initiative Runtime Specification with which the bundle complies." + SpecVersionInSemVer Code = 0xb001 + iota + // RootOnWindowsRequired represents "On Windows, for Windows Server Containers, this field is REQUIRED." + RootOnWindowsRequired + // RootOnHyperVNotSet represents "For Hyper-V Containers, this field MUST NOT be set." + RootOnHyperVNotSet + // RootOnNonWindowsRequired represents "On all other platforms, this field is REQUIRED." + RootOnNonWindowsRequired + // RootPathOnWindowsGUID represents "On Windows, `path` MUST be a volume GUID path." + RootPathOnWindowsGUID + // RootPathOnPosixConvention represents "The value SHOULD be the conventional `rootfs`." + RootPathOnPosixConvention + // RootPathExist represents "A directory MUST exist at the path declared by the field." + RootPathExist + // RootReadonlyImplement represents "`readonly` (bool, OPTIONAL) If true then the root filesystem MUST be read-only inside the container, defaults to false." + RootReadonlyImplement + // RootReadonlyOnWindowsFalse represents "* On Windows, this field MUST be omitted or false." + RootReadonlyOnWindowsFalse + // MountsInOrder represents "The runtime MUST mount entries in the listed order." + MountsInOrder + // MountsDestAbs represents "Destination of mount point: path inside container. This value MUST be an absolute path." + MountsDestAbs + // MountsDestOnWindowsNotNested represents "Windows: one mount destination MUST NOT be nested within another mount (e.g., c:\\foo and c:\\foo\\bar)." + MountsDestOnWindowsNotNested + // MountsOptionsOnWindowsROSupport represents "Windows: runtimes MUST support `ro`, mounting the filesystem read-only when `ro` is given." + MountsOptionsOnWindowsROSupport + // ProcRequiredAtStart represents "This property is REQUIRED when `start` is called." + ProcRequiredAtStart + // ProcConsoleSizeIgnore represents "Runtimes MUST ignore `consoleSize` if `terminal` is `false` or unset." + ProcConsoleSizeIgnore + // ProcCwdAbs represents "cwd (string, REQUIRED) is the working directory that will be set for the executable. This value MUST be an absolute path." + ProcCwdAbs + // ProcArgsOneEntryRequired represents "This specification extends the IEEE standard in that at least one entry is REQUIRED, and that entry is used with the same semantics as `execvp`'s *file*." + ProcArgsOneEntryRequired + // PosixProcRlimitsTypeGenError represents "The runtime MUST generate an error for any values which cannot be mapped to a relevant kernel interface." + PosixProcRlimitsTypeGenError + // PosixProcRlimitsTypeGet represents "For each entry in `rlimits`, a `getrlimit(3)` on `type` MUST succeed." + PosixProcRlimitsTypeGet + // PosixProcRlimitsTypeValueError represents "valid values are defined in the ... man page" + PosixProcRlimitsTypeValueError + // PosixProcRlimitsSoftMatchCur represents "`rlim.rlim_cur` MUST match the configured value." + PosixProcRlimitsSoftMatchCur + // PosixProcRlimitsHardMatchMax represents "`rlim.rlim_max` MUST match the configured value." + PosixProcRlimitsHardMatchMax + // PosixProcRlimitsErrorOnDup represents "If `rlimits` contains duplicated entries with same `type`, the runtime MUST generate an error." + PosixProcRlimitsErrorOnDup + // LinuxProcCapError represents "Any value which cannot be mapped to a relevant kernel interface MUST cause an error." + LinuxProcCapError + // LinuxProcOomScoreAdjSet represents "If `oomScoreAdj` is set, the runtime MUST set `oom_score_adj` to the given value." + LinuxProcOomScoreAdjSet + // LinuxProcOomScoreAdjNotSet represents "If `oomScoreAdj` is not set, the runtime MUST NOT change the value of `oom_score_adj`." + LinuxProcOomScoreAdjNotSet + // PlatformSpecConfOnWindowsSet represents "This MUST be set if the target platform of this spec is `windows`." + PlatformSpecConfOnWindowsSet + // PosixHooksPathAbs represents "This specification extends the IEEE standard in that `path` MUST be absolute." + PosixHooksPathAbs + // PosixHooksTimeoutPositive represents "If set, `timeout` MUST be greater than zero." + PosixHooksTimeoutPositive + // PosixHooksCalledInOrder represents "Hooks MUST be called in the listed order." + PosixHooksCalledInOrder + // PosixHooksStateToStdin represents "The state of the container MUST be passed to hooks over stdin so that they may do work appropriate to the current state of the container." + PosixHooksStateToStdin + // PrestartTiming represents "The pre-start hooks MUST be called after the `start` operation is called but before the user-specified program command is executed." + PrestartTiming + // PoststartTiming represents "The post-start hooks MUST be called after the user-specified process is executed but before the `start` operation returns." + PoststartTiming + // PoststopTiming represents "The post-stop hooks MUST be called after the container is deleted but before the `delete` operation returns." + PoststopTiming + // AnnotationsKeyValueMap represents "Annotations MUST be a key-value map." + AnnotationsKeyValueMap + // AnnotationsKeyString represents "Keys MUST be strings." + AnnotationsKeyString + // AnnotationsKeyRequired represents "Keys MUST NOT be an empty string." + AnnotationsKeyRequired + // AnnotationsKeyReversedDomain represents "Keys SHOULD be named using a reverse domain notation - e.g. `com.example.myKey`." + AnnotationsKeyReversedDomain + // AnnotationsKeyReservedNS represents "Keys using the `org.opencontainers` namespace are reserved and MUST NOT be used by subsequent specifications." + AnnotationsKeyReservedNS + // AnnotationsKeyIgnoreUnknown represents "Implementations that are reading/processing this configuration file MUST NOT generate an error if they encounter an unknown annotation key." + AnnotationsKeyIgnoreUnknown + // AnnotationsValueString represents "Values MUST be strings." + AnnotationsValueString + // ExtensibilityIgnoreUnknownProp represents "Runtimes that are reading or processing this configuration file MUST NOT generate an error if they encounter an unknown property." + ExtensibilityIgnoreUnknownProp + // ValidValues represents "Runtimes that are reading or processing this configuration file MUST generate an error when invalid or unsupported values are encountered." + ValidValues +) + +var ( + specificationVersionRef = func(version string) (reference string, err error) { + return fmt.Sprintf(referenceTemplate, version, "config.md#specification-version"), nil + } + rootRef = func(version string) (reference string, err error) { + return fmt.Sprintf(referenceTemplate, version, "config.md#root"), nil + } + mountsRef = func(version string) (reference string, err error) { + return fmt.Sprintf(referenceTemplate, version, "config.md#mounts"), nil + } + processRef = func(version string) (reference string, err error) { + return fmt.Sprintf(referenceTemplate, version, "config.md#process"), nil + } + posixProcessRef = func(version string) (reference string, err error) { + return fmt.Sprintf(referenceTemplate, version, "config.md#posix-process"), nil + } + linuxProcessRef = func(version string) (reference string, err error) { + return fmt.Sprintf(referenceTemplate, version, "config.md#linux-process"), nil + } + platformSpecificConfigurationRef = func(version string) (reference string, err error) { + return fmt.Sprintf(referenceTemplate, version, "config.md#platform-specific-configuration"), nil + } + posixPlatformHooksRef = func(version string) (reference string, err error) { + return fmt.Sprintf(referenceTemplate, version, "config.md#posix-platform-hooks"), nil + } + prestartRef = func(version string) (reference string, err error) { + return fmt.Sprintf(referenceTemplate, version, "config.md#prestart"), nil + } + poststartRef = func(version string) (reference string, err error) { + return fmt.Sprintf(referenceTemplate, version, "config.md#poststart"), nil + } + poststopRef = func(version string) (reference string, err error) { + return fmt.Sprintf(referenceTemplate, version, "config.md#poststop"), nil + } + annotationsRef = func(version string) (reference string, err error) { + return fmt.Sprintf(referenceTemplate, version, "config.md#annotations"), nil + } + extensibilityRef = func(version string) (reference string, err error) { + return fmt.Sprintf(referenceTemplate, version, "config.md#extensibility"), nil + } + validValuesRef = func(version string) (reference string, err error) { + return fmt.Sprintf(referenceTemplate, version, "config.md#valid-values"), nil + } +) + +func init() { + register(SpecVersionInSemVer, rfc2119.Must, specificationVersionRef) + register(RootOnWindowsRequired, rfc2119.Required, rootRef) + register(RootOnHyperVNotSet, rfc2119.Must, rootRef) + register(RootOnNonWindowsRequired, rfc2119.Required, rootRef) + register(RootPathOnWindowsGUID, rfc2119.Must, rootRef) + register(RootPathOnPosixConvention, rfc2119.Should, rootRef) + register(RootPathExist, rfc2119.Must, rootRef) + register(RootReadonlyImplement, rfc2119.Must, rootRef) + register(RootReadonlyOnWindowsFalse, rfc2119.Must, rootRef) + register(MountsInOrder, rfc2119.Must, mountsRef) + register(MountsDestAbs, rfc2119.Must, mountsRef) + register(MountsDestOnWindowsNotNested, rfc2119.Must, mountsRef) + register(MountsOptionsOnWindowsROSupport, rfc2119.Must, mountsRef) + register(ProcRequiredAtStart, rfc2119.Required, processRef) + register(ProcConsoleSizeIgnore, rfc2119.Must, processRef) + register(ProcCwdAbs, rfc2119.Must, processRef) + register(ProcArgsOneEntryRequired, rfc2119.Required, processRef) + register(PosixProcRlimitsTypeGenError, rfc2119.Must, posixProcessRef) + register(PosixProcRlimitsTypeGet, rfc2119.Must, posixProcessRef) + register(PosixProcRlimitsTypeValueError, rfc2119.Should, posixProcessRef) + register(PosixProcRlimitsSoftMatchCur, rfc2119.Must, posixProcessRef) + register(PosixProcRlimitsHardMatchMax, rfc2119.Must, posixProcessRef) + register(PosixProcRlimitsErrorOnDup, rfc2119.Must, posixProcessRef) + register(LinuxProcCapError, rfc2119.Must, linuxProcessRef) + register(LinuxProcOomScoreAdjSet, rfc2119.Must, linuxProcessRef) + register(LinuxProcOomScoreAdjNotSet, rfc2119.Must, linuxProcessRef) + register(PlatformSpecConfOnWindowsSet, rfc2119.Must, platformSpecificConfigurationRef) + register(PosixHooksPathAbs, rfc2119.Must, posixPlatformHooksRef) + register(PosixHooksTimeoutPositive, rfc2119.Must, posixPlatformHooksRef) + register(PosixHooksCalledInOrder, rfc2119.Must, posixPlatformHooksRef) + register(PosixHooksStateToStdin, rfc2119.Must, posixPlatformHooksRef) + register(PrestartTiming, rfc2119.Must, prestartRef) + register(PoststartTiming, rfc2119.Must, poststartRef) + register(PoststopTiming, rfc2119.Must, poststopRef) + register(AnnotationsKeyValueMap, rfc2119.Must, annotationsRef) + register(AnnotationsKeyString, rfc2119.Must, annotationsRef) + register(AnnotationsKeyRequired, rfc2119.Must, annotationsRef) + register(AnnotationsKeyReversedDomain, rfc2119.Should, annotationsRef) + register(AnnotationsKeyReservedNS, rfc2119.Must, annotationsRef) + register(AnnotationsKeyIgnoreUnknown, rfc2119.Must, annotationsRef) + register(AnnotationsValueString, rfc2119.Must, annotationsRef) + register(ExtensibilityIgnoreUnknownProp, rfc2119.Must, extensibilityRef) + register(ValidValues, rfc2119.Must, validValuesRef) +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/specerror/error.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/specerror/error.go new file mode 100644 index 0000000000..5de9492d9a --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/specerror/error.go @@ -0,0 +1,152 @@ +// Package specerror implements runtime-spec-specific tooling for +// tracking RFC 2119 violations. +package specerror + +import ( + "fmt" + + "github.com/hashicorp/go-multierror" + rfc2119 "github.com/opencontainers/runtime-tools/error" +) + +const referenceTemplate = "https://github.com/opencontainers/runtime-spec/blob/v%s/%s" + +// Code represents the spec violation, enumerating both +// configuration violations and runtime violations. +type Code int64 + +const ( + // NonError represents that an input is not an error + NonError Code = 0x1a001 + iota + // NonRFCError represents that an error is not a rfc2119 error + NonRFCError +) + +type errorTemplate struct { + Level rfc2119.Level + Reference func(version string) (reference string, err error) +} + +// Error represents a runtime-spec violation. +type Error struct { + // Err holds the RFC 2119 violation. + Err rfc2119.Error + + // Code is a matchable holds a Code + Code Code +} + +// LevelErrors represents Errors filtered into fatal and warnings. +type LevelErrors struct { + // Warnings holds Errors that were below a compliance-level threshold. + Warnings []*Error + + // Error holds errors that were at or above a compliance-level + // threshold, as well as errors that are not Errors. + Error *multierror.Error +} + +var ociErrors = map[Code]errorTemplate{} + +func register(code Code, level rfc2119.Level, ref func(versiong string) (string, error)) { + if _, ok := ociErrors[code]; ok { + panic(fmt.Sprintf("should not regist a same code twice: %v", code)) + } + + ociErrors[code] = errorTemplate{Level: level, Reference: ref} +} + +// Error returns the error message with specification reference. +func (err *Error) Error() string { + return err.Err.Error() +} + +// NewRFCError creates an rfc2119.Error referencing a spec violation. +// +// A version string (for the version of the spec that was violated) +// must be set to get a working URL. +func NewRFCError(code Code, err error, version string) (*rfc2119.Error, error) { + template := ociErrors[code] + reference, err2 := template.Reference(version) + if err2 != nil { + return nil, err2 + } + return &rfc2119.Error{ + Level: template.Level, + Reference: reference, + Err: err, + }, nil +} + +// NewRFCErrorOrPanic creates an rfc2119.Error referencing a spec +// violation and panics on failure. This is handy for situations +// where you can't be bothered to check NewRFCError for failure. +func NewRFCErrorOrPanic(code Code, err error, version string) *rfc2119.Error { + rfcError, err2 := NewRFCError(code, err, version) + if err2 != nil { + panic(err2.Error()) + } + return rfcError +} + +// NewError creates an Error referencing a spec violation. The error +// can be cast to an *Error for extracting structured information +// about the level of the violation and a reference to the violated +// spec condition. +// +// A version string (for the version of the spec that was violated) +// must be set to get a working URL. +func NewError(code Code, err error, version string) error { + rfcError, err2 := NewRFCError(code, err, version) + if err2 != nil { + return err2 + } + return &Error{ + Err: *rfcError, + Code: code, + } +} + +// FindError finds an error from a source error (multiple error) and +// returns the error code if found. +// If the source error is nil or empty, return NonError. +// If the source error is not a multiple error, return NonRFCError. +func FindError(err error, code Code) Code { + if err == nil { + return NonError + } + + if merr, ok := err.(*multierror.Error); ok { + if merr.ErrorOrNil() == nil { + return NonError + } + for _, e := range merr.Errors { + if rfcErr, ok := e.(*Error); ok { + if rfcErr.Code == code { + return code + } + } + } + } + return NonRFCError +} + +// SplitLevel removes RFC 2119 errors with a level less than 'level' +// from the source error. If the source error is not a multierror, it +// is returned unchanged. +func SplitLevel(errIn error, level rfc2119.Level) (levelErrors LevelErrors, errOut error) { + merr, ok := errIn.(*multierror.Error) + if !ok { + return levelErrors, errIn + } + for _, err := range merr.Errors { + e, ok := err.(*Error) + if ok && e.Err.Level < level { + fmt.Println(e) + levelErrors.Warnings = append(levelErrors.Warnings, e) + continue + } + levelErrors.Error = multierror.Append(levelErrors.Error, err) + } + return levelErrors, nil +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/specerror/runtime-linux.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/specerror/runtime-linux.go new file mode 100644 index 0000000000..8eb259ba16 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/specerror/runtime-linux.go @@ -0,0 +1,23 @@ +package specerror + +import ( + "fmt" + + rfc2119 "github.com/opencontainers/runtime-tools/error" +) + +// define error codes +const ( + // DefaultRuntimeLinuxSymlinks represents "While creating the container (step 2 in the lifecycle), runtimes MUST create default symlinks if the source file exists after processing `mounts`." + DefaultRuntimeLinuxSymlinks Code = 0xf001 + iota +) + +var ( + devSymbolicLinksRef = func(version string) (reference string, err error) { + return fmt.Sprintf(referenceTemplate, version, "runtime-linux.md#dev-symbolic-links"), nil + } +) + +func init() { + register(DefaultRuntimeLinuxSymlinks, rfc2119.Must, devSymbolicLinksRef) +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/specerror/runtime.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/specerror/runtime.go new file mode 100644 index 0000000000..383aea63c0 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/specerror/runtime.go @@ -0,0 +1,179 @@ +package specerror + +import ( + "fmt" + + rfc2119 "github.com/opencontainers/runtime-tools/error" +) + +// define error codes +const ( + // EntityOperSameContainer represents "The entity using a runtime to create a container MUST be able to use the operations defined in this specification against that same container." + EntityOperSameContainer Code = 0xe001 + iota + // StateIDUniq represents "`id` (string, REQUIRED) is the container's ID. This MUST be unique across all containers on this host." + StateIDUniq + // StateNewStatus represents "Additional values MAY be defined by the runtime, however, they MUST be used to represent new runtime states not defined above." + StateNewStatus + // DefaultStateJSONPattern represents "When serialized in JSON, the format MUST adhere to the default pattern." + DefaultStateJSONPattern + // EnvCreateImplement represents "The container's runtime environment MUST be created according to the configuration in `config.json`." + EnvCreateImplement + // EnvCreateError represents "If the runtime is unable to create the environment specified in the `config.json`, it MUST generate an error." + EnvCreateError + // ProcNotRunAtResRequest represents "While the resources requested in the `config.json` MUST be created, the user-specified program (from `process`) MUST NOT be run at this time." + ProcNotRunAtResRequest + // ConfigUpdatesWithoutAffect represents "Any updates to `config.json` after this step MUST NOT affect the container." + ConfigUpdatesWithoutAffect + // PrestartHooksInvoke represents "The prestart hooks MUST be invoked by the runtime." + PrestartHooksInvoke + // PrestartHookFailGenError represents "If any prestart hook fails, the runtime MUST generate an error, stop the container, and continue the lifecycle at step 9." + PrestartHookFailGenError + // ProcImplement represents "The runtime MUST run the user-specified program, as specified by `process`." + ProcImplement + // PoststartHooksInvoke represents "The poststart hooks MUST be invoked by the runtime." + PoststartHooksInvoke + // PoststartHookFailGenWarn represents "If any poststart hook fails, the runtime MUST log a warning, but the remaining hooks and lifecycle continue as if the hook had succeeded." + PoststartHookFailGenWarn + // UndoCreateSteps represents "The container MUST be destroyed by undoing the steps performed during create phase (step 2)." + UndoCreateSteps + // PoststopHooksInvoke represents "The poststop hooks MUST be invoked by the runtime." + PoststopHooksInvoke + // PoststopHookFailGenWarn represents "If any poststop hook fails, the runtime MUST log a warning, but the remaining hooks and lifecycle continue as if the hook had succeeded." + PoststopHookFailGenWarn + // ErrorsLeaveStateUnchange represents "Unless otherwise stated, generating an error MUST leave the state of the environment as if the operation were never attempted - modulo any possible trivial ancillary changes such as logging." + ErrorsLeaveStateUnchange + // WarnsLeaveFlowUnchange represents "Unless otherwise stated, logging a warning does not change the flow of the operation; it MUST continue as if the warning had not been logged." + WarnsLeaveFlowUnchange + // DefaultOperations represents "Unless otherwise stated, runtimes MUST support the default operations." + DefaultOperations + // QueryWithoutIDGenError represents "This operation MUST generate an error if it is not provided the ID of a container." + QueryWithoutIDGenError + // QueryNonExistGenError represents "Attempting to query a container that does not exist MUST generate an error." + QueryNonExistGenError + // QueryStateImplement represents "This operation MUST return the state of a container as specified in the State section." + QueryStateImplement + // CreateWithBundlePathAndID represents "This operation MUST generate an error if it is not provided a path to the bundle and the container ID to associate with the container." + CreateWithBundlePathAndID + // CreateWithUniqueID represents "If the ID provided is not unique across all containers within the scope of the runtime, or is not valid in any other way, the implementation MUST generate an error and a new container MUST NOT be created." + CreateWithUniqueID + // CreateNewContainer represents "This operation MUST create a new container." + CreateNewContainer + // PropsApplyExceptProcOnCreate represents "All of the properties configured in `config.json` except for `process` MUST be applied." + PropsApplyExceptProcOnCreate + // ProcArgsApplyUntilStart represents `process.args` MUST NOT be applied until triggered by the `start` operation." + ProcArgsApplyUntilStart + // PropApplyFailGenError represents "If the runtime cannot apply a property as specified in the configuration, it MUST generate an error." + PropApplyFailGenError + // PropApplyFailNotCreate represents "If the runtime cannot apply a property as specified in the configuration, a new container MUST NOT be created." + PropApplyFailNotCreate + // StartWithoutIDGenError represents "`start` operation MUST generate an error if it is not provided the container ID." + StartWithoutIDGenError + // StartNotCreatedHaveNoEffect represents "Attempting to `start` a container that is not `created` MUST have no effect on the container." + StartNotCreatedHaveNoEffect + // StartNotCreatedGenError represents "Attempting to `start` a container that is not `created` MUST generate an error." + StartNotCreatedGenError + // StartProcImplement represents "`start` operation MUST run the user-specified program as specified by `process`." + StartProcImplement + // StartWithProcUnsetGenError represents "`start` operation MUST generate an error if `process` was not set." + StartWithProcUnsetGenError + // KillWithoutIDGenError represents "`kill` operation MUST generate an error if it is not provided the container ID." + KillWithoutIDGenError + // KillNonCreateRunHaveNoEffect represents "Attempting to send a signal to a container that is neither `created` nor `running` MUST have no effect on the container." + KillNonCreateRunHaveNoEffect + // KillNonCreateRunGenError represents "Attempting to send a signal to a container that is neither `created` nor `running` MUST generate an error." + KillNonCreateRunGenError + // KillSignalImplement represents "`kill` operation MUST send the specified signal to the container process." + KillSignalImplement + // DeleteWithoutIDGenError represents "`delete` operation MUST generate an error if it is not provided the container ID." + DeleteWithoutIDGenError + // DeleteNonStopHaveNoEffect represents "Attempting to `delete` a container that is not `stopped` MUST have no effect on the container." + DeleteNonStopHaveNoEffect + // DeleteNonStopGenError represents "Attempting to `delete` a container that is not `stopped` MUST generate an error." + DeleteNonStopGenError + // DeleteResImplement represents "Deleting a container MUST delete the resources that were created during the `create` step." + DeleteResImplement + // DeleteOnlyCreatedRes represents "Note that resources associated with the container, but not created by this container, MUST NOT be deleted." + DeleteOnlyCreatedRes +) + +var ( + scopeOfAContainerRef = func(version string) (reference string, err error) { + return fmt.Sprintf(referenceTemplate, version, "runtime.md#scope-of-a-container"), nil + } + stateRef = func(version string) (reference string, err error) { + return fmt.Sprintf(referenceTemplate, version, "runtime.md#state"), nil + } + lifecycleRef = func(version string) (reference string, err error) { + return fmt.Sprintf(referenceTemplate, version, "runtime.md#lifecycle"), nil + } + errorsRef = func(version string) (reference string, err error) { + return fmt.Sprintf(referenceTemplate, version, "runtime.md#errors"), nil + } + warningsRef = func(version string) (reference string, err error) { + return fmt.Sprintf(referenceTemplate, version, "runtime.md#warnings"), nil + } + operationsRef = func(version string) (reference string, err error) { + return fmt.Sprintf(referenceTemplate, version, "runtime.md#operations"), nil + } + queryStateRef = func(version string) (reference string, err error) { + return fmt.Sprintf(referenceTemplate, version, "runtime.md#query-state"), nil + } + createRef = func(version string) (reference string, err error) { + return fmt.Sprintf(referenceTemplate, version, "runtime.md#create"), nil + } + startRef = func(version string) (reference string, err error) { + return fmt.Sprintf(referenceTemplate, version, "runtime.md#start"), nil + } + killRef = func(version string) (reference string, err error) { + return fmt.Sprintf(referenceTemplate, version, "runtime.md#kill"), nil + } + deleteRef = func(version string) (reference string, err error) { + return fmt.Sprintf(referenceTemplate, version, "runtime.md#delete"), nil + } +) + +func init() { + register(EntityOperSameContainer, rfc2119.Must, scopeOfAContainerRef) + register(StateIDUniq, rfc2119.Must, stateRef) + register(StateNewStatus, rfc2119.Must, stateRef) + register(DefaultStateJSONPattern, rfc2119.Must, stateRef) + register(EnvCreateImplement, rfc2119.Must, lifecycleRef) + register(EnvCreateError, rfc2119.Must, lifecycleRef) + register(ProcNotRunAtResRequest, rfc2119.Must, lifecycleRef) + register(ConfigUpdatesWithoutAffect, rfc2119.Must, lifecycleRef) + register(PrestartHooksInvoke, rfc2119.Must, lifecycleRef) + register(PrestartHookFailGenError, rfc2119.Must, lifecycleRef) + register(ProcImplement, rfc2119.Must, lifecycleRef) + register(PoststartHooksInvoke, rfc2119.Must, lifecycleRef) + register(PoststartHookFailGenWarn, rfc2119.Must, lifecycleRef) + register(UndoCreateSteps, rfc2119.Must, lifecycleRef) + register(PoststopHooksInvoke, rfc2119.Must, lifecycleRef) + register(PoststopHookFailGenWarn, rfc2119.Must, lifecycleRef) + register(ErrorsLeaveStateUnchange, rfc2119.Must, errorsRef) + register(WarnsLeaveFlowUnchange, rfc2119.Must, warningsRef) + register(DefaultOperations, rfc2119.Must, operationsRef) + register(QueryWithoutIDGenError, rfc2119.Must, queryStateRef) + register(QueryNonExistGenError, rfc2119.Must, queryStateRef) + register(QueryStateImplement, rfc2119.Must, queryStateRef) + register(CreateWithBundlePathAndID, rfc2119.Must, createRef) + register(CreateWithUniqueID, rfc2119.Must, createRef) + register(CreateNewContainer, rfc2119.Must, createRef) + register(PropsApplyExceptProcOnCreate, rfc2119.Must, createRef) + register(ProcArgsApplyUntilStart, rfc2119.Must, createRef) + register(PropApplyFailGenError, rfc2119.Must, createRef) + register(PropApplyFailNotCreate, rfc2119.Must, createRef) + register(StartWithoutIDGenError, rfc2119.Must, startRef) + register(StartNotCreatedHaveNoEffect, rfc2119.Must, startRef) + register(StartNotCreatedGenError, rfc2119.Must, startRef) + register(StartProcImplement, rfc2119.Must, startRef) + register(StartWithProcUnsetGenError, rfc2119.Must, startRef) + register(KillWithoutIDGenError, rfc2119.Must, killRef) + register(KillNonCreateRunHaveNoEffect, rfc2119.Must, killRef) + register(KillNonCreateRunGenError, rfc2119.Must, killRef) + register(KillSignalImplement, rfc2119.Must, killRef) + register(DeleteWithoutIDGenError, rfc2119.Must, deleteRef) + register(DeleteNonStopHaveNoEffect, rfc2119.Must, deleteRef) + register(DeleteNonStopGenError, rfc2119.Must, deleteRef) + register(DeleteResImplement, rfc2119.Must, deleteRef) + register(DeleteOnlyCreatedRes, rfc2119.Must, deleteRef) +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/validate/validate.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/validate/validate.go new file mode 100644 index 0000000000..e2e820979e --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/validate/validate.go @@ -0,0 +1,838 @@ +package validate + +import ( + "bufio" + "encoding/json" + "errors" + "fmt" + "io/ioutil" + "net" + "os" + "path/filepath" + "reflect" + "regexp" + "runtime" + "strings" + "unicode" + "unicode/utf8" + + "github.com/blang/semver" + "github.com/hashicorp/go-multierror" + rspec "github.com/opencontainers/runtime-spec/specs-go" + osFilepath "github.com/opencontainers/runtime-tools/filepath" + "github.com/sirupsen/logrus" + "github.com/syndtr/gocapability/capability" + + "github.com/opencontainers/runtime-tools/specerror" + "github.com/xeipuuv/gojsonschema" +) + +const specConfig = "config.json" + +var ( + // http://pubs.opengroup.org/onlinepubs/9699919799/functions/getrlimit.html + posixRlimits = []string{ + "RLIMIT_AS", + "RLIMIT_CORE", + "RLIMIT_CPU", + "RLIMIT_DATA", + "RLIMIT_FSIZE", + "RLIMIT_NOFILE", + "RLIMIT_STACK", + } + + // https://git.kernel.org/pub/scm/docs/man-pages/man-pages.git/tree/man2/getrlimit.2?h=man-pages-4.13 + linuxRlimits = append(posixRlimits, []string{ + "RLIMIT_MEMLOCK", + "RLIMIT_MSGQUEUE", + "RLIMIT_NICE", + "RLIMIT_NPROC", + "RLIMIT_RSS", + "RLIMIT_RTPRIO", + "RLIMIT_RTTIME", + "RLIMIT_SIGPENDING", + }...) + + configSchemaTemplate = "https://raw.githubusercontent.com/opencontainers/runtime-spec/v%s/schema/config-schema.json" +) + +// Validator represents a validator for runtime bundle +type Validator struct { + spec *rspec.Spec + bundlePath string + HostSpecific bool + platform string +} + +// NewValidator creates a Validator +func NewValidator(spec *rspec.Spec, bundlePath string, hostSpecific bool, platform string) (Validator, error) { + if hostSpecific && platform != runtime.GOOS { + return Validator{}, fmt.Errorf("When hostSpecific is set, platform must be same as the host platform") + } + return Validator{ + spec: spec, + bundlePath: bundlePath, + HostSpecific: hostSpecific, + platform: platform, + }, nil +} + +// NewValidatorFromPath creates a Validator with specified bundle path +func NewValidatorFromPath(bundlePath string, hostSpecific bool, platform string) (Validator, error) { + if bundlePath == "" { + return Validator{}, fmt.Errorf("bundle path shouldn't be empty") + } + + if _, err := os.Stat(bundlePath); err != nil { + return Validator{}, err + } + + configPath := filepath.Join(bundlePath, specConfig) + content, err := ioutil.ReadFile(configPath) + if err != nil { + return Validator{}, specerror.NewError(specerror.ConfigInRootBundleDir, err, rspec.Version) + } + if !utf8.Valid(content) { + return Validator{}, fmt.Errorf("%q is not encoded in UTF-8", configPath) + } + var spec rspec.Spec + if err = json.Unmarshal(content, &spec); err != nil { + return Validator{}, err + } + + return NewValidator(&spec, bundlePath, hostSpecific, platform) +} + +// CheckAll checks all parts of runtime bundle +func (v *Validator) CheckAll() error { + var errs *multierror.Error + errs = multierror.Append(errs, v.CheckJSONSchema()) + errs = multierror.Append(errs, v.CheckPlatform()) + errs = multierror.Append(errs, v.CheckRoot()) + errs = multierror.Append(errs, v.CheckMandatoryFields()) + errs = multierror.Append(errs, v.CheckSemVer()) + errs = multierror.Append(errs, v.CheckMounts()) + errs = multierror.Append(errs, v.CheckProcess()) + errs = multierror.Append(errs, v.CheckLinux()) + errs = multierror.Append(errs, v.CheckAnnotations()) + if v.platform == "linux" || v.platform == "solaris" { + errs = multierror.Append(errs, v.CheckHooks()) + } + + return errs.ErrorOrNil() +} + +// JSONSchemaURL returns the URL for the JSON Schema specifying the +// configuration format. It consumes configSchemaTemplate, but we +// provide it as a function to isolate consumers from inconsistent +// naming as runtime-spec evolves. +func JSONSchemaURL(version string) (url string, err error) { + ver, err := semver.Parse(version) + if err != nil { + return "", specerror.NewError(specerror.SpecVersionInSemVer, err, rspec.Version) + } + configRenamedToConfigSchemaVersion, err := semver.Parse("1.0.0-rc2") // config.json became config-schema.json in 1.0.0-rc2 + if ver.Compare(configRenamedToConfigSchemaVersion) == -1 { + return "", fmt.Errorf("unsupported configuration version (older than %s)", configRenamedToConfigSchemaVersion) + } + return fmt.Sprintf(configSchemaTemplate, version), nil +} + +// CheckJSONSchema validates the configuration against the +// runtime-spec JSON Schema, using the version of the schema that +// matches the configuration's declared version. +func (v *Validator) CheckJSONSchema() (errs error) { + logrus.Debugf("check JSON schema") + + url, err := JSONSchemaURL(v.spec.Version) + if err != nil { + errs = multierror.Append(errs, err) + return errs + } + + schemaLoader := gojsonschema.NewReferenceLoader(url) + documentLoader := gojsonschema.NewGoLoader(v.spec) + result, err := gojsonschema.Validate(schemaLoader, documentLoader) + if err != nil { + errs = multierror.Append(errs, err) + return errs + } + + if !result.Valid() { + for _, resultError := range result.Errors() { + errs = multierror.Append(errs, errors.New(resultError.String())) + } + } + + return errs +} + +// CheckRoot checks status of v.spec.Root +func (v *Validator) CheckRoot() (errs error) { + logrus.Debugf("check root") + + if v.platform == "windows" && v.spec.Windows != nil { + if v.spec.Windows.HyperV != nil { + if v.spec.Root != nil { + errs = multierror.Append(errs, + specerror.NewError(specerror.RootOnHyperVNotSet, fmt.Errorf("for Hyper-V containers, Root must not be set"), rspec.Version)) + } + return + } else if v.spec.Root == nil { + errs = multierror.Append(errs, + specerror.NewError(specerror.RootOnWindowsRequired, fmt.Errorf("on Windows, for Windows Server Containers, this field is REQUIRED"), rspec.Version)) + return + } + } else if v.platform != "windows" && v.spec.Root == nil { + errs = multierror.Append(errs, + specerror.NewError(specerror.RootOnNonWindowsRequired, fmt.Errorf("on all other platforms, this field is REQUIRED"), rspec.Version)) + return + } + + if v.platform == "windows" { + matched, err := regexp.MatchString(`\\\\[?]\\Volume[{][a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}[}]\\`, v.spec.Root.Path) + if err != nil { + errs = multierror.Append(errs, err) + } else if !matched { + errs = multierror.Append(errs, + specerror.NewError(specerror.RootPathOnWindowsGUID, fmt.Errorf("root.path is %q, but it MUST be a volume GUID path when target platform is windows", v.spec.Root.Path), rspec.Version)) + } + + if v.spec.Root.Readonly { + errs = multierror.Append(errs, + specerror.NewError(specerror.RootReadonlyOnWindowsFalse, fmt.Errorf("root.readonly field MUST be omitted or false when target platform is windows"), rspec.Version)) + } + + return + } + + absBundlePath, err := filepath.Abs(v.bundlePath) + if err != nil { + errs = multierror.Append(errs, fmt.Errorf("unable to convert %q to an absolute path", v.bundlePath)) + return + } + + if filepath.Base(v.spec.Root.Path) != "rootfs" { + errs = multierror.Append(errs, + specerror.NewError(specerror.RootPathOnPosixConvention, fmt.Errorf("path name should be the conventional 'rootfs'"), rspec.Version)) + } + + var rootfsPath string + var absRootPath string + if filepath.IsAbs(v.spec.Root.Path) { + rootfsPath = v.spec.Root.Path + absRootPath = filepath.Clean(rootfsPath) + } else { + var err error + rootfsPath = filepath.Join(v.bundlePath, v.spec.Root.Path) + absRootPath, err = filepath.Abs(rootfsPath) + if err != nil { + errs = multierror.Append(errs, fmt.Errorf("unable to convert %q to an absolute path", rootfsPath)) + return + } + } + + if fi, err := os.Stat(rootfsPath); err != nil { + errs = multierror.Append(errs, + specerror.NewError(specerror.RootPathExist, fmt.Errorf("cannot find the root path %q", rootfsPath), rspec.Version)) + } else if !fi.IsDir() { + errs = multierror.Append(errs, + specerror.NewError(specerror.RootPathExist, fmt.Errorf("root.path %q is not a directory", rootfsPath), rspec.Version)) + } + + rootParent := filepath.Dir(absRootPath) + if absRootPath == string(filepath.Separator) || rootParent != absBundlePath { + errs = multierror.Append(errs, + specerror.NewError(specerror.ArtifactsInSingleDir, fmt.Errorf("root.path is %q, but it MUST be a child of %q", v.spec.Root.Path, absBundlePath), rspec.Version)) + } + + return +} + +// CheckSemVer checks v.spec.Version +func (v *Validator) CheckSemVer() (errs error) { + logrus.Debugf("check semver") + + version := v.spec.Version + _, err := semver.Parse(version) + if err != nil { + errs = multierror.Append(errs, + specerror.NewError(specerror.SpecVersionInSemVer, fmt.Errorf("%q is not valid SemVer: %s", version, err.Error()), rspec.Version)) + } + if version != rspec.Version { + errs = multierror.Append(errs, fmt.Errorf("validate currently only handles version %s, but the supplied configuration targets %s", rspec.Version, version)) + } + + return +} + +// CheckHooks check v.spec.Hooks +func (v *Validator) CheckHooks() (errs error) { + logrus.Debugf("check hooks") + + if v.platform != "linux" && v.platform != "solaris" { + errs = multierror.Append(errs, fmt.Errorf("For %q platform, the configuration structure does not support hooks", v.platform)) + return + } + + if v.spec.Hooks != nil { + errs = multierror.Append(errs, v.checkEventHooks("prestart", v.spec.Hooks.Prestart, v.HostSpecific)) + errs = multierror.Append(errs, v.checkEventHooks("poststart", v.spec.Hooks.Poststart, v.HostSpecific)) + errs = multierror.Append(errs, v.checkEventHooks("poststop", v.spec.Hooks.Poststop, v.HostSpecific)) + } + + return +} + +func (v *Validator) checkEventHooks(hookType string, hooks []rspec.Hook, hostSpecific bool) (errs error) { + for i, hook := range hooks { + if !osFilepath.IsAbs(v.platform, hook.Path) { + errs = multierror.Append(errs, + specerror.NewError( + specerror.PosixHooksPathAbs, + fmt.Errorf("hooks.%s[%d].path %v: is not absolute path", + hookType, i, hook.Path), + rspec.Version)) + } + + if hostSpecific { + fi, err := os.Stat(hook.Path) + if err != nil { + errs = multierror.Append(errs, fmt.Errorf("cannot find %s hook: %v", hookType, hook.Path)) + } + if fi.Mode()&0111 == 0 { + errs = multierror.Append(errs, fmt.Errorf("the %s hook %v: is not executable", hookType, hook.Path)) + } + } + + for _, env := range hook.Env { + if !envValid(env) { + errs = multierror.Append(errs, fmt.Errorf("env %q for hook %v is in the invalid form", env, hook.Path)) + } + } + } + + return +} + +// CheckProcess checks v.spec.Process +func (v *Validator) CheckProcess() (errs error) { + logrus.Debugf("check process") + + if v.spec.Process == nil { + return + } + + process := v.spec.Process + if !osFilepath.IsAbs(v.platform, process.Cwd) { + errs = multierror.Append(errs, + specerror.NewError( + specerror.ProcCwdAbs, + fmt.Errorf("cwd %q is not an absolute path", process.Cwd), + rspec.Version)) + } + + for _, env := range process.Env { + if !envValid(env) { + errs = multierror.Append(errs, fmt.Errorf("env %q should be in the form of 'key=value'. The left hand side must consist solely of letters, digits, and underscores '_'", env)) + } + } + + if len(process.Args) == 0 { + errs = multierror.Append(errs, + specerror.NewError( + specerror.ProcArgsOneEntryRequired, + fmt.Errorf("args must not be empty"), + rspec.Version)) + } else { + if filepath.IsAbs(process.Args[0]) && v.spec.Root != nil { + var rootfsPath string + if filepath.IsAbs(v.spec.Root.Path) { + rootfsPath = v.spec.Root.Path + } else { + rootfsPath = filepath.Join(v.bundlePath, v.spec.Root.Path) + } + absPath := filepath.Join(rootfsPath, process.Args[0]) + fileinfo, err := os.Stat(absPath) + if os.IsNotExist(err) { + logrus.Warnf("executable %q is not available in rootfs currently", process.Args[0]) + } else if err != nil { + errs = multierror.Append(errs, err) + } else { + m := fileinfo.Mode() + if m.IsDir() || m&0111 == 0 { + errs = multierror.Append(errs, fmt.Errorf("arg %q is not executable", process.Args[0])) + } + } + } + } + + if v.platform == "linux" || v.platform == "solaris" { + errs = multierror.Append(errs, v.CheckRlimits()) + } + + if v.platform == "linux" { + if v.spec.Process.Capabilities != nil { + errs = multierror.Append(errs, v.CheckCapabilities()) + } + + if len(process.ApparmorProfile) > 0 { + profilePath := filepath.Join(v.bundlePath, v.spec.Root.Path, "/etc/apparmor.d", process.ApparmorProfile) + _, err := os.Stat(profilePath) + if err != nil { + errs = multierror.Append(errs, err) + } + } + } + + return +} + +// CheckCapabilities checks v.spec.Process.Capabilities +func (v *Validator) CheckCapabilities() (errs error) { + if v.platform != "linux" { + errs = multierror.Append(errs, fmt.Errorf("For %q platform, the configuration structure does not support process.capabilities", v.platform)) + return + } + + process := v.spec.Process + var effective, permitted, inheritable, ambient bool + caps := make(map[string][]string) + + for _, cap := range process.Capabilities.Bounding { + caps[cap] = append(caps[cap], "bounding") + } + for _, cap := range process.Capabilities.Effective { + caps[cap] = append(caps[cap], "effective") + } + for _, cap := range process.Capabilities.Inheritable { + caps[cap] = append(caps[cap], "inheritable") + } + for _, cap := range process.Capabilities.Permitted { + caps[cap] = append(caps[cap], "permitted") + } + for _, cap := range process.Capabilities.Ambient { + caps[cap] = append(caps[cap], "ambient") + } + + for capability, owns := range caps { + if err := CapValid(capability, v.HostSpecific); err != nil { + errs = multierror.Append(errs, fmt.Errorf("capability %q is not valid, man capabilities(7)", capability)) + } + + effective, permitted, ambient, inheritable = false, false, false, false + for _, set := range owns { + if set == "effective" { + effective = true + continue + } + if set == "inheritable" { + inheritable = true + continue + } + if set == "permitted" { + permitted = true + continue + } + if set == "ambient" { + ambient = true + continue + } + } + if effective && !permitted { + errs = multierror.Append(errs, fmt.Errorf("effective capability %q is not allowed, as it's not permitted", capability)) + } + if ambient && !(permitted && inheritable) { + errs = multierror.Append(errs, fmt.Errorf("ambient capability %q is not allowed, as it's not permitted and inheribate", capability)) + } + } + + return +} + +// CheckRlimits checks v.spec.Process.Rlimits +func (v *Validator) CheckRlimits() (errs error) { + if v.platform != "linux" && v.platform != "solaris" { + errs = multierror.Append(errs, fmt.Errorf("For %q platform, the configuration structure does not support process.rlimits", v.platform)) + return + } + + process := v.spec.Process + for index, rlimit := range process.Rlimits { + for i := index + 1; i < len(process.Rlimits); i++ { + if process.Rlimits[index].Type == process.Rlimits[i].Type { + errs = multierror.Append(errs, + specerror.NewError( + specerror.PosixProcRlimitsErrorOnDup, + fmt.Errorf("rlimit can not contain the same type %q", + process.Rlimits[index].Type), + rspec.Version)) + } + } + errs = multierror.Append(errs, v.rlimitValid(rlimit)) + } + + return +} + +func supportedMountTypes(OS string, hostSpecific bool) (map[string]bool, error) { + supportedTypes := make(map[string]bool) + + if OS != "linux" && OS != "windows" { + logrus.Warnf("%v is not supported to check mount type", OS) + return nil, nil + } else if OS == "windows" { + supportedTypes["ntfs"] = true + return supportedTypes, nil + } + + if hostSpecific { + f, err := os.Open("/proc/filesystems") + if err != nil { + return nil, err + } + defer f.Close() + + s := bufio.NewScanner(f) + for s.Scan() { + if err := s.Err(); err != nil { + return supportedTypes, err + } + + text := s.Text() + parts := strings.Split(text, "\t") + if len(parts) > 1 { + supportedTypes[parts[1]] = true + } else { + supportedTypes[parts[0]] = true + } + } + + supportedTypes["bind"] = true + + return supportedTypes, nil + } + logrus.Warn("Checking linux mount types without --host-specific is not supported yet") + return nil, nil +} + +// CheckMounts checks v.spec.Mounts +func (v *Validator) CheckMounts() (errs error) { + logrus.Debugf("check mounts") + + supportedTypes, err := supportedMountTypes(v.platform, v.HostSpecific) + if err != nil { + errs = multierror.Append(errs, err) + return + } + + for i, mountA := range v.spec.Mounts { + if supportedTypes != nil && !supportedTypes[mountA.Type] { + errs = multierror.Append(errs, fmt.Errorf("unsupported mount type %q", mountA.Type)) + } + if !osFilepath.IsAbs(v.platform, mountA.Destination) { + errs = multierror.Append(errs, + specerror.NewError( + specerror.MountsDestAbs, + fmt.Errorf("mounts[%d].destination %q is not absolute", + i, + mountA.Destination), + rspec.Version)) + } + for j, mountB := range v.spec.Mounts { + if i == j { + continue + } + // whether B.Desination is nested within A.Destination + nested, err := osFilepath.IsAncestor(v.platform, mountA.Destination, mountB.Destination, ".") + if err != nil { + errs = multierror.Append(errs, err) + continue + } + if nested { + if v.platform == "windows" && i < j { + errs = multierror.Append(errs, + specerror.NewError( + specerror.MountsDestOnWindowsNotNested, + fmt.Errorf("on Windows, %v nested within %v is forbidden", + mountB.Destination, mountA.Destination), + rspec.Version)) + } + if i > j { + logrus.Warnf("%v will be covered by %v", mountB.Destination, mountA.Destination) + } + } + } + } + + return +} + +// CheckPlatform checks v.platform +func (v *Validator) CheckPlatform() (errs error) { + logrus.Debugf("check platform") + + if v.platform != "linux" && v.platform != "solaris" && v.platform != "windows" { + errs = multierror.Append(errs, fmt.Errorf("platform %q is not supported", v.platform)) + return + } + + if v.HostSpecific && v.platform != runtime.GOOS { + errs = multierror.Append(errs, fmt.Errorf("platform %q differs from the host %q, skipping host-specific checks", v.platform, runtime.GOOS)) + v.HostSpecific = false + } + + if v.platform == "windows" { + if v.spec.Windows == nil { + errs = multierror.Append(errs, + specerror.NewError( + specerror.PlatformSpecConfOnWindowsSet, + fmt.Errorf("'windows' MUST be set when platform is `windows`"), + rspec.Version)) + } + } + + return +} + +// CheckLinuxResources checks v.spec.Linux.Resources +func (v *Validator) CheckLinuxResources() (errs error) { + logrus.Debugf("check linux resources") + + r := v.spec.Linux.Resources + if r.Memory != nil { + if r.Memory.Limit != nil && r.Memory.Swap != nil && uint64(*r.Memory.Limit) > uint64(*r.Memory.Swap) { + errs = multierror.Append(errs, fmt.Errorf("minimum memoryswap should be larger than memory limit")) + } + if r.Memory.Limit != nil && r.Memory.Reservation != nil && uint64(*r.Memory.Reservation) > uint64(*r.Memory.Limit) { + errs = multierror.Append(errs, fmt.Errorf("minimum memory limit should be larger than memory reservation")) + } + } + if r.Network != nil && v.HostSpecific { + var exist bool + interfaces, err := net.Interfaces() + if err != nil { + errs = multierror.Append(errs, err) + return + } + for _, prio := range r.Network.Priorities { + exist = false + for _, ni := range interfaces { + if prio.Name == ni.Name { + exist = true + break + } + } + if !exist { + errs = multierror.Append(errs, fmt.Errorf("interface %s does not exist currently", prio.Name)) + } + } + } + for index := 0; index < len(r.Devices); index++ { + switch r.Devices[index].Type { + case "a", "b", "c", "": + default: + errs = multierror.Append(errs, fmt.Errorf("type of devices %s is invalid", r.Devices[index].Type)) + } + + access := []byte(r.Devices[index].Access) + for i := 0; i < len(access); i++ { + switch access[i] { + case 'r', 'w', 'm': + default: + errs = multierror.Append(errs, fmt.Errorf("access %s is invalid", r.Devices[index].Access)) + return + } + } + } + + if r.BlockIO != nil && r.BlockIO.WeightDevice != nil { + for i, weightDevice := range r.BlockIO.WeightDevice { + if weightDevice.Weight == nil && weightDevice.LeafWeight == nil { + errs = multierror.Append(errs, + specerror.NewError( + specerror.BlkIOWeightOrLeafWeightExist, + fmt.Errorf("linux.resources.blockIO.weightDevice[%d] specifies neither weight nor leafWeight", i), + rspec.Version)) + } + } + } + + return +} + +// CheckAnnotations checks v.spec.Annotations +func (v *Validator) CheckAnnotations() (errs error) { + logrus.Debugf("check annotations") + + reversedDomain := regexp.MustCompile(`^[A-Za-z]{2,6}(\.[A-Za-z0-9-]{1,63})+$`) + for key := range v.spec.Annotations { + if strings.HasPrefix(key, "org.opencontainers") { + errs = multierror.Append(errs, + specerror.NewError( + specerror.AnnotationsKeyReservedNS, + fmt.Errorf("key %q is reserved", key), + rspec.Version)) + } + + if !reversedDomain.MatchString(key) { + errs = multierror.Append(errs, + specerror.NewError( + specerror.AnnotationsKeyReversedDomain, + fmt.Errorf("key %q SHOULD be named using a reverse domain notation", key), + rspec.Version)) + } + } + + return +} + +// CapValid checks whether a capability is valid +func CapValid(c string, hostSpecific bool) error { + isValid := false + + if !strings.HasPrefix(c, "CAP_") { + return fmt.Errorf("capability %s must start with CAP_", c) + } + for _, cap := range capability.List() { + if c == fmt.Sprintf("CAP_%s", strings.ToUpper(cap.String())) { + if hostSpecific && cap > LastCap() { + return fmt.Errorf("%s is not supported on the current host", c) + } + isValid = true + break + } + } + + if !isValid { + return fmt.Errorf("invalid capability: %s", c) + } + return nil +} + +func envValid(env string) bool { + items := strings.Split(env, "=") + if len(items) < 2 { + return false + } + for i, ch := range strings.TrimSpace(items[0]) { + if !unicode.IsDigit(ch) && !unicode.IsLetter(ch) && ch != '_' { + return false + } + if i == 0 && unicode.IsDigit(ch) { + logrus.Warnf("Env %v: variable name beginning with digit is not recommended.", env) + } + } + return true +} + +func (v *Validator) rlimitValid(rlimit rspec.POSIXRlimit) (errs error) { + if rlimit.Hard < rlimit.Soft { + errs = multierror.Append(errs, fmt.Errorf("hard limit of rlimit %s should not be less than soft limit", rlimit.Type)) + } + + if v.platform == "linux" { + for _, val := range linuxRlimits { + if val == rlimit.Type { + return + } + } + errs = multierror.Append(errs, specerror.NewError(specerror.PosixProcRlimitsTypeValueError, fmt.Errorf("rlimit type %q may not be valid", rlimit.Type), v.spec.Version)) + } else if v.platform == "solaris" { + for _, val := range posixRlimits { + if val == rlimit.Type { + return + } + } + errs = multierror.Append(errs, specerror.NewError(specerror.PosixProcRlimitsTypeValueError, fmt.Errorf("rlimit type %q may not be valid", rlimit.Type), v.spec.Version)) + } else { + logrus.Warnf("process.rlimits validation not yet implemented for platform %q", v.platform) + } + + return +} + +func isStruct(t reflect.Type) bool { + return t.Kind() == reflect.Struct +} + +func isStructPtr(t reflect.Type) bool { + return t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct +} + +func checkMandatoryUnit(field reflect.Value, tagField reflect.StructField, parent string) (errs error) { + mandatory := !strings.Contains(tagField.Tag.Get("json"), "omitempty") + switch field.Kind() { + case reflect.Ptr: + if mandatory && field.IsNil() { + errs = multierror.Append(errs, fmt.Errorf("'%s.%s' should not be empty", parent, tagField.Name)) + } + case reflect.String: + if mandatory && (field.Len() == 0) { + errs = multierror.Append(errs, fmt.Errorf("'%s.%s' should not be empty", parent, tagField.Name)) + } + case reflect.Slice: + if mandatory && (field.IsNil() || field.Len() == 0) { + errs = multierror.Append(errs, fmt.Errorf("'%s.%s' should not be empty", parent, tagField.Name)) + return + } + for index := 0; index < field.Len(); index++ { + mValue := field.Index(index) + if mValue.CanInterface() { + errs = multierror.Append(errs, checkMandatory(mValue.Interface())) + } + } + case reflect.Map: + if mandatory && (field.IsNil() || field.Len() == 0) { + errs = multierror.Append(errs, fmt.Errorf("'%s.%s' should not be empty", parent, tagField.Name)) + return + } + keys := field.MapKeys() + for index := 0; index < len(keys); index++ { + mValue := field.MapIndex(keys[index]) + if mValue.CanInterface() { + errs = multierror.Append(errs, checkMandatory(mValue.Interface())) + } + } + default: + } + + return +} + +func checkMandatory(obj interface{}) (errs error) { + objT := reflect.TypeOf(obj) + objV := reflect.ValueOf(obj) + if isStructPtr(objT) { + objT = objT.Elem() + objV = objV.Elem() + } else if !isStruct(objT) { + return + } + + for i := 0; i < objT.NumField(); i++ { + t := objT.Field(i).Type + if isStructPtr(t) && objV.Field(i).IsNil() { + if !strings.Contains(objT.Field(i).Tag.Get("json"), "omitempty") { + errs = multierror.Append(errs, fmt.Errorf("'%s.%s' should not be empty", objT.Name(), objT.Field(i).Name)) + } + } else if (isStruct(t) || isStructPtr(t)) && objV.Field(i).CanInterface() { + errs = multierror.Append(errs, checkMandatory(objV.Field(i).Interface())) + } else { + errs = multierror.Append(errs, checkMandatoryUnit(objV.Field(i), objT.Field(i), objT.Name())) + } + + } + return +} + +// CheckMandatoryFields checks mandatory field of container's config file +func (v *Validator) CheckMandatoryFields() error { + logrus.Debugf("check mandatory fields") + + if v.spec == nil { + return fmt.Errorf("Spec can't be nil") + } + + return checkMandatory(v.spec) +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/validate/validate_linux.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/validate/validate_linux.go new file mode 100644 index 0000000000..8d452c2090 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/validate/validate_linux.go @@ -0,0 +1,230 @@ +// +build linux + +package validate + +import ( + "errors" + "fmt" + "os" + "path/filepath" + "strings" + "syscall" + + "github.com/syndtr/gocapability/capability" + + multierror "github.com/hashicorp/go-multierror" + rspec "github.com/opencontainers/runtime-spec/specs-go" + osFilepath "github.com/opencontainers/runtime-tools/filepath" + "github.com/opencontainers/runtime-tools/specerror" + "github.com/sirupsen/logrus" +) + +// LastCap return last cap of system +func LastCap() capability.Cap { + last := capability.CAP_LAST_CAP + // hack for RHEL6 which has no /proc/sys/kernel/cap_last_cap + if last == capability.Cap(63) { + last = capability.CAP_BLOCK_SUSPEND + } + + return last +} + +func deviceValid(d rspec.LinuxDevice) bool { + switch d.Type { + case "b", "c", "u": + if d.Major <= 0 || d.Minor <= 0 { + return false + } + case "p": + if d.Major != 0 || d.Minor != 0 { + return false + } + default: + return false + } + return true +} + +// CheckLinux checks v.spec.Linux +func (v *Validator) CheckLinux() (errs error) { + logrus.Debugf("check linux") + + if v.spec.Linux == nil { + return + } + + var nsTypeList = map[rspec.LinuxNamespaceType]struct { + num int + newExist bool + }{ + rspec.PIDNamespace: {0, false}, + rspec.NetworkNamespace: {0, false}, + rspec.MountNamespace: {0, false}, + rspec.IPCNamespace: {0, false}, + rspec.UTSNamespace: {0, false}, + rspec.UserNamespace: {0, false}, + rspec.CgroupNamespace: {0, false}, + } + + for index := 0; index < len(v.spec.Linux.Namespaces); index++ { + ns := v.spec.Linux.Namespaces[index] + if ns.Path != "" && !osFilepath.IsAbs(v.platform, ns.Path) { + errs = multierror.Append(errs, specerror.NewError(specerror.NSPathAbs, fmt.Errorf("namespace.path %q is not an absolute path", ns.Path), rspec.Version)) + } + + tmpItem := nsTypeList[ns.Type] + tmpItem.num = tmpItem.num + 1 + if tmpItem.num > 1 { + errs = multierror.Append(errs, specerror.NewError(specerror.NSErrorOnDup, fmt.Errorf("duplicated namespace %q", ns.Type), rspec.Version)) + } + + if len(ns.Path) == 0 { + tmpItem.newExist = true + } + nsTypeList[ns.Type] = tmpItem + } + + if (len(v.spec.Linux.UIDMappings) > 0 || len(v.spec.Linux.GIDMappings) > 0) && !nsTypeList[rspec.UserNamespace].newExist { + errs = multierror.Append(errs, errors.New("the UID/GID mappings requires a new User namespace to be specified as well")) + } + + for k := range v.spec.Linux.Sysctl { + if strings.HasPrefix(k, "net.") && !nsTypeList[rspec.NetworkNamespace].newExist { + errs = multierror.Append(errs, fmt.Errorf("sysctl %v requires a new Network namespace to be specified as well", k)) + } + if strings.HasPrefix(k, "fs.mqueue.") { + if !nsTypeList[rspec.MountNamespace].newExist || !nsTypeList[rspec.IPCNamespace].newExist { + errs = multierror.Append(errs, fmt.Errorf("sysctl %v requires a new IPC namespace and Mount namespace to be specified as well", k)) + } + } + } + + if v.platform == "linux" && !nsTypeList[rspec.UTSNamespace].newExist && v.spec.Hostname != "" { + errs = multierror.Append(errs, fmt.Errorf("on Linux, hostname requires a new UTS namespace to be specified as well")) + } + + // Linux devices validation + devList := make(map[string]bool) + devTypeList := make(map[string]bool) + for index := 0; index < len(v.spec.Linux.Devices); index++ { + device := v.spec.Linux.Devices[index] + if !deviceValid(device) { + errs = multierror.Append(errs, fmt.Errorf("device %v is invalid", device)) + } + + if _, exists := devList[device.Path]; exists { + errs = multierror.Append(errs, fmt.Errorf("device %s is duplicated", device.Path)) + } else { + var rootfsPath string + if filepath.IsAbs(v.spec.Root.Path) { + rootfsPath = v.spec.Root.Path + } else { + rootfsPath = filepath.Join(v.bundlePath, v.spec.Root.Path) + } + absPath := filepath.Join(rootfsPath, device.Path) + fi, err := os.Stat(absPath) + if os.IsNotExist(err) { + devList[device.Path] = true + } else if err != nil { + errs = multierror.Append(errs, err) + } else { + fStat, ok := fi.Sys().(*syscall.Stat_t) + if !ok { + errs = multierror.Append(errs, specerror.NewError(specerror.DevicesAvailable, + fmt.Errorf("cannot determine state for device %s", device.Path), rspec.Version)) + continue + } + var devType string + switch fStat.Mode & syscall.S_IFMT { + case syscall.S_IFCHR: + devType = "c" + case syscall.S_IFBLK: + devType = "b" + case syscall.S_IFIFO: + devType = "p" + default: + devType = "unmatched" + } + if devType != device.Type || (devType == "c" && device.Type == "u") { + errs = multierror.Append(errs, specerror.NewError(specerror.DevicesFileNotMatch, + fmt.Errorf("unmatched %s already exists in filesystem", device.Path), rspec.Version)) + continue + } + if devType != "p" { + dev := fStat.Rdev + major := (dev >> 8) & 0xfff + minor := (dev & 0xff) | ((dev >> 12) & 0xfff00) + if int64(major) != device.Major || int64(minor) != device.Minor { + errs = multierror.Append(errs, specerror.NewError(specerror.DevicesFileNotMatch, + fmt.Errorf("unmatched %s already exists in filesystem", device.Path), rspec.Version)) + continue + } + } + if device.FileMode != nil { + expectedPerm := *device.FileMode & os.ModePerm + actualPerm := fi.Mode() & os.ModePerm + if expectedPerm != actualPerm { + errs = multierror.Append(errs, specerror.NewError(specerror.DevicesFileNotMatch, + fmt.Errorf("unmatched %s already exists in filesystem", device.Path), rspec.Version)) + continue + } + } + if device.UID != nil { + if *device.UID != fStat.Uid { + errs = multierror.Append(errs, specerror.NewError(specerror.DevicesFileNotMatch, + fmt.Errorf("unmatched %s already exists in filesystem", device.Path), rspec.Version)) + continue + } + } + if device.GID != nil { + if *device.GID != fStat.Gid { + errs = multierror.Append(errs, specerror.NewError(specerror.DevicesFileNotMatch, + fmt.Errorf("unmatched %s already exists in filesystem", device.Path), rspec.Version)) + continue + } + } + } + } + + // unify u->c when comparing, they are synonyms + var devID string + if device.Type == "u" { + devID = fmt.Sprintf("%s:%d:%d", "c", device.Major, device.Minor) + } else { + devID = fmt.Sprintf("%s:%d:%d", device.Type, device.Major, device.Minor) + } + + if _, exists := devTypeList[devID]; exists { + logrus.Warnf("%v", specerror.NewError(specerror.DevicesErrorOnDup, fmt.Errorf("type:%s, major:%d and minor:%d for linux devices is duplicated", device.Type, device.Major, device.Minor), rspec.Version)) + } else { + devTypeList[devID] = true + } + } + + if v.spec.Linux.Resources != nil { + errs = multierror.Append(errs, v.CheckLinuxResources()) + } + + for _, maskedPath := range v.spec.Linux.MaskedPaths { + if !strings.HasPrefix(maskedPath, "/") { + errs = multierror.Append(errs, + specerror.NewError( + specerror.MaskedPathsAbs, + fmt.Errorf("maskedPath %v is not an absolute path", maskedPath), + rspec.Version)) + } + } + + for _, readonlyPath := range v.spec.Linux.ReadonlyPaths { + if !strings.HasPrefix(readonlyPath, "/") { + errs = multierror.Append(errs, + specerror.NewError( + specerror.ReadonlyPathsAbs, + fmt.Errorf("readonlyPath %v is not an absolute path", readonlyPath), + rspec.Version)) + } + } + + return +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/validate/validate_unsupported.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/validate/validate_unsupported.go new file mode 100644 index 0000000000..f150c326c1 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/opencontainers/runtime-tools/validate/validate_unsupported.go @@ -0,0 +1,17 @@ +// +build !linux + +package validate + +import ( + "github.com/syndtr/gocapability/capability" +) + +// LastCap return last cap of system +func LastCap() capability.Cap { + return capability.Cap(-1) +} + +// CheckLinux is a noop on this platform +func (v *Validator) CheckLinux() (errs error) { + return nil +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/pkg/errors/LICENSE b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/pkg/errors/LICENSE new file mode 100644 index 0000000000..835ba3e755 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/pkg/errors/LICENSE @@ -0,0 +1,23 @@ +Copyright (c) 2015, Dave Cheney +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/pkg/errors/README.md b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/pkg/errors/README.md new file mode 100644 index 0000000000..6483ba2afb --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/pkg/errors/README.md @@ -0,0 +1,52 @@ +# errors [![Travis-CI](https://travis-ci.org/pkg/errors.svg)](https://travis-ci.org/pkg/errors) [![AppVeyor](https://ci.appveyor.com/api/projects/status/b98mptawhudj53ep/branch/master?svg=true)](https://ci.appveyor.com/project/davecheney/errors/branch/master) [![GoDoc](https://godoc.org/github.com/pkg/errors?status.svg)](http://godoc.org/github.com/pkg/errors) [![Report card](https://goreportcard.com/badge/github.com/pkg/errors)](https://goreportcard.com/report/github.com/pkg/errors) [![Sourcegraph](https://sourcegraph.com/github.com/pkg/errors/-/badge.svg)](https://sourcegraph.com/github.com/pkg/errors?badge) + +Package errors provides simple error handling primitives. + +`go get github.com/pkg/errors` + +The traditional error handling idiom in Go is roughly akin to +```go +if err != nil { + return err +} +``` +which applied recursively up the call stack results in error reports without context or debugging information. The errors package allows programmers to add context to the failure path in their code in a way that does not destroy the original value of the error. + +## Adding context to an error + +The errors.Wrap function returns a new error that adds context to the original error. For example +```go +_, err := ioutil.ReadAll(r) +if err != nil { + return errors.Wrap(err, "read failed") +} +``` +## Retrieving the cause of an error + +Using `errors.Wrap` constructs a stack of errors, adding context to the preceding error. Depending on the nature of the error it may be necessary to reverse the operation of errors.Wrap to retrieve the original error for inspection. Any error value which implements this interface can be inspected by `errors.Cause`. +```go +type causer interface { + Cause() error +} +``` +`errors.Cause` will recursively retrieve the topmost error which does not implement `causer`, which is assumed to be the original cause. For example: +```go +switch err := errors.Cause(err).(type) { +case *MyError: + // handle specifically +default: + // unknown error +} +``` + +[Read the package documentation for more information](https://godoc.org/github.com/pkg/errors). + +## Contributing + +We welcome pull requests, bug fixes and issue reports. With that said, the bar for adding new symbols to this package is intentionally set high. + +Before proposing a change, please discuss your change by raising an issue. + +## License + +BSD-2-Clause diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/pkg/errors/errors.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/pkg/errors/errors.go new file mode 100644 index 0000000000..7421f326ff --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/pkg/errors/errors.go @@ -0,0 +1,282 @@ +// Package errors provides simple error handling primitives. +// +// The traditional error handling idiom in Go is roughly akin to +// +// if err != nil { +// return err +// } +// +// which when applied recursively up the call stack results in error reports +// without context or debugging information. The errors package allows +// programmers to add context to the failure path in their code in a way +// that does not destroy the original value of the error. +// +// Adding context to an error +// +// The errors.Wrap function returns a new error that adds context to the +// original error by recording a stack trace at the point Wrap is called, +// together with the supplied message. For example +// +// _, err := ioutil.ReadAll(r) +// if err != nil { +// return errors.Wrap(err, "read failed") +// } +// +// If additional control is required, the errors.WithStack and +// errors.WithMessage functions destructure errors.Wrap into its component +// operations: annotating an error with a stack trace and with a message, +// respectively. +// +// Retrieving the cause of an error +// +// Using errors.Wrap constructs a stack of errors, adding context to the +// preceding error. Depending on the nature of the error it may be necessary +// to reverse the operation of errors.Wrap to retrieve the original error +// for inspection. Any error value which implements this interface +// +// type causer interface { +// Cause() error +// } +// +// can be inspected by errors.Cause. errors.Cause will recursively retrieve +// the topmost error that does not implement causer, which is assumed to be +// the original cause. For example: +// +// switch err := errors.Cause(err).(type) { +// case *MyError: +// // handle specifically +// default: +// // unknown error +// } +// +// Although the causer interface is not exported by this package, it is +// considered a part of its stable public interface. +// +// Formatted printing of errors +// +// All error values returned from this package implement fmt.Formatter and can +// be formatted by the fmt package. The following verbs are supported: +// +// %s print the error. If the error has a Cause it will be +// printed recursively. +// %v see %s +// %+v extended format. Each Frame of the error's StackTrace will +// be printed in detail. +// +// Retrieving the stack trace of an error or wrapper +// +// New, Errorf, Wrap, and Wrapf record a stack trace at the point they are +// invoked. This information can be retrieved with the following interface: +// +// type stackTracer interface { +// StackTrace() errors.StackTrace +// } +// +// The returned errors.StackTrace type is defined as +// +// type StackTrace []Frame +// +// The Frame type represents a call site in the stack trace. Frame supports +// the fmt.Formatter interface that can be used for printing information about +// the stack trace of this error. For example: +// +// if err, ok := err.(stackTracer); ok { +// for _, f := range err.StackTrace() { +// fmt.Printf("%+s:%d", f) +// } +// } +// +// Although the stackTracer interface is not exported by this package, it is +// considered a part of its stable public interface. +// +// See the documentation for Frame.Format for more details. +package errors + +import ( + "fmt" + "io" +) + +// New returns an error with the supplied message. +// New also records the stack trace at the point it was called. +func New(message string) error { + return &fundamental{ + msg: message, + stack: callers(), + } +} + +// Errorf formats according to a format specifier and returns the string +// as a value that satisfies error. +// Errorf also records the stack trace at the point it was called. +func Errorf(format string, args ...interface{}) error { + return &fundamental{ + msg: fmt.Sprintf(format, args...), + stack: callers(), + } +} + +// fundamental is an error that has a message and a stack, but no caller. +type fundamental struct { + msg string + *stack +} + +func (f *fundamental) Error() string { return f.msg } + +func (f *fundamental) Format(s fmt.State, verb rune) { + switch verb { + case 'v': + if s.Flag('+') { + io.WriteString(s, f.msg) + f.stack.Format(s, verb) + return + } + fallthrough + case 's': + io.WriteString(s, f.msg) + case 'q': + fmt.Fprintf(s, "%q", f.msg) + } +} + +// WithStack annotates err with a stack trace at the point WithStack was called. +// If err is nil, WithStack returns nil. +func WithStack(err error) error { + if err == nil { + return nil + } + return &withStack{ + err, + callers(), + } +} + +type withStack struct { + error + *stack +} + +func (w *withStack) Cause() error { return w.error } + +func (w *withStack) Format(s fmt.State, verb rune) { + switch verb { + case 'v': + if s.Flag('+') { + fmt.Fprintf(s, "%+v", w.Cause()) + w.stack.Format(s, verb) + return + } + fallthrough + case 's': + io.WriteString(s, w.Error()) + case 'q': + fmt.Fprintf(s, "%q", w.Error()) + } +} + +// Wrap returns an error annotating err with a stack trace +// at the point Wrap is called, and the supplied message. +// If err is nil, Wrap returns nil. +func Wrap(err error, message string) error { + if err == nil { + return nil + } + err = &withMessage{ + cause: err, + msg: message, + } + return &withStack{ + err, + callers(), + } +} + +// Wrapf returns an error annotating err with a stack trace +// at the point Wrapf is called, and the format specifier. +// If err is nil, Wrapf returns nil. +func Wrapf(err error, format string, args ...interface{}) error { + if err == nil { + return nil + } + err = &withMessage{ + cause: err, + msg: fmt.Sprintf(format, args...), + } + return &withStack{ + err, + callers(), + } +} + +// WithMessage annotates err with a new message. +// If err is nil, WithMessage returns nil. +func WithMessage(err error, message string) error { + if err == nil { + return nil + } + return &withMessage{ + cause: err, + msg: message, + } +} + +// WithMessagef annotates err with the format specifier. +// If err is nil, WithMessagef returns nil. +func WithMessagef(err error, format string, args ...interface{}) error { + if err == nil { + return nil + } + return &withMessage{ + cause: err, + msg: fmt.Sprintf(format, args...), + } +} + +type withMessage struct { + cause error + msg string +} + +func (w *withMessage) Error() string { return w.msg + ": " + w.cause.Error() } +func (w *withMessage) Cause() error { return w.cause } + +func (w *withMessage) Format(s fmt.State, verb rune) { + switch verb { + case 'v': + if s.Flag('+') { + fmt.Fprintf(s, "%+v\n", w.Cause()) + io.WriteString(s, w.msg) + return + } + fallthrough + case 's', 'q': + io.WriteString(s, w.Error()) + } +} + +// Cause returns the underlying cause of the error, if possible. +// An error value has a cause if it implements the following +// interface: +// +// type causer interface { +// Cause() error +// } +// +// If the error does not implement Cause, the original error will +// be returned. If the error is nil, nil will be returned without further +// investigation. +func Cause(err error) error { + type causer interface { + Cause() error + } + + for err != nil { + cause, ok := err.(causer) + if !ok { + break + } + err = cause.Cause() + } + return err +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/pkg/errors/stack.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/pkg/errors/stack.go new file mode 100644 index 0000000000..2874a048cf --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/pkg/errors/stack.go @@ -0,0 +1,147 @@ +package errors + +import ( + "fmt" + "io" + "path" + "runtime" + "strings" +) + +// Frame represents a program counter inside a stack frame. +type Frame uintptr + +// pc returns the program counter for this frame; +// multiple frames may have the same PC value. +func (f Frame) pc() uintptr { return uintptr(f) - 1 } + +// file returns the full path to the file that contains the +// function for this Frame's pc. +func (f Frame) file() string { + fn := runtime.FuncForPC(f.pc()) + if fn == nil { + return "unknown" + } + file, _ := fn.FileLine(f.pc()) + return file +} + +// line returns the line number of source code of the +// function for this Frame's pc. +func (f Frame) line() int { + fn := runtime.FuncForPC(f.pc()) + if fn == nil { + return 0 + } + _, line := fn.FileLine(f.pc()) + return line +} + +// Format formats the frame according to the fmt.Formatter interface. +// +// %s source file +// %d source line +// %n function name +// %v equivalent to %s:%d +// +// Format accepts flags that alter the printing of some verbs, as follows: +// +// %+s function name and path of source file relative to the compile time +// GOPATH separated by \n\t (\n\t) +// %+v equivalent to %+s:%d +func (f Frame) Format(s fmt.State, verb rune) { + switch verb { + case 's': + switch { + case s.Flag('+'): + pc := f.pc() + fn := runtime.FuncForPC(pc) + if fn == nil { + io.WriteString(s, "unknown") + } else { + file, _ := fn.FileLine(pc) + fmt.Fprintf(s, "%s\n\t%s", fn.Name(), file) + } + default: + io.WriteString(s, path.Base(f.file())) + } + case 'd': + fmt.Fprintf(s, "%d", f.line()) + case 'n': + name := runtime.FuncForPC(f.pc()).Name() + io.WriteString(s, funcname(name)) + case 'v': + f.Format(s, 's') + io.WriteString(s, ":") + f.Format(s, 'd') + } +} + +// StackTrace is stack of Frames from innermost (newest) to outermost (oldest). +type StackTrace []Frame + +// Format formats the stack of Frames according to the fmt.Formatter interface. +// +// %s lists source files for each Frame in the stack +// %v lists the source file and line number for each Frame in the stack +// +// Format accepts flags that alter the printing of some verbs, as follows: +// +// %+v Prints filename, function, and line number for each Frame in the stack. +func (st StackTrace) Format(s fmt.State, verb rune) { + switch verb { + case 'v': + switch { + case s.Flag('+'): + for _, f := range st { + fmt.Fprintf(s, "\n%+v", f) + } + case s.Flag('#'): + fmt.Fprintf(s, "%#v", []Frame(st)) + default: + fmt.Fprintf(s, "%v", []Frame(st)) + } + case 's': + fmt.Fprintf(s, "%s", []Frame(st)) + } +} + +// stack represents a stack of program counters. +type stack []uintptr + +func (s *stack) Format(st fmt.State, verb rune) { + switch verb { + case 'v': + switch { + case st.Flag('+'): + for _, pc := range *s { + f := Frame(pc) + fmt.Fprintf(st, "\n%+v", f) + } + } + } +} + +func (s *stack) StackTrace() StackTrace { + f := make([]Frame, len(*s)) + for i := 0; i < len(f); i++ { + f[i] = Frame((*s)[i]) + } + return f +} + +func callers() *stack { + const depth = 32 + var pcs [depth]uintptr + n := runtime.Callers(3, pcs[:]) + var st stack = pcs[0:n] + return &st +} + +// funcname removes the path prefix component of a function's name reported by func.Name(). +func funcname(name string) string { + i := strings.LastIndex(name, "/") + name = name[i+1:] + i = strings.Index(name, ".") + return name[i+1:] +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/LICENSE b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/LICENSE new file mode 100644 index 0000000000..f090cb42f3 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Simon Eskildsen + +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. diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/README.md b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/README.md new file mode 100644 index 0000000000..3987310551 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/README.md @@ -0,0 +1,494 @@ +# Logrus :walrus: [![Build Status](https://travis-ci.org/sirupsen/logrus.svg?branch=master)](https://travis-ci.org/sirupsen/logrus) [![GoDoc](https://godoc.org/github.com/sirupsen/logrus?status.svg)](https://godoc.org/github.com/sirupsen/logrus) + +Logrus is a structured logger for Go (golang), completely API compatible with +the standard library logger. + +**Seeing weird case-sensitive problems?** It's in the past been possible to +import Logrus as both upper- and lower-case. Due to the Go package environment, +this caused issues in the community and we needed a standard. Some environments +experienced problems with the upper-case variant, so the lower-case was decided. +Everything using `logrus` will need to use the lower-case: +`github.com/sirupsen/logrus`. Any package that isn't, should be changed. + +To fix Glide, see [these +comments](https://github.com/sirupsen/logrus/issues/553#issuecomment-306591437). +For an in-depth explanation of the casing issue, see [this +comment](https://github.com/sirupsen/logrus/issues/570#issuecomment-313933276). + +**Are you interested in assisting in maintaining Logrus?** Currently I have a +lot of obligations, and I am unable to provide Logrus with the maintainership it +needs. If you'd like to help, please reach out to me at `simon at author's +username dot com`. + +Nicely color-coded in development (when a TTY is attached, otherwise just +plain text): + +![Colored](http://i.imgur.com/PY7qMwd.png) + +With `log.SetFormatter(&log.JSONFormatter{})`, for easy parsing by logstash +or Splunk: + +```json +{"animal":"walrus","level":"info","msg":"A group of walrus emerges from the +ocean","size":10,"time":"2014-03-10 19:57:38.562264131 -0400 EDT"} + +{"level":"warning","msg":"The group's number increased tremendously!", +"number":122,"omg":true,"time":"2014-03-10 19:57:38.562471297 -0400 EDT"} + +{"animal":"walrus","level":"info","msg":"A giant walrus appears!", +"size":10,"time":"2014-03-10 19:57:38.562500591 -0400 EDT"} + +{"animal":"walrus","level":"info","msg":"Tremendously sized cow enters the ocean.", +"size":9,"time":"2014-03-10 19:57:38.562527896 -0400 EDT"} + +{"level":"fatal","msg":"The ice breaks!","number":100,"omg":true, +"time":"2014-03-10 19:57:38.562543128 -0400 EDT"} +``` + +With the default `log.SetFormatter(&log.TextFormatter{})` when a TTY is not +attached, the output is compatible with the +[logfmt](http://godoc.org/github.com/kr/logfmt) format: + +```text +time="2015-03-26T01:27:38-04:00" level=debug msg="Started observing beach" animal=walrus number=8 +time="2015-03-26T01:27:38-04:00" level=info msg="A group of walrus emerges from the ocean" animal=walrus size=10 +time="2015-03-26T01:27:38-04:00" level=warning msg="The group's number increased tremendously!" number=122 omg=true +time="2015-03-26T01:27:38-04:00" level=debug msg="Temperature changes" temperature=-4 +time="2015-03-26T01:27:38-04:00" level=panic msg="It's over 9000!" animal=orca size=9009 +time="2015-03-26T01:27:38-04:00" level=fatal msg="The ice breaks!" err=&{0x2082280c0 map[animal:orca size:9009] 2015-03-26 01:27:38.441574009 -0400 EDT panic It's over 9000!} number=100 omg=true +``` +To ensure this behaviour even if a TTY is attached, set your formatter as follows: + +```go + log.SetFormatter(&log.TextFormatter{ + DisableColors: true, + FullTimestamp: true, + }) +``` + +#### Logging Method Name + +If you wish to add the calling method as a field, instruct the logger via: +```go +log.SetReportCaller(true) +``` +This adds the caller as 'method' like so: + +```json +{"animal":"penguin","level":"fatal","method":"github.com/sirupsen/arcticcreatures.migrate","msg":"a penguin swims by", +"time":"2014-03-10 19:57:38.562543129 -0400 EDT"} +``` + +```text +time="2015-03-26T01:27:38-04:00" level=fatal method=github.com/sirupsen/arcticcreatures.migrate msg="a penguin swims by" animal=penguin +``` +Note that this does add measurable overhead - the cost will depend on the version of Go, but is +between 20 and 40% in recent tests with 1.6 and 1.7. You can validate this in your +environment via benchmarks: +``` +go test -bench=.*CallerTracing +``` + + +#### Case-sensitivity + +The organization's name was changed to lower-case--and this will not be changed +back. If you are getting import conflicts due to case sensitivity, please use +the lower-case import: `github.com/sirupsen/logrus`. + +#### Example + +The simplest way to use Logrus is simply the package-level exported logger: + +```go +package main + +import ( + log "github.com/sirupsen/logrus" +) + +func main() { + log.WithFields(log.Fields{ + "animal": "walrus", + }).Info("A walrus appears") +} +``` + +Note that it's completely api-compatible with the stdlib logger, so you can +replace your `log` imports everywhere with `log "github.com/sirupsen/logrus"` +and you'll now have the flexibility of Logrus. You can customize it all you +want: + +```go +package main + +import ( + "os" + log "github.com/sirupsen/logrus" +) + +func init() { + // Log as JSON instead of the default ASCII formatter. + log.SetFormatter(&log.JSONFormatter{}) + + // Output to stdout instead of the default stderr + // Can be any io.Writer, see below for File example + log.SetOutput(os.Stdout) + + // Only log the warning severity or above. + log.SetLevel(log.WarnLevel) +} + +func main() { + log.WithFields(log.Fields{ + "animal": "walrus", + "size": 10, + }).Info("A group of walrus emerges from the ocean") + + log.WithFields(log.Fields{ + "omg": true, + "number": 122, + }).Warn("The group's number increased tremendously!") + + log.WithFields(log.Fields{ + "omg": true, + "number": 100, + }).Fatal("The ice breaks!") + + // A common pattern is to re-use fields between logging statements by re-using + // the logrus.Entry returned from WithFields() + contextLogger := log.WithFields(log.Fields{ + "common": "this is a common field", + "other": "I also should be logged always", + }) + + contextLogger.Info("I'll be logged with common and other field") + contextLogger.Info("Me too") +} +``` + +For more advanced usage such as logging to multiple locations from the same +application, you can also create an instance of the `logrus` Logger: + +```go +package main + +import ( + "os" + "github.com/sirupsen/logrus" +) + +// Create a new instance of the logger. You can have any number of instances. +var log = logrus.New() + +func main() { + // The API for setting attributes is a little different than the package level + // exported logger. See Godoc. + log.Out = os.Stdout + + // You could set this to any `io.Writer` such as a file + // file, err := os.OpenFile("logrus.log", os.O_CREATE|os.O_WRONLY, 0666) + // if err == nil { + // log.Out = file + // } else { + // log.Info("Failed to log to file, using default stderr") + // } + + log.WithFields(logrus.Fields{ + "animal": "walrus", + "size": 10, + }).Info("A group of walrus emerges from the ocean") +} +``` + +#### Fields + +Logrus encourages careful, structured logging through logging fields instead of +long, unparseable error messages. For example, instead of: `log.Fatalf("Failed +to send event %s to topic %s with key %d")`, you should log the much more +discoverable: + +```go +log.WithFields(log.Fields{ + "event": event, + "topic": topic, + "key": key, +}).Fatal("Failed to send event") +``` + +We've found this API forces you to think about logging in a way that produces +much more useful logging messages. We've been in countless situations where just +a single added field to a log statement that was already there would've saved us +hours. The `WithFields` call is optional. + +In general, with Logrus using any of the `printf`-family functions should be +seen as a hint you should add a field, however, you can still use the +`printf`-family functions with Logrus. + +#### Default Fields + +Often it's helpful to have fields _always_ attached to log statements in an +application or parts of one. For example, you may want to always log the +`request_id` and `user_ip` in the context of a request. Instead of writing +`log.WithFields(log.Fields{"request_id": request_id, "user_ip": user_ip})` on +every line, you can create a `logrus.Entry` to pass around instead: + +```go +requestLogger := log.WithFields(log.Fields{"request_id": request_id, "user_ip": user_ip}) +requestLogger.Info("something happened on that request") # will log request_id and user_ip +requestLogger.Warn("something not great happened") +``` + +#### Hooks + +You can add hooks for logging levels. For example to send errors to an exception +tracking service on `Error`, `Fatal` and `Panic`, info to StatsD or log to +multiple places simultaneously, e.g. syslog. + +Logrus comes with [built-in hooks](hooks/). Add those, or your custom hook, in +`init`: + +```go +import ( + log "github.com/sirupsen/logrus" + "gopkg.in/gemnasium/logrus-airbrake-hook.v2" // the package is named "airbrake" + logrus_syslog "github.com/sirupsen/logrus/hooks/syslog" + "log/syslog" +) + +func init() { + + // Use the Airbrake hook to report errors that have Error severity or above to + // an exception tracker. You can create custom hooks, see the Hooks section. + log.AddHook(airbrake.NewHook(123, "xyz", "production")) + + hook, err := logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "") + if err != nil { + log.Error("Unable to connect to local syslog daemon") + } else { + log.AddHook(hook) + } +} +``` +Note: Syslog hook also support connecting to local syslog (Ex. "/dev/log" or "/var/run/syslog" or "/var/run/log"). For the detail, please check the [syslog hook README](hooks/syslog/README.md). + +A list of currently known of service hook can be found in this wiki [page](https://github.com/sirupsen/logrus/wiki/Hooks) + + +#### Level logging + +Logrus has seven logging levels: Trace, Debug, Info, Warning, Error, Fatal and Panic. + +```go +log.Trace("Something very low level.") +log.Debug("Useful debugging information.") +log.Info("Something noteworthy happened!") +log.Warn("You should probably take a look at this.") +log.Error("Something failed but I'm not quitting.") +// Calls os.Exit(1) after logging +log.Fatal("Bye.") +// Calls panic() after logging +log.Panic("I'm bailing.") +``` + +You can set the logging level on a `Logger`, then it will only log entries with +that severity or anything above it: + +```go +// Will log anything that is info or above (warn, error, fatal, panic). Default. +log.SetLevel(log.InfoLevel) +``` + +It may be useful to set `log.Level = logrus.DebugLevel` in a debug or verbose +environment if your application has that. + +#### Entries + +Besides the fields added with `WithField` or `WithFields` some fields are +automatically added to all logging events: + +1. `time`. The timestamp when the entry was created. +2. `msg`. The logging message passed to `{Info,Warn,Error,Fatal,Panic}` after + the `AddFields` call. E.g. `Failed to send event.` +3. `level`. The logging level. E.g. `info`. + +#### Environments + +Logrus has no notion of environment. + +If you wish for hooks and formatters to only be used in specific environments, +you should handle that yourself. For example, if your application has a global +variable `Environment`, which is a string representation of the environment you +could do: + +```go +import ( + log "github.com/sirupsen/logrus" +) + +init() { + // do something here to set environment depending on an environment variable + // or command-line flag + if Environment == "production" { + log.SetFormatter(&log.JSONFormatter{}) + } else { + // The TextFormatter is default, you don't actually have to do this. + log.SetFormatter(&log.TextFormatter{}) + } +} +``` + +This configuration is how `logrus` was intended to be used, but JSON in +production is mostly only useful if you do log aggregation with tools like +Splunk or Logstash. + +#### Formatters + +The built-in logging formatters are: + +* `logrus.TextFormatter`. Logs the event in colors if stdout is a tty, otherwise + without colors. + * *Note:* to force colored output when there is no TTY, set the `ForceColors` + field to `true`. To force no colored output even if there is a TTY set the + `DisableColors` field to `true`. For Windows, see + [github.com/mattn/go-colorable](https://github.com/mattn/go-colorable). + * When colors are enabled, levels are truncated to 4 characters by default. To disable + truncation set the `DisableLevelTruncation` field to `true`. + * All options are listed in the [generated docs](https://godoc.org/github.com/sirupsen/logrus#TextFormatter). +* `logrus.JSONFormatter`. Logs fields as JSON. + * All options are listed in the [generated docs](https://godoc.org/github.com/sirupsen/logrus#JSONFormatter). + +Third party logging formatters: + +* [`FluentdFormatter`](https://github.com/joonix/log). Formats entries that can be parsed by Kubernetes and Google Container Engine. +* [`GELF`](https://github.com/fabienm/go-logrus-formatters). Formats entries so they comply to Graylog's [GELF 1.1 specification](http://docs.graylog.org/en/2.4/pages/gelf.html). +* [`logstash`](https://github.com/bshuster-repo/logrus-logstash-hook). Logs fields as [Logstash](http://logstash.net) Events. +* [`prefixed`](https://github.com/x-cray/logrus-prefixed-formatter). Displays log entry source along with alternative layout. +* [`zalgo`](https://github.com/aybabtme/logzalgo). Invoking the P͉̫o̳̼̊w̖͈̰͎e̬͔̭͂r͚̼̹̲ ̫͓͉̳͈ō̠͕͖̚f̝͍̠ ͕̲̞͖͑Z̖̫̤̫ͪa͉̬͈̗l͖͎g̳̥o̰̥̅!̣͔̲̻͊̄ ̙̘̦̹̦. + +You can define your formatter by implementing the `Formatter` interface, +requiring a `Format` method. `Format` takes an `*Entry`. `entry.Data` is a +`Fields` type (`map[string]interface{}`) with all your fields as well as the +default ones (see Entries section above): + +```go +type MyJSONFormatter struct { +} + +log.SetFormatter(new(MyJSONFormatter)) + +func (f *MyJSONFormatter) Format(entry *Entry) ([]byte, error) { + // Note this doesn't include Time, Level and Message which are available on + // the Entry. Consult `godoc` on information about those fields or read the + // source of the official loggers. + serialized, err := json.Marshal(entry.Data) + if err != nil { + return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err) + } + return append(serialized, '\n'), nil +} +``` + +#### Logger as an `io.Writer` + +Logrus can be transformed into an `io.Writer`. That writer is the end of an `io.Pipe` and it is your responsibility to close it. + +```go +w := logger.Writer() +defer w.Close() + +srv := http.Server{ + // create a stdlib log.Logger that writes to + // logrus.Logger. + ErrorLog: log.New(w, "", 0), +} +``` + +Each line written to that writer will be printed the usual way, using formatters +and hooks. The level for those entries is `info`. + +This means that we can override the standard library logger easily: + +```go +logger := logrus.New() +logger.Formatter = &logrus.JSONFormatter{} + +// Use logrus for standard log output +// Note that `log` here references stdlib's log +// Not logrus imported under the name `log`. +log.SetOutput(logger.Writer()) +``` + +#### Rotation + +Log rotation is not provided with Logrus. Log rotation should be done by an +external program (like `logrotate(8)`) that can compress and delete old log +entries. It should not be a feature of the application-level logger. + +#### Tools + +| Tool | Description | +| ---- | ----------- | +|[Logrus Mate](https://github.com/gogap/logrus_mate)|Logrus mate is a tool for Logrus to manage loggers, you can initial logger's level, hook and formatter by config file, the logger will generated with different config at different environment.| +|[Logrus Viper Helper](https://github.com/heirko/go-contrib/tree/master/logrusHelper)|An Helper around Logrus to wrap with spf13/Viper to load configuration with fangs! And to simplify Logrus configuration use some behavior of [Logrus Mate](https://github.com/gogap/logrus_mate). [sample](https://github.com/heirko/iris-contrib/blob/master/middleware/logrus-logger/example) | + +#### Testing + +Logrus has a built in facility for asserting the presence of log messages. This is implemented through the `test` hook and provides: + +* decorators for existing logger (`test.NewLocal` and `test.NewGlobal`) which basically just add the `test` hook +* a test logger (`test.NewNullLogger`) that just records log messages (and does not output any): + +```go +import( + "github.com/sirupsen/logrus" + "github.com/sirupsen/logrus/hooks/test" + "github.com/stretchr/testify/assert" + "testing" +) + +func TestSomething(t*testing.T){ + logger, hook := test.NewNullLogger() + logger.Error("Helloerror") + + assert.Equal(t, 1, len(hook.Entries)) + assert.Equal(t, logrus.ErrorLevel, hook.LastEntry().Level) + assert.Equal(t, "Helloerror", hook.LastEntry().Message) + + hook.Reset() + assert.Nil(t, hook.LastEntry()) +} +``` + +#### Fatal handlers + +Logrus can register one or more functions that will be called when any `fatal` +level message is logged. The registered handlers will be executed before +logrus performs a `os.Exit(1)`. This behavior may be helpful if callers need +to gracefully shutdown. Unlike a `panic("Something went wrong...")` call which can be intercepted with a deferred `recover` a call to `os.Exit(1)` can not be intercepted. + +``` +... +handler := func() { + // gracefully shutdown something... +} +logrus.RegisterExitHandler(handler) +... +``` + +#### Thread safety + +By default, Logger is protected by a mutex for concurrent writes. The mutex is held when calling hooks and writing logs. +If you are sure such locking is not needed, you can call logger.SetNoLock() to disable the locking. + +Situation when locking is not needed includes: + +* You have no hooks registered, or hooks calling is already thread-safe. + +* Writing to logger.Out is already thread-safe, for example: + + 1) logger.Out is protected by locks. + + 2) logger.Out is a os.File handler opened with `O_APPEND` flag, and every write is smaller than 4k. (This allow multi-thread/multi-process writing) + + (Refer to http://www.notthewizard.com/2014/06/17/are-files-appends-really-atomic/) diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/alt_exit.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/alt_exit.go new file mode 100644 index 0000000000..8af90637a9 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/alt_exit.go @@ -0,0 +1,64 @@ +package logrus + +// The following code was sourced and modified from the +// https://github.com/tebeka/atexit package governed by the following license: +// +// Copyright (c) 2012 Miki Tebeka . +// +// 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. + +import ( + "fmt" + "os" +) + +var handlers = []func(){} + +func runHandler(handler func()) { + defer func() { + if err := recover(); err != nil { + fmt.Fprintln(os.Stderr, "Error: Logrus exit handler error:", err) + } + }() + + handler() +} + +func runHandlers() { + for _, handler := range handlers { + runHandler(handler) + } +} + +// Exit runs all the Logrus atexit handlers and then terminates the program using os.Exit(code) +func Exit(code int) { + runHandlers() + os.Exit(code) +} + +// RegisterExitHandler adds a Logrus Exit handler, call logrus.Exit to invoke +// all handlers. The handlers will also be invoked when any Fatal log entry is +// made. +// +// This method is useful when a caller wishes to use logrus to log a fatal +// message but also needs to gracefully shutdown. An example usecase could be +// closing database connections, or sending a alert that the application is +// closing. +func RegisterExitHandler(handler func()) { + handlers = append(handlers, handler) +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/doc.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/doc.go new file mode 100644 index 0000000000..da67aba06d --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/doc.go @@ -0,0 +1,26 @@ +/* +Package logrus is a structured logger for Go, completely API compatible with the standard library logger. + + +The simplest way to use Logrus is simply the package-level exported logger: + + package main + + import ( + log "github.com/sirupsen/logrus" + ) + + func main() { + log.WithFields(log.Fields{ + "animal": "walrus", + "number": 1, + "size": 10, + }).Info("A walrus appears") + } + +Output: + time="2015-09-07T08:48:33Z" level=info msg="A walrus appears" animal=walrus number=1 size=10 + +For a full guide visit https://github.com/sirupsen/logrus +*/ +package logrus diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/entry.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/entry.go new file mode 100644 index 0000000000..df6d188def --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/entry.go @@ -0,0 +1,393 @@ +package logrus + +import ( + "bytes" + "fmt" + "os" + "reflect" + "runtime" + "strings" + "sync" + "time" +) + +var ( + bufferPool *sync.Pool + + // qualified package name, cached at first use + logrusPackage string + + // Positions in the call stack when tracing to report the calling method + minimumCallerDepth int + + // Used for caller information initialisation + callerInitOnce sync.Once +) + +const ( + maximumCallerDepth int = 25 + knownLogrusFrames int = 4 +) + +func init() { + bufferPool = &sync.Pool{ + New: func() interface{} { + return new(bytes.Buffer) + }, + } + + // start at the bottom of the stack before the package-name cache is primed + minimumCallerDepth = 1 +} + +// Defines the key when adding errors using WithError. +var ErrorKey = "error" + +// An entry is the final or intermediate Logrus logging entry. It contains all +// the fields passed with WithField{,s}. It's finally logged when Trace, Debug, +// Info, Warn, Error, Fatal or Panic is called on it. These objects can be +// reused and passed around as much as you wish to avoid field duplication. +type Entry struct { + Logger *Logger + + // Contains all the fields set by the user. + Data Fields + + // Time at which the log entry was created + Time time.Time + + // Level the log entry was logged at: Trace, Debug, Info, Warn, Error, Fatal or Panic + // This field will be set on entry firing and the value will be equal to the one in Logger struct field. + Level Level + + // Calling method, with package name + Caller *runtime.Frame + + // Message passed to Trace, Debug, Info, Warn, Error, Fatal or Panic + Message string + + // When formatter is called in entry.log(), a Buffer may be set to entry + Buffer *bytes.Buffer + + // err may contain a field formatting error + err string +} + +func NewEntry(logger *Logger) *Entry { + return &Entry{ + Logger: logger, + // Default is three fields, plus one optional. Give a little extra room. + Data: make(Fields, 6), + } +} + +// Returns the string representation from the reader and ultimately the +// formatter. +func (entry *Entry) String() (string, error) { + serialized, err := entry.Logger.Formatter.Format(entry) + if err != nil { + return "", err + } + str := string(serialized) + return str, nil +} + +// Add an error as single field (using the key defined in ErrorKey) to the Entry. +func (entry *Entry) WithError(err error) *Entry { + return entry.WithField(ErrorKey, err) +} + +// Add a single field to the Entry. +func (entry *Entry) WithField(key string, value interface{}) *Entry { + return entry.WithFields(Fields{key: value}) +} + +// Add a map of fields to the Entry. +func (entry *Entry) WithFields(fields Fields) *Entry { + data := make(Fields, len(entry.Data)+len(fields)) + for k, v := range entry.Data { + data[k] = v + } + fieldErr := entry.err + for k, v := range fields { + isErrField := false + if t := reflect.TypeOf(v); t != nil { + switch t.Kind() { + case reflect.Func: + isErrField = true + case reflect.Ptr: + isErrField = t.Elem().Kind() == reflect.Func + } + } + if isErrField { + tmp := fmt.Sprintf("can not add field %q", k) + if fieldErr != "" { + fieldErr = entry.err + ", " + tmp + } else { + fieldErr = tmp + } + } else { + data[k] = v + } + } + return &Entry{Logger: entry.Logger, Data: data, Time: entry.Time, err: fieldErr} +} + +// Overrides the time of the Entry. +func (entry *Entry) WithTime(t time.Time) *Entry { + return &Entry{Logger: entry.Logger, Data: entry.Data, Time: t, err: entry.err} +} + +// getPackageName reduces a fully qualified function name to the package name +// There really ought to be to be a better way... +func getPackageName(f string) string { + for { + lastPeriod := strings.LastIndex(f, ".") + lastSlash := strings.LastIndex(f, "/") + if lastPeriod > lastSlash { + f = f[:lastPeriod] + } else { + break + } + } + + return f +} + +// getCaller retrieves the name of the first non-logrus calling function +func getCaller() *runtime.Frame { + // Restrict the lookback frames to avoid runaway lookups + pcs := make([]uintptr, maximumCallerDepth) + depth := runtime.Callers(minimumCallerDepth, pcs) + frames := runtime.CallersFrames(pcs[:depth]) + + // cache this package's fully-qualified name + callerInitOnce.Do(func() { + logrusPackage = getPackageName(runtime.FuncForPC(pcs[0]).Name()) + + // now that we have the cache, we can skip a minimum count of known-logrus functions + // XXX this is dubious, the number of frames may vary store an entry in a logger interface + minimumCallerDepth = knownLogrusFrames + }) + + for f, again := frames.Next(); again; f, again = frames.Next() { + pkg := getPackageName(f.Function) + + // If the caller isn't part of this package, we're done + if pkg != logrusPackage { + return &f + } + } + + // if we got here, we failed to find the caller's context + return nil +} + +func (entry Entry) HasCaller() (has bool) { + return entry.Logger != nil && + entry.Logger.ReportCaller && + entry.Caller != nil +} + +// This function is not declared with a pointer value because otherwise +// race conditions will occur when using multiple goroutines +func (entry Entry) log(level Level, msg string) { + var buffer *bytes.Buffer + + // Default to now, but allow users to override if they want. + // + // We don't have to worry about polluting future calls to Entry#log() + // with this assignment because this function is declared with a + // non-pointer receiver. + if entry.Time.IsZero() { + entry.Time = time.Now() + } + + entry.Level = level + entry.Message = msg + if entry.Logger.ReportCaller { + entry.Caller = getCaller() + } + + entry.fireHooks() + + buffer = bufferPool.Get().(*bytes.Buffer) + buffer.Reset() + defer bufferPool.Put(buffer) + entry.Buffer = buffer + + entry.write() + + entry.Buffer = nil + + // To avoid Entry#log() returning a value that only would make sense for + // panic() to use in Entry#Panic(), we avoid the allocation by checking + // directly here. + if level <= PanicLevel { + panic(&entry) + } +} + +func (entry *Entry) fireHooks() { + entry.Logger.mu.Lock() + defer entry.Logger.mu.Unlock() + err := entry.Logger.Hooks.Fire(entry.Level, entry) + if err != nil { + fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err) + } +} + +func (entry *Entry) write() { + entry.Logger.mu.Lock() + defer entry.Logger.mu.Unlock() + serialized, err := entry.Logger.Formatter.Format(entry) + if err != nil { + fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err) + } else { + _, err = entry.Logger.Out.Write(serialized) + if err != nil { + fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err) + } + } +} + +func (entry *Entry) Log(level Level, args ...interface{}) { + if entry.Logger.IsLevelEnabled(level) { + entry.log(level, fmt.Sprint(args...)) + } +} + +func (entry *Entry) Trace(args ...interface{}) { + entry.Log(TraceLevel, args...) +} + +func (entry *Entry) Debug(args ...interface{}) { + entry.Log(DebugLevel, args...) +} + +func (entry *Entry) Print(args ...interface{}) { + entry.Info(args...) +} + +func (entry *Entry) Info(args ...interface{}) { + entry.Log(InfoLevel, args...) +} + +func (entry *Entry) Warn(args ...interface{}) { + entry.Log(WarnLevel, args...) +} + +func (entry *Entry) Warning(args ...interface{}) { + entry.Warn(args...) +} + +func (entry *Entry) Error(args ...interface{}) { + entry.Log(ErrorLevel, args...) +} + +func (entry *Entry) Fatal(args ...interface{}) { + entry.Log(FatalLevel, args...) + entry.Logger.Exit(1) +} + +func (entry *Entry) Panic(args ...interface{}) { + entry.Log(PanicLevel, args...) + panic(fmt.Sprint(args...)) +} + +// Entry Printf family functions + +func (entry *Entry) Logf(level Level, format string, args ...interface{}) { + entry.Log(level, fmt.Sprintf(format, args...)) +} + +func (entry *Entry) Tracef(format string, args ...interface{}) { + entry.Logf(TraceLevel, format, args...) +} + +func (entry *Entry) Debugf(format string, args ...interface{}) { + entry.Logf(DebugLevel, format, args...) +} + +func (entry *Entry) Infof(format string, args ...interface{}) { + entry.Logf(InfoLevel, format, args...) +} + +func (entry *Entry) Printf(format string, args ...interface{}) { + entry.Infof(format, args...) +} + +func (entry *Entry) Warnf(format string, args ...interface{}) { + entry.Logf(WarnLevel, format, args...) +} + +func (entry *Entry) Warningf(format string, args ...interface{}) { + entry.Warnf(format, args...) +} + +func (entry *Entry) Errorf(format string, args ...interface{}) { + entry.Logf(ErrorLevel, format, args...) +} + +func (entry *Entry) Fatalf(format string, args ...interface{}) { + entry.Logf(FatalLevel, format, args...) + entry.Logger.Exit(1) +} + +func (entry *Entry) Panicf(format string, args ...interface{}) { + entry.Logf(PanicLevel, format, args...) +} + +// Entry Println family functions + +func (entry *Entry) Logln(level Level, args ...interface{}) { + if entry.Logger.IsLevelEnabled(level) { + entry.Log(level, entry.sprintlnn(args...)) + } +} + +func (entry *Entry) Traceln(args ...interface{}) { + entry.Logln(TraceLevel, args...) +} + +func (entry *Entry) Debugln(args ...interface{}) { + entry.Logln(DebugLevel, args...) +} + +func (entry *Entry) Infoln(args ...interface{}) { + entry.Logln(InfoLevel, args...) +} + +func (entry *Entry) Println(args ...interface{}) { + entry.Infoln(args...) +} + +func (entry *Entry) Warnln(args ...interface{}) { + entry.Logln(WarnLevel, args...) +} + +func (entry *Entry) Warningln(args ...interface{}) { + entry.Warnln(args...) +} + +func (entry *Entry) Errorln(args ...interface{}) { + entry.Logln(ErrorLevel, args...) +} + +func (entry *Entry) Fatalln(args ...interface{}) { + entry.Logln(FatalLevel, args...) + entry.Logger.Exit(1) +} + +func (entry *Entry) Panicln(args ...interface{}) { + entry.Logln(PanicLevel, args...) +} + +// Sprintlnn => Sprint no newline. This is to get the behavior of how +// fmt.Sprintln where spaces are always added between operands, regardless of +// their type. Instead of vendoring the Sprintln implementation to spare a +// string allocation, we do the simplest thing. +func (entry *Entry) sprintlnn(args ...interface{}) string { + msg := fmt.Sprintln(args...) + return msg[:len(msg)-1] +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/exported.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/exported.go new file mode 100644 index 0000000000..7342613c37 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/exported.go @@ -0,0 +1,219 @@ +package logrus + +import ( + "io" + "time" +) + +var ( + // std is the name of the standard logger in stdlib `log` + std = New() +) + +func StandardLogger() *Logger { + return std +} + +// SetOutput sets the standard logger output. +func SetOutput(out io.Writer) { + std.SetOutput(out) +} + +// SetFormatter sets the standard logger formatter. +func SetFormatter(formatter Formatter) { + std.SetFormatter(formatter) +} + +// SetReportCaller sets whether the standard logger will include the calling +// method as a field. +func SetReportCaller(include bool) { + std.SetReportCaller(include) +} + +// SetLevel sets the standard logger level. +func SetLevel(level Level) { + std.SetLevel(level) +} + +// GetLevel returns the standard logger level. +func GetLevel() Level { + return std.GetLevel() +} + +// IsLevelEnabled checks if the log level of the standard logger is greater than the level param +func IsLevelEnabled(level Level) bool { + return std.IsLevelEnabled(level) +} + +// AddHook adds a hook to the standard logger hooks. +func AddHook(hook Hook) { + std.AddHook(hook) +} + +// WithError creates an entry from the standard logger and adds an error to it, using the value defined in ErrorKey as key. +func WithError(err error) *Entry { + return std.WithField(ErrorKey, err) +} + +// WithField creates an entry from the standard logger and adds a field to +// it. If you want multiple fields, use `WithFields`. +// +// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal +// or Panic on the Entry it returns. +func WithField(key string, value interface{}) *Entry { + return std.WithField(key, value) +} + +// WithFields creates an entry from the standard logger and adds multiple +// fields to it. This is simply a helper for `WithField`, invoking it +// once for each field. +// +// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal +// or Panic on the Entry it returns. +func WithFields(fields Fields) *Entry { + return std.WithFields(fields) +} + +// WithTime creats an entry from the standard logger and overrides the time of +// logs generated with it. +// +// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal +// or Panic on the Entry it returns. +func WithTime(t time.Time) *Entry { + return std.WithTime(t) +} + +// Trace logs a message at level Trace on the standard logger. +func Trace(args ...interface{}) { + std.Trace(args...) +} + +// Debug logs a message at level Debug on the standard logger. +func Debug(args ...interface{}) { + std.Debug(args...) +} + +// Print logs a message at level Info on the standard logger. +func Print(args ...interface{}) { + std.Print(args...) +} + +// Info logs a message at level Info on the standard logger. +func Info(args ...interface{}) { + std.Info(args...) +} + +// Warn logs a message at level Warn on the standard logger. +func Warn(args ...interface{}) { + std.Warn(args...) +} + +// Warning logs a message at level Warn on the standard logger. +func Warning(args ...interface{}) { + std.Warning(args...) +} + +// Error logs a message at level Error on the standard logger. +func Error(args ...interface{}) { + std.Error(args...) +} + +// Panic logs a message at level Panic on the standard logger. +func Panic(args ...interface{}) { + std.Panic(args...) +} + +// Fatal logs a message at level Fatal on the standard logger then the process will exit with status set to 1. +func Fatal(args ...interface{}) { + std.Fatal(args...) +} + +// Tracef logs a message at level Trace on the standard logger. +func Tracef(format string, args ...interface{}) { + std.Tracef(format, args...) +} + +// Debugf logs a message at level Debug on the standard logger. +func Debugf(format string, args ...interface{}) { + std.Debugf(format, args...) +} + +// Printf logs a message at level Info on the standard logger. +func Printf(format string, args ...interface{}) { + std.Printf(format, args...) +} + +// Infof logs a message at level Info on the standard logger. +func Infof(format string, args ...interface{}) { + std.Infof(format, args...) +} + +// Warnf logs a message at level Warn on the standard logger. +func Warnf(format string, args ...interface{}) { + std.Warnf(format, args...) +} + +// Warningf logs a message at level Warn on the standard logger. +func Warningf(format string, args ...interface{}) { + std.Warningf(format, args...) +} + +// Errorf logs a message at level Error on the standard logger. +func Errorf(format string, args ...interface{}) { + std.Errorf(format, args...) +} + +// Panicf logs a message at level Panic on the standard logger. +func Panicf(format string, args ...interface{}) { + std.Panicf(format, args...) +} + +// Fatalf logs a message at level Fatal on the standard logger then the process will exit with status set to 1. +func Fatalf(format string, args ...interface{}) { + std.Fatalf(format, args...) +} + +// Traceln logs a message at level Trace on the standard logger. +func Traceln(args ...interface{}) { + std.Traceln(args...) +} + +// Debugln logs a message at level Debug on the standard logger. +func Debugln(args ...interface{}) { + std.Debugln(args...) +} + +// Println logs a message at level Info on the standard logger. +func Println(args ...interface{}) { + std.Println(args...) +} + +// Infoln logs a message at level Info on the standard logger. +func Infoln(args ...interface{}) { + std.Infoln(args...) +} + +// Warnln logs a message at level Warn on the standard logger. +func Warnln(args ...interface{}) { + std.Warnln(args...) +} + +// Warningln logs a message at level Warn on the standard logger. +func Warningln(args ...interface{}) { + std.Warningln(args...) +} + +// Errorln logs a message at level Error on the standard logger. +func Errorln(args ...interface{}) { + std.Errorln(args...) +} + +// Panicln logs a message at level Panic on the standard logger. +func Panicln(args ...interface{}) { + std.Panicln(args...) +} + +// Fatalln logs a message at level Fatal on the standard logger then the process will exit with status set to 1. +func Fatalln(args ...interface{}) { + std.Fatalln(args...) +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/formatter.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/formatter.go new file mode 100644 index 0000000000..408883773e --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/formatter.go @@ -0,0 +1,78 @@ +package logrus + +import "time" + +// Default key names for the default fields +const ( + defaultTimestampFormat = time.RFC3339 + FieldKeyMsg = "msg" + FieldKeyLevel = "level" + FieldKeyTime = "time" + FieldKeyLogrusError = "logrus_error" + FieldKeyFunc = "func" + FieldKeyFile = "file" +) + +// The Formatter interface is used to implement a custom Formatter. It takes an +// `Entry`. It exposes all the fields, including the default ones: +// +// * `entry.Data["msg"]`. The message passed from Info, Warn, Error .. +// * `entry.Data["time"]`. The timestamp. +// * `entry.Data["level"]. The level the entry was logged at. +// +// Any additional fields added with `WithField` or `WithFields` are also in +// `entry.Data`. Format is expected to return an array of bytes which are then +// logged to `logger.Out`. +type Formatter interface { + Format(*Entry) ([]byte, error) +} + +// This is to not silently overwrite `time`, `msg`, `func` and `level` fields when +// dumping it. If this code wasn't there doing: +// +// logrus.WithField("level", 1).Info("hello") +// +// Would just silently drop the user provided level. Instead with this code +// it'll logged as: +// +// {"level": "info", "fields.level": 1, "msg": "hello", "time": "..."} +// +// It's not exported because it's still using Data in an opinionated way. It's to +// avoid code duplication between the two default formatters. +func prefixFieldClashes(data Fields, fieldMap FieldMap, reportCaller bool) { + timeKey := fieldMap.resolve(FieldKeyTime) + if t, ok := data[timeKey]; ok { + data["fields."+timeKey] = t + delete(data, timeKey) + } + + msgKey := fieldMap.resolve(FieldKeyMsg) + if m, ok := data[msgKey]; ok { + data["fields."+msgKey] = m + delete(data, msgKey) + } + + levelKey := fieldMap.resolve(FieldKeyLevel) + if l, ok := data[levelKey]; ok { + data["fields."+levelKey] = l + delete(data, levelKey) + } + + logrusErrKey := fieldMap.resolve(FieldKeyLogrusError) + if l, ok := data[logrusErrKey]; ok { + data["fields."+logrusErrKey] = l + delete(data, logrusErrKey) + } + + // If reportCaller is not set, 'func' will not conflict. + if reportCaller { + funcKey := fieldMap.resolve(FieldKeyFunc) + if l, ok := data[funcKey]; ok { + data["fields."+funcKey] = l + } + fileKey := fieldMap.resolve(FieldKeyFile) + if l, ok := data[fileKey]; ok { + data["fields."+fileKey] = l + } + } +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/hooks.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/hooks.go new file mode 100644 index 0000000000..3f151cdc39 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/hooks.go @@ -0,0 +1,34 @@ +package logrus + +// A hook to be fired when logging on the logging levels returned from +// `Levels()` on your implementation of the interface. Note that this is not +// fired in a goroutine or a channel with workers, you should handle such +// functionality yourself if your call is non-blocking and you don't wish for +// the logging calls for levels returned from `Levels()` to block. +type Hook interface { + Levels() []Level + Fire(*Entry) error +} + +// Internal type for storing the hooks on a logger instance. +type LevelHooks map[Level][]Hook + +// Add a hook to an instance of logger. This is called with +// `log.Hooks.Add(new(MyHook))` where `MyHook` implements the `Hook` interface. +func (hooks LevelHooks) Add(hook Hook) { + for _, level := range hook.Levels() { + hooks[level] = append(hooks[level], hook) + } +} + +// Fire all the hooks for the passed level. Used by `entry.log` to fire +// appropriate hooks for a log entry. +func (hooks LevelHooks) Fire(level Level, entry *Entry) error { + for _, hook := range hooks[level] { + if err := hook.Fire(entry); err != nil { + return err + } + } + + return nil +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/json_formatter.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/json_formatter.go new file mode 100644 index 0000000000..2605753599 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/json_formatter.go @@ -0,0 +1,105 @@ +package logrus + +import ( + "bytes" + "encoding/json" + "fmt" +) + +type fieldKey string + +// FieldMap allows customization of the key names for default fields. +type FieldMap map[fieldKey]string + +func (f FieldMap) resolve(key fieldKey) string { + if k, ok := f[key]; ok { + return k + } + + return string(key) +} + +// JSONFormatter formats logs into parsable json +type JSONFormatter struct { + // TimestampFormat sets the format used for marshaling timestamps. + TimestampFormat string + + // DisableTimestamp allows disabling automatic timestamps in output + DisableTimestamp bool + + // DataKey allows users to put all the log entry parameters into a nested dictionary at a given key. + DataKey string + + // FieldMap allows users to customize the names of keys for default fields. + // As an example: + // formatter := &JSONFormatter{ + // FieldMap: FieldMap{ + // FieldKeyTime: "@timestamp", + // FieldKeyLevel: "@level", + // FieldKeyMsg: "@message", + // FieldKeyFunc: "@caller", + // }, + // } + FieldMap FieldMap + + // PrettyPrint will indent all json logs + PrettyPrint bool +} + +// Format renders a single log entry +func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) { + data := make(Fields, len(entry.Data)+4) + for k, v := range entry.Data { + switch v := v.(type) { + case error: + // Otherwise errors are ignored by `encoding/json` + // https://github.com/sirupsen/logrus/issues/137 + data[k] = v.Error() + default: + data[k] = v + } + } + + if f.DataKey != "" { + newData := make(Fields, 4) + newData[f.DataKey] = data + data = newData + } + + prefixFieldClashes(data, f.FieldMap, entry.HasCaller()) + + timestampFormat := f.TimestampFormat + if timestampFormat == "" { + timestampFormat = defaultTimestampFormat + } + + if entry.err != "" { + data[f.FieldMap.resolve(FieldKeyLogrusError)] = entry.err + } + if !f.DisableTimestamp { + data[f.FieldMap.resolve(FieldKeyTime)] = entry.Time.Format(timestampFormat) + } + data[f.FieldMap.resolve(FieldKeyMsg)] = entry.Message + data[f.FieldMap.resolve(FieldKeyLevel)] = entry.Level.String() + if entry.HasCaller() { + data[f.FieldMap.resolve(FieldKeyFunc)] = entry.Caller.Function + data[f.FieldMap.resolve(FieldKeyFile)] = fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line) + } + + var b *bytes.Buffer + if entry.Buffer != nil { + b = entry.Buffer + } else { + b = &bytes.Buffer{} + } + + encoder := json.NewEncoder(b) + if f.PrettyPrint { + encoder.SetIndent("", " ") + } + if err := encoder.Encode(data); err != nil { + return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err) + } + + return b.Bytes(), nil +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/logger.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/logger.go new file mode 100644 index 0000000000..9bf64e22ae --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/logger.go @@ -0,0 +1,343 @@ +package logrus + +import ( + "io" + "os" + "sync" + "sync/atomic" + "time" +) + +type Logger struct { + // The logs are `io.Copy`'d to this in a mutex. It's common to set this to a + // file, or leave it default which is `os.Stderr`. You can also set this to + // something more adventurous, such as logging to Kafka. + Out io.Writer + // Hooks for the logger instance. These allow firing events based on logging + // levels and log entries. For example, to send errors to an error tracking + // service, log to StatsD or dump the core on fatal errors. + Hooks LevelHooks + // All log entries pass through the formatter before logged to Out. The + // included formatters are `TextFormatter` and `JSONFormatter` for which + // TextFormatter is the default. In development (when a TTY is attached) it + // logs with colors, but to a file it wouldn't. You can easily implement your + // own that implements the `Formatter` interface, see the `README` or included + // formatters for examples. + Formatter Formatter + + // Flag for whether to log caller info (off by default) + ReportCaller bool + + // The logging level the logger should log at. This is typically (and defaults + // to) `logrus.Info`, which allows Info(), Warn(), Error() and Fatal() to be + // logged. + Level Level + // Used to sync writing to the log. Locking is enabled by Default + mu MutexWrap + // Reusable empty entry + entryPool sync.Pool + // Function to exit the application, defaults to `os.Exit()` + ExitFunc exitFunc +} + +type exitFunc func(int) + +type MutexWrap struct { + lock sync.Mutex + disabled bool +} + +func (mw *MutexWrap) Lock() { + if !mw.disabled { + mw.lock.Lock() + } +} + +func (mw *MutexWrap) Unlock() { + if !mw.disabled { + mw.lock.Unlock() + } +} + +func (mw *MutexWrap) Disable() { + mw.disabled = true +} + +// Creates a new logger. Configuration should be set by changing `Formatter`, +// `Out` and `Hooks` directly on the default logger instance. You can also just +// instantiate your own: +// +// var log = &Logger{ +// Out: os.Stderr, +// Formatter: new(JSONFormatter), +// Hooks: make(LevelHooks), +// Level: logrus.DebugLevel, +// } +// +// It's recommended to make this a global instance called `log`. +func New() *Logger { + return &Logger{ + Out: os.Stderr, + Formatter: new(TextFormatter), + Hooks: make(LevelHooks), + Level: InfoLevel, + ExitFunc: os.Exit, + ReportCaller: false, + } +} + +func (logger *Logger) newEntry() *Entry { + entry, ok := logger.entryPool.Get().(*Entry) + if ok { + return entry + } + return NewEntry(logger) +} + +func (logger *Logger) releaseEntry(entry *Entry) { + entry.Data = map[string]interface{}{} + logger.entryPool.Put(entry) +} + +// Adds a field to the log entry, note that it doesn't log until you call +// Debug, Print, Info, Warn, Error, Fatal or Panic. It only creates a log entry. +// If you want multiple fields, use `WithFields`. +func (logger *Logger) WithField(key string, value interface{}) *Entry { + entry := logger.newEntry() + defer logger.releaseEntry(entry) + return entry.WithField(key, value) +} + +// Adds a struct of fields to the log entry. All it does is call `WithField` for +// each `Field`. +func (logger *Logger) WithFields(fields Fields) *Entry { + entry := logger.newEntry() + defer logger.releaseEntry(entry) + return entry.WithFields(fields) +} + +// Add an error as single field to the log entry. All it does is call +// `WithError` for the given `error`. +func (logger *Logger) WithError(err error) *Entry { + entry := logger.newEntry() + defer logger.releaseEntry(entry) + return entry.WithError(err) +} + +// Overrides the time of the log entry. +func (logger *Logger) WithTime(t time.Time) *Entry { + entry := logger.newEntry() + defer logger.releaseEntry(entry) + return entry.WithTime(t) +} + +func (logger *Logger) Logf(level Level, format string, args ...interface{}) { + if logger.IsLevelEnabled(level) { + entry := logger.newEntry() + entry.Logf(level, format, args...) + logger.releaseEntry(entry) + } +} + +func (logger *Logger) Tracef(format string, args ...interface{}) { + logger.Logf(TraceLevel, format, args...) +} + +func (logger *Logger) Debugf(format string, args ...interface{}) { + logger.Logf(DebugLevel, format, args...) +} + +func (logger *Logger) Infof(format string, args ...interface{}) { + logger.Logf(InfoLevel, format, args...) +} + +func (logger *Logger) Printf(format string, args ...interface{}) { + entry := logger.newEntry() + entry.Printf(format, args...) + logger.releaseEntry(entry) +} + +func (logger *Logger) Warnf(format string, args ...interface{}) { + logger.Logf(WarnLevel, format, args...) +} + +func (logger *Logger) Warningf(format string, args ...interface{}) { + logger.Warnf(format, args...) +} + +func (logger *Logger) Errorf(format string, args ...interface{}) { + logger.Logf(ErrorLevel, format, args...) +} + +func (logger *Logger) Fatalf(format string, args ...interface{}) { + logger.Logf(FatalLevel, format, args...) + logger.Exit(1) +} + +func (logger *Logger) Panicf(format string, args ...interface{}) { + logger.Logf(PanicLevel, format, args...) +} + +func (logger *Logger) Log(level Level, args ...interface{}) { + if logger.IsLevelEnabled(level) { + entry := logger.newEntry() + entry.Log(level, args...) + logger.releaseEntry(entry) + } +} + +func (logger *Logger) Trace(args ...interface{}) { + logger.Log(TraceLevel, args...) +} + +func (logger *Logger) Debug(args ...interface{}) { + logger.Log(DebugLevel, args...) +} + +func (logger *Logger) Info(args ...interface{}) { + logger.Log(InfoLevel, args...) +} + +func (logger *Logger) Print(args ...interface{}) { + entry := logger.newEntry() + entry.Info(args...) + logger.releaseEntry(entry) +} + +func (logger *Logger) Warn(args ...interface{}) { + logger.Log(WarnLevel, args...) +} + +func (logger *Logger) Warning(args ...interface{}) { + logger.Warn(args...) +} + +func (logger *Logger) Error(args ...interface{}) { + logger.Log(ErrorLevel, args...) +} + +func (logger *Logger) Fatal(args ...interface{}) { + logger.Log(FatalLevel, args...) + logger.Exit(1) +} + +func (logger *Logger) Panic(args ...interface{}) { + logger.Log(PanicLevel, args...) +} + +func (logger *Logger) Logln(level Level, args ...interface{}) { + if logger.IsLevelEnabled(level) { + entry := logger.newEntry() + entry.Logln(level, args...) + logger.releaseEntry(entry) + } +} + +func (logger *Logger) Traceln(args ...interface{}) { + logger.Logln(TraceLevel, args...) +} + +func (logger *Logger) Debugln(args ...interface{}) { + logger.Logln(DebugLevel, args...) +} + +func (logger *Logger) Infoln(args ...interface{}) { + logger.Logln(InfoLevel, args...) +} + +func (logger *Logger) Println(args ...interface{}) { + entry := logger.newEntry() + entry.Println(args...) + logger.releaseEntry(entry) +} + +func (logger *Logger) Warnln(args ...interface{}) { + logger.Logln(WarnLevel, args...) +} + +func (logger *Logger) Warningln(args ...interface{}) { + logger.Warn(args...) +} + +func (logger *Logger) Errorln(args ...interface{}) { + logger.Logln(ErrorLevel, args...) +} + +func (logger *Logger) Fatalln(args ...interface{}) { + logger.Logln(FatalLevel, args...) + logger.Exit(1) +} + +func (logger *Logger) Panicln(args ...interface{}) { + logger.Logln(PanicLevel, args...) +} + +func (logger *Logger) Exit(code int) { + runHandlers() + if logger.ExitFunc == nil { + logger.ExitFunc = os.Exit + } + logger.ExitFunc(code) +} + +//When file is opened with appending mode, it's safe to +//write concurrently to a file (within 4k message on Linux). +//In these cases user can choose to disable the lock. +func (logger *Logger) SetNoLock() { + logger.mu.Disable() +} + +func (logger *Logger) level() Level { + return Level(atomic.LoadUint32((*uint32)(&logger.Level))) +} + +// SetLevel sets the logger level. +func (logger *Logger) SetLevel(level Level) { + atomic.StoreUint32((*uint32)(&logger.Level), uint32(level)) +} + +// GetLevel returns the logger level. +func (logger *Logger) GetLevel() Level { + return logger.level() +} + +// AddHook adds a hook to the logger hooks. +func (logger *Logger) AddHook(hook Hook) { + logger.mu.Lock() + defer logger.mu.Unlock() + logger.Hooks.Add(hook) +} + +// IsLevelEnabled checks if the log level of the logger is greater than the level param +func (logger *Logger) IsLevelEnabled(level Level) bool { + return logger.level() >= level +} + +// SetFormatter sets the logger formatter. +func (logger *Logger) SetFormatter(formatter Formatter) { + logger.mu.Lock() + defer logger.mu.Unlock() + logger.Formatter = formatter +} + +// SetOutput sets the logger output. +func (logger *Logger) SetOutput(output io.Writer) { + logger.mu.Lock() + defer logger.mu.Unlock() + logger.Out = output +} + +func (logger *Logger) SetReportCaller(reportCaller bool) { + logger.mu.Lock() + defer logger.mu.Unlock() + logger.ReportCaller = reportCaller +} + +// ReplaceHooks replaces the logger hooks and returns the old ones +func (logger *Logger) ReplaceHooks(hooks LevelHooks) LevelHooks { + logger.mu.Lock() + oldHooks := logger.Hooks + logger.Hooks = hooks + logger.mu.Unlock() + return oldHooks +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/logrus.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/logrus.go new file mode 100644 index 0000000000..c1ca889902 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/logrus.go @@ -0,0 +1,186 @@ +package logrus + +import ( + "fmt" + "log" + "strings" +) + +// Fields type, used to pass to `WithFields`. +type Fields map[string]interface{} + +// Level type +type Level uint32 + +// Convert the Level to a string. E.g. PanicLevel becomes "panic". +func (level Level) String() string { + if b, err := level.MarshalText(); err == nil { + return string(b) + } else { + return "unknown" + } +} + +// ParseLevel takes a string level and returns the Logrus log level constant. +func ParseLevel(lvl string) (Level, error) { + switch strings.ToLower(lvl) { + case "panic": + return PanicLevel, nil + case "fatal": + return FatalLevel, nil + case "error": + return ErrorLevel, nil + case "warn", "warning": + return WarnLevel, nil + case "info": + return InfoLevel, nil + case "debug": + return DebugLevel, nil + case "trace": + return TraceLevel, nil + } + + var l Level + return l, fmt.Errorf("not a valid logrus Level: %q", lvl) +} + +// UnmarshalText implements encoding.TextUnmarshaler. +func (level *Level) UnmarshalText(text []byte) error { + l, err := ParseLevel(string(text)) + if err != nil { + return err + } + + *level = Level(l) + + return nil +} + +func (level Level) MarshalText() ([]byte, error) { + switch level { + case TraceLevel: + return []byte("trace"), nil + case DebugLevel: + return []byte("debug"), nil + case InfoLevel: + return []byte("info"), nil + case WarnLevel: + return []byte("warning"), nil + case ErrorLevel: + return []byte("error"), nil + case FatalLevel: + return []byte("fatal"), nil + case PanicLevel: + return []byte("panic"), nil + } + + return nil, fmt.Errorf("not a valid lorus level %q", level) +} + +// A constant exposing all logging levels +var AllLevels = []Level{ + PanicLevel, + FatalLevel, + ErrorLevel, + WarnLevel, + InfoLevel, + DebugLevel, + TraceLevel, +} + +// These are the different logging levels. You can set the logging level to log +// on your instance of logger, obtained with `logrus.New()`. +const ( + // PanicLevel level, highest level of severity. Logs and then calls panic with the + // message passed to Debug, Info, ... + PanicLevel Level = iota + // FatalLevel level. Logs and then calls `logger.Exit(1)`. It will exit even if the + // logging level is set to Panic. + FatalLevel + // ErrorLevel level. Logs. Used for errors that should definitely be noted. + // Commonly used for hooks to send errors to an error tracking service. + ErrorLevel + // WarnLevel level. Non-critical entries that deserve eyes. + WarnLevel + // InfoLevel level. General operational entries about what's going on inside the + // application. + InfoLevel + // DebugLevel level. Usually only enabled when debugging. Very verbose logging. + DebugLevel + // TraceLevel level. Designates finer-grained informational events than the Debug. + TraceLevel +) + +// Won't compile if StdLogger can't be realized by a log.Logger +var ( + _ StdLogger = &log.Logger{} + _ StdLogger = &Entry{} + _ StdLogger = &Logger{} +) + +// StdLogger is what your logrus-enabled library should take, that way +// it'll accept a stdlib logger and a logrus logger. There's no standard +// interface, this is the closest we get, unfortunately. +type StdLogger interface { + Print(...interface{}) + Printf(string, ...interface{}) + Println(...interface{}) + + Fatal(...interface{}) + Fatalf(string, ...interface{}) + Fatalln(...interface{}) + + Panic(...interface{}) + Panicf(string, ...interface{}) + Panicln(...interface{}) +} + +// The FieldLogger interface generalizes the Entry and Logger types +type FieldLogger interface { + WithField(key string, value interface{}) *Entry + WithFields(fields Fields) *Entry + WithError(err error) *Entry + + Debugf(format string, args ...interface{}) + Infof(format string, args ...interface{}) + Printf(format string, args ...interface{}) + Warnf(format string, args ...interface{}) + Warningf(format string, args ...interface{}) + Errorf(format string, args ...interface{}) + Fatalf(format string, args ...interface{}) + Panicf(format string, args ...interface{}) + + Debug(args ...interface{}) + Info(args ...interface{}) + Print(args ...interface{}) + Warn(args ...interface{}) + Warning(args ...interface{}) + Error(args ...interface{}) + Fatal(args ...interface{}) + Panic(args ...interface{}) + + Debugln(args ...interface{}) + Infoln(args ...interface{}) + Println(args ...interface{}) + Warnln(args ...interface{}) + Warningln(args ...interface{}) + Errorln(args ...interface{}) + Fatalln(args ...interface{}) + Panicln(args ...interface{}) + + // IsDebugEnabled() bool + // IsInfoEnabled() bool + // IsWarnEnabled() bool + // IsErrorEnabled() bool + // IsFatalEnabled() bool + // IsPanicEnabled() bool +} + +// Ext1FieldLogger (the first extension to FieldLogger) is superfluous, it is +// here for consistancy. Do not use. Use Logger or Entry instead. +type Ext1FieldLogger interface { + FieldLogger + Tracef(format string, args ...interface{}) + Trace(args ...interface{}) + Traceln(args ...interface{}) +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/terminal_check_aix.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/terminal_check_aix.go new file mode 100644 index 0000000000..04fdb7ba37 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/terminal_check_aix.go @@ -0,0 +1,9 @@ +// +build !appengine,!js,!windows,aix + +package logrus + +import "io" + +func checkIfTerminal(w io.Writer) bool { + return false +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/terminal_check_appengine.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/terminal_check_appengine.go new file mode 100644 index 0000000000..2403de9819 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/terminal_check_appengine.go @@ -0,0 +1,11 @@ +// +build appengine + +package logrus + +import ( + "io" +) + +func checkIfTerminal(w io.Writer) bool { + return true +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/terminal_check_js.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/terminal_check_js.go new file mode 100644 index 0000000000..0c209750a3 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/terminal_check_js.go @@ -0,0 +1,11 @@ +// +build js + +package logrus + +import ( + "io" +) + +func checkIfTerminal(w io.Writer) bool { + return false +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/terminal_check_notappengine.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/terminal_check_notappengine.go new file mode 100644 index 0000000000..d46556509e --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/terminal_check_notappengine.go @@ -0,0 +1,19 @@ +// +build !appengine,!js,!windows,!aix + +package logrus + +import ( + "io" + "os" + + "golang.org/x/crypto/ssh/terminal" +) + +func checkIfTerminal(w io.Writer) bool { + switch v := w.(type) { + case *os.File: + return terminal.IsTerminal(int(v.Fd())) + default: + return false + } +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/terminal_check_windows.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/terminal_check_windows.go new file mode 100644 index 0000000000..3b9d2864ca --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/terminal_check_windows.go @@ -0,0 +1,20 @@ +// +build !appengine,!js,windows + +package logrus + +import ( + "io" + "os" + "syscall" +) + +func checkIfTerminal(w io.Writer) bool { + switch v := w.(type) { + case *os.File: + var mode uint32 + err := syscall.GetConsoleMode(syscall.Handle(v.Fd()), &mode) + return err == nil + default: + return false + } +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/terminal_notwindows.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/terminal_notwindows.go new file mode 100644 index 0000000000..3dbd237203 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/terminal_notwindows.go @@ -0,0 +1,8 @@ +// +build !windows + +package logrus + +import "io" + +func initTerminal(w io.Writer) { +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/terminal_windows.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/terminal_windows.go new file mode 100644 index 0000000000..b4ef5286cd --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/terminal_windows.go @@ -0,0 +1,18 @@ +// +build !appengine,!js,windows + +package logrus + +import ( + "io" + "os" + "syscall" + + sequences "github.com/konsorten/go-windows-terminal-sequences" +) + +func initTerminal(w io.Writer) { + switch v := w.(type) { + case *os.File: + sequences.EnableVirtualTerminalProcessing(syscall.Handle(v.Fd()), true) + } +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/text_formatter.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/text_formatter.go new file mode 100644 index 0000000000..fb21649c9a --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/text_formatter.go @@ -0,0 +1,273 @@ +package logrus + +import ( + "bytes" + "fmt" + "os" + "runtime" + "sort" + "strings" + "sync" + "time" +) + +const ( + nocolor = 0 + red = 31 + green = 32 + yellow = 33 + blue = 36 + gray = 37 +) + +var ( + baseTimestamp time.Time + emptyFieldMap FieldMap +) + +func init() { + baseTimestamp = time.Now() +} + +// TextFormatter formats logs into text +type TextFormatter struct { + // Set to true to bypass checking for a TTY before outputting colors. + ForceColors bool + + // Force disabling colors. + DisableColors bool + + // Override coloring based on CLICOLOR and CLICOLOR_FORCE. - https://bixense.com/clicolors/ + EnvironmentOverrideColors bool + + // Disable timestamp logging. useful when output is redirected to logging + // system that already adds timestamps. + DisableTimestamp bool + + // Enable logging the full timestamp when a TTY is attached instead of just + // the time passed since beginning of execution. + FullTimestamp bool + + // TimestampFormat to use for display when a full timestamp is printed + TimestampFormat string + + // The fields are sorted by default for a consistent output. For applications + // that log extremely frequently and don't use the JSON formatter this may not + // be desired. + DisableSorting bool + + // The keys sorting function, when uninitialized it uses sort.Strings. + SortingFunc func([]string) + + // Disables the truncation of the level text to 4 characters. + DisableLevelTruncation bool + + // QuoteEmptyFields will wrap empty fields in quotes if true + QuoteEmptyFields bool + + // Whether the logger's out is to a terminal + isTerminal bool + + // FieldMap allows users to customize the names of keys for default fields. + // As an example: + // formatter := &TextFormatter{ + // FieldMap: FieldMap{ + // FieldKeyTime: "@timestamp", + // FieldKeyLevel: "@level", + // FieldKeyMsg: "@message"}} + FieldMap FieldMap + + terminalInitOnce sync.Once +} + +func (f *TextFormatter) init(entry *Entry) { + if entry.Logger != nil { + f.isTerminal = checkIfTerminal(entry.Logger.Out) + + if f.isTerminal { + initTerminal(entry.Logger.Out) + } + } +} + +func (f *TextFormatter) isColored() bool { + isColored := f.ForceColors || (f.isTerminal && (runtime.GOOS != "windows")) + + if f.EnvironmentOverrideColors { + if force, ok := os.LookupEnv("CLICOLOR_FORCE"); ok && force != "0" { + isColored = true + } else if ok && force == "0" { + isColored = false + } else if os.Getenv("CLICOLOR") == "0" { + isColored = false + } + } + + return isColored && !f.DisableColors +} + +// Format renders a single log entry +func (f *TextFormatter) Format(entry *Entry) ([]byte, error) { + data := make(Fields) + for k, v := range entry.Data { + data[k] = v + } + prefixFieldClashes(data, f.FieldMap, entry.HasCaller()) + keys := make([]string, 0, len(data)) + for k := range data { + keys = append(keys, k) + } + + fixedKeys := make([]string, 0, 4+len(data)) + if !f.DisableTimestamp { + fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyTime)) + } + fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyLevel)) + if entry.Message != "" { + fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyMsg)) + } + if entry.err != "" { + fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyLogrusError)) + } + if entry.HasCaller() { + fixedKeys = append(fixedKeys, + f.FieldMap.resolve(FieldKeyFunc), f.FieldMap.resolve(FieldKeyFile)) + } + + if !f.DisableSorting { + if f.SortingFunc == nil { + sort.Strings(keys) + fixedKeys = append(fixedKeys, keys...) + } else { + if !f.isColored() { + fixedKeys = append(fixedKeys, keys...) + f.SortingFunc(fixedKeys) + } else { + f.SortingFunc(keys) + } + } + } else { + fixedKeys = append(fixedKeys, keys...) + } + + var b *bytes.Buffer + if entry.Buffer != nil { + b = entry.Buffer + } else { + b = &bytes.Buffer{} + } + + f.terminalInitOnce.Do(func() { f.init(entry) }) + + timestampFormat := f.TimestampFormat + if timestampFormat == "" { + timestampFormat = defaultTimestampFormat + } + if f.isColored() { + f.printColored(b, entry, keys, data, timestampFormat) + } else { + for _, key := range fixedKeys { + var value interface{} + switch { + case key == f.FieldMap.resolve(FieldKeyTime): + value = entry.Time.Format(timestampFormat) + case key == f.FieldMap.resolve(FieldKeyLevel): + value = entry.Level.String() + case key == f.FieldMap.resolve(FieldKeyMsg): + value = entry.Message + case key == f.FieldMap.resolve(FieldKeyLogrusError): + value = entry.err + case key == f.FieldMap.resolve(FieldKeyFunc) && entry.HasCaller(): + value = entry.Caller.Function + case key == f.FieldMap.resolve(FieldKeyFile) && entry.HasCaller(): + value = fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line) + default: + value = data[key] + } + f.appendKeyValue(b, key, value) + } + } + + b.WriteByte('\n') + return b.Bytes(), nil +} + +func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []string, data Fields, timestampFormat string) { + var levelColor int + switch entry.Level { + case DebugLevel, TraceLevel: + levelColor = gray + case WarnLevel: + levelColor = yellow + case ErrorLevel, FatalLevel, PanicLevel: + levelColor = red + default: + levelColor = blue + } + + levelText := strings.ToUpper(entry.Level.String()) + if !f.DisableLevelTruncation { + levelText = levelText[0:4] + } + + // Remove a single newline if it already exists in the message to keep + // the behavior of logrus text_formatter the same as the stdlib log package + entry.Message = strings.TrimSuffix(entry.Message, "\n") + + caller := "" + + if entry.HasCaller() { + caller = fmt.Sprintf("%s:%d %s()", + entry.Caller.File, entry.Caller.Line, entry.Caller.Function) + } + + if f.DisableTimestamp { + fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m%s %-44s ", levelColor, levelText, caller, entry.Message) + } else if !f.FullTimestamp { + fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d]%s %-44s ", levelColor, levelText, int(entry.Time.Sub(baseTimestamp)/time.Second), caller, entry.Message) + } else { + fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s]%s %-44s ", levelColor, levelText, entry.Time.Format(timestampFormat), caller, entry.Message) + } + for _, k := range keys { + v := data[k] + fmt.Fprintf(b, " \x1b[%dm%s\x1b[0m=", levelColor, k) + f.appendValue(b, v) + } +} + +func (f *TextFormatter) needsQuoting(text string) bool { + if f.QuoteEmptyFields && len(text) == 0 { + return true + } + for _, ch := range text { + if !((ch >= 'a' && ch <= 'z') || + (ch >= 'A' && ch <= 'Z') || + (ch >= '0' && ch <= '9') || + ch == '-' || ch == '.' || ch == '_' || ch == '/' || ch == '@' || ch == '^' || ch == '+') { + return true + } + } + return false +} + +func (f *TextFormatter) appendKeyValue(b *bytes.Buffer, key string, value interface{}) { + if b.Len() > 0 { + b.WriteByte(' ') + } + b.WriteString(key) + b.WriteByte('=') + f.appendValue(b, value) +} + +func (f *TextFormatter) appendValue(b *bytes.Buffer, value interface{}) { + stringVal, ok := value.(string) + if !ok { + stringVal = fmt.Sprint(value) + } + + if !f.needsQuoting(stringVal) { + b.WriteString(stringVal) + } else { + b.WriteString(fmt.Sprintf("%q", stringVal)) + } +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/writer.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/writer.go new file mode 100644 index 0000000000..9e1f751359 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/sirupsen/logrus/writer.go @@ -0,0 +1,64 @@ +package logrus + +import ( + "bufio" + "io" + "runtime" +) + +func (logger *Logger) Writer() *io.PipeWriter { + return logger.WriterLevel(InfoLevel) +} + +func (logger *Logger) WriterLevel(level Level) *io.PipeWriter { + return NewEntry(logger).WriterLevel(level) +} + +func (entry *Entry) Writer() *io.PipeWriter { + return entry.WriterLevel(InfoLevel) +} + +func (entry *Entry) WriterLevel(level Level) *io.PipeWriter { + reader, writer := io.Pipe() + + var printFunc func(args ...interface{}) + + switch level { + case TraceLevel: + printFunc = entry.Trace + case DebugLevel: + printFunc = entry.Debug + case InfoLevel: + printFunc = entry.Info + case WarnLevel: + printFunc = entry.Warn + case ErrorLevel: + printFunc = entry.Error + case FatalLevel: + printFunc = entry.Fatal + case PanicLevel: + printFunc = entry.Panic + default: + printFunc = entry.Print + } + + go entry.writerScanner(reader, printFunc) + runtime.SetFinalizer(writer, writerFinalizer) + + return writer +} + +func (entry *Entry) writerScanner(reader *io.PipeReader, printFunc func(args ...interface{})) { + scanner := bufio.NewScanner(reader) + for scanner.Scan() { + printFunc(scanner.Text()) + } + if err := scanner.Err(); err != nil { + entry.Errorf("Error while reading from Writer: %s", err) + } + reader.Close() +} + +func writerFinalizer(writer *io.PipeWriter) { + writer.Close() +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/syndtr/gocapability/LICENSE b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/syndtr/gocapability/LICENSE new file mode 100644 index 0000000000..80dd96de77 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/syndtr/gocapability/LICENSE @@ -0,0 +1,24 @@ +Copyright 2013 Suryandaru Triandana +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/syndtr/gocapability/capability/capability.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/syndtr/gocapability/capability/capability.go new file mode 100644 index 0000000000..c07c55794d --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/syndtr/gocapability/capability/capability.go @@ -0,0 +1,72 @@ +// Copyright (c) 2013, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Package capability provides utilities for manipulating POSIX capabilities. +package capability + +type Capabilities interface { + // Get check whether a capability present in the given + // capabilities set. The 'which' value should be one of EFFECTIVE, + // PERMITTED, INHERITABLE, BOUNDING or AMBIENT. + Get(which CapType, what Cap) bool + + // Empty check whether all capability bits of the given capabilities + // set are zero. The 'which' value should be one of EFFECTIVE, + // PERMITTED, INHERITABLE, BOUNDING or AMBIENT. + Empty(which CapType) bool + + // Full check whether all capability bits of the given capabilities + // set are one. The 'which' value should be one of EFFECTIVE, + // PERMITTED, INHERITABLE, BOUNDING or AMBIENT. + Full(which CapType) bool + + // Set sets capabilities of the given capabilities sets. The + // 'which' value should be one or combination (OR'ed) of EFFECTIVE, + // PERMITTED, INHERITABLE, BOUNDING or AMBIENT. + Set(which CapType, caps ...Cap) + + // Unset unsets capabilities of the given capabilities sets. The + // 'which' value should be one or combination (OR'ed) of EFFECTIVE, + // PERMITTED, INHERITABLE, BOUNDING or AMBIENT. + Unset(which CapType, caps ...Cap) + + // Fill sets all bits of the given capabilities kind to one. The + // 'kind' value should be one or combination (OR'ed) of CAPS, + // BOUNDS or AMBS. + Fill(kind CapType) + + // Clear sets all bits of the given capabilities kind to zero. The + // 'kind' value should be one or combination (OR'ed) of CAPS, + // BOUNDS or AMBS. + Clear(kind CapType) + + // String return current capabilities state of the given capabilities + // set as string. The 'which' value should be one of EFFECTIVE, + // PERMITTED, INHERITABLE BOUNDING or AMBIENT + StringCap(which CapType) string + + // String return current capabilities state as string. + String() string + + // Load load actual capabilities value. This will overwrite all + // outstanding changes. + Load() error + + // Apply apply the capabilities settings, so all changes will take + // effect. + Apply(kind CapType) error +} + +// NewPid create new initialized Capabilities object for given pid when it +// is nonzero, or for the current pid if pid is 0 +func NewPid(pid int) (Capabilities, error) { + return newPid(pid) +} + +// NewFile create new initialized Capabilities object for given named file. +func NewFile(name string) (Capabilities, error) { + return newFile(name) +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/syndtr/gocapability/capability/capability_linux.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/syndtr/gocapability/capability/capability_linux.go new file mode 100644 index 0000000000..205e0f7013 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/syndtr/gocapability/capability/capability_linux.go @@ -0,0 +1,650 @@ +// Copyright (c) 2013, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package capability + +import ( + "bufio" + "errors" + "fmt" + "io" + "os" + "strings" + "syscall" +) + +var errUnknownVers = errors.New("unknown capability version") + +const ( + linuxCapVer1 = 0x19980330 + linuxCapVer2 = 0x20071026 + linuxCapVer3 = 0x20080522 +) + +var ( + capVers uint32 + capLastCap Cap +) + +func init() { + var hdr capHeader + capget(&hdr, nil) + capVers = hdr.version + + if initLastCap() == nil { + CAP_LAST_CAP = capLastCap + if capLastCap > 31 { + capUpperMask = (uint32(1) << (uint(capLastCap) - 31)) - 1 + } else { + capUpperMask = 0 + } + } +} + +func initLastCap() error { + if capLastCap != 0 { + return nil + } + + f, err := os.Open("/proc/sys/kernel/cap_last_cap") + if err != nil { + return err + } + defer f.Close() + + var b []byte = make([]byte, 11) + _, err = f.Read(b) + if err != nil { + return err + } + + fmt.Sscanf(string(b), "%d", &capLastCap) + + return nil +} + +func mkStringCap(c Capabilities, which CapType) (ret string) { + for i, first := Cap(0), true; i <= CAP_LAST_CAP; i++ { + if !c.Get(which, i) { + continue + } + if first { + first = false + } else { + ret += ", " + } + ret += i.String() + } + return +} + +func mkString(c Capabilities, max CapType) (ret string) { + ret = "{" + for i := CapType(1); i <= max; i <<= 1 { + ret += " " + i.String() + "=\"" + if c.Empty(i) { + ret += "empty" + } else if c.Full(i) { + ret += "full" + } else { + ret += c.StringCap(i) + } + ret += "\"" + } + ret += " }" + return +} + +func newPid(pid int) (c Capabilities, err error) { + switch capVers { + case linuxCapVer1: + p := new(capsV1) + p.hdr.version = capVers + p.hdr.pid = pid + c = p + case linuxCapVer2, linuxCapVer3: + p := new(capsV3) + p.hdr.version = capVers + p.hdr.pid = pid + c = p + default: + err = errUnknownVers + return + } + err = c.Load() + if err != nil { + c = nil + } + return +} + +type capsV1 struct { + hdr capHeader + data capData +} + +func (c *capsV1) Get(which CapType, what Cap) bool { + if what > 32 { + return false + } + + switch which { + case EFFECTIVE: + return (1< 32 { + continue + } + + if which&EFFECTIVE != 0 { + c.data.effective |= 1 << uint(what) + } + if which&PERMITTED != 0 { + c.data.permitted |= 1 << uint(what) + } + if which&INHERITABLE != 0 { + c.data.inheritable |= 1 << uint(what) + } + } +} + +func (c *capsV1) Unset(which CapType, caps ...Cap) { + for _, what := range caps { + if what > 32 { + continue + } + + if which&EFFECTIVE != 0 { + c.data.effective &= ^(1 << uint(what)) + } + if which&PERMITTED != 0 { + c.data.permitted &= ^(1 << uint(what)) + } + if which&INHERITABLE != 0 { + c.data.inheritable &= ^(1 << uint(what)) + } + } +} + +func (c *capsV1) Fill(kind CapType) { + if kind&CAPS == CAPS { + c.data.effective = 0x7fffffff + c.data.permitted = 0x7fffffff + c.data.inheritable = 0 + } +} + +func (c *capsV1) Clear(kind CapType) { + if kind&CAPS == CAPS { + c.data.effective = 0 + c.data.permitted = 0 + c.data.inheritable = 0 + } +} + +func (c *capsV1) StringCap(which CapType) (ret string) { + return mkStringCap(c, which) +} + +func (c *capsV1) String() (ret string) { + return mkString(c, BOUNDING) +} + +func (c *capsV1) Load() (err error) { + return capget(&c.hdr, &c.data) +} + +func (c *capsV1) Apply(kind CapType) error { + if kind&CAPS == CAPS { + return capset(&c.hdr, &c.data) + } + return nil +} + +type capsV3 struct { + hdr capHeader + data [2]capData + bounds [2]uint32 + ambient [2]uint32 +} + +func (c *capsV3) Get(which CapType, what Cap) bool { + var i uint + if what > 31 { + i = uint(what) >> 5 + what %= 32 + } + + switch which { + case EFFECTIVE: + return (1< 31 { + i = uint(what) >> 5 + what %= 32 + } + + if which&EFFECTIVE != 0 { + c.data[i].effective |= 1 << uint(what) + } + if which&PERMITTED != 0 { + c.data[i].permitted |= 1 << uint(what) + } + if which&INHERITABLE != 0 { + c.data[i].inheritable |= 1 << uint(what) + } + if which&BOUNDING != 0 { + c.bounds[i] |= 1 << uint(what) + } + if which&AMBIENT != 0 { + c.ambient[i] |= 1 << uint(what) + } + } +} + +func (c *capsV3) Unset(which CapType, caps ...Cap) { + for _, what := range caps { + var i uint + if what > 31 { + i = uint(what) >> 5 + what %= 32 + } + + if which&EFFECTIVE != 0 { + c.data[i].effective &= ^(1 << uint(what)) + } + if which&PERMITTED != 0 { + c.data[i].permitted &= ^(1 << uint(what)) + } + if which&INHERITABLE != 0 { + c.data[i].inheritable &= ^(1 << uint(what)) + } + if which&BOUNDING != 0 { + c.bounds[i] &= ^(1 << uint(what)) + } + if which&AMBIENT != 0 { + c.ambient[i] &= ^(1 << uint(what)) + } + } +} + +func (c *capsV3) Fill(kind CapType) { + if kind&CAPS == CAPS { + c.data[0].effective = 0xffffffff + c.data[0].permitted = 0xffffffff + c.data[0].inheritable = 0 + c.data[1].effective = 0xffffffff + c.data[1].permitted = 0xffffffff + c.data[1].inheritable = 0 + } + + if kind&BOUNDS == BOUNDS { + c.bounds[0] = 0xffffffff + c.bounds[1] = 0xffffffff + } + if kind&AMBS == AMBS { + c.ambient[0] = 0xffffffff + c.ambient[1] = 0xffffffff + } +} + +func (c *capsV3) Clear(kind CapType) { + if kind&CAPS == CAPS { + c.data[0].effective = 0 + c.data[0].permitted = 0 + c.data[0].inheritable = 0 + c.data[1].effective = 0 + c.data[1].permitted = 0 + c.data[1].inheritable = 0 + } + + if kind&BOUNDS == BOUNDS { + c.bounds[0] = 0 + c.bounds[1] = 0 + } + if kind&AMBS == AMBS { + c.ambient[0] = 0 + c.ambient[1] = 0 + } +} + +func (c *capsV3) StringCap(which CapType) (ret string) { + return mkStringCap(c, which) +} + +func (c *capsV3) String() (ret string) { + return mkString(c, BOUNDING) +} + +func (c *capsV3) Load() (err error) { + err = capget(&c.hdr, &c.data[0]) + if err != nil { + return + } + + var status_path string + + if c.hdr.pid == 0 { + status_path = fmt.Sprintf("/proc/self/status") + } else { + status_path = fmt.Sprintf("/proc/%d/status", c.hdr.pid) + } + + f, err := os.Open(status_path) + if err != nil { + return + } + b := bufio.NewReader(f) + for { + line, e := b.ReadString('\n') + if e != nil { + if e != io.EOF { + err = e + } + break + } + if strings.HasPrefix(line, "CapB") { + fmt.Sscanf(line[4:], "nd: %08x%08x", &c.bounds[1], &c.bounds[0]) + continue + } + if strings.HasPrefix(line, "CapA") { + fmt.Sscanf(line[4:], "mb: %08x%08x", &c.ambient[1], &c.ambient[0]) + continue + } + } + f.Close() + + return +} + +func (c *capsV3) Apply(kind CapType) (err error) { + if kind&BOUNDS == BOUNDS { + var data [2]capData + err = capget(&c.hdr, &data[0]) + if err != nil { + return + } + if (1< 31 { + if c.data.version == 1 { + return false + } + i = uint(what) >> 5 + what %= 32 + } + + switch which { + case EFFECTIVE: + return (1< 31 { + if c.data.version == 1 { + continue + } + i = uint(what) >> 5 + what %= 32 + } + + if which&EFFECTIVE != 0 { + c.data.effective[i] |= 1 << uint(what) + } + if which&PERMITTED != 0 { + c.data.data[i].permitted |= 1 << uint(what) + } + if which&INHERITABLE != 0 { + c.data.data[i].inheritable |= 1 << uint(what) + } + } +} + +func (c *capsFile) Unset(which CapType, caps ...Cap) { + for _, what := range caps { + var i uint + if what > 31 { + if c.data.version == 1 { + continue + } + i = uint(what) >> 5 + what %= 32 + } + + if which&EFFECTIVE != 0 { + c.data.effective[i] &= ^(1 << uint(what)) + } + if which&PERMITTED != 0 { + c.data.data[i].permitted &= ^(1 << uint(what)) + } + if which&INHERITABLE != 0 { + c.data.data[i].inheritable &= ^(1 << uint(what)) + } + } +} + +func (c *capsFile) Fill(kind CapType) { + if kind&CAPS == CAPS { + c.data.effective[0] = 0xffffffff + c.data.data[0].permitted = 0xffffffff + c.data.data[0].inheritable = 0 + if c.data.version == 2 { + c.data.effective[1] = 0xffffffff + c.data.data[1].permitted = 0xffffffff + c.data.data[1].inheritable = 0 + } + } +} + +func (c *capsFile) Clear(kind CapType) { + if kind&CAPS == CAPS { + c.data.effective[0] = 0 + c.data.data[0].permitted = 0 + c.data.data[0].inheritable = 0 + if c.data.version == 2 { + c.data.effective[1] = 0 + c.data.data[1].permitted = 0 + c.data.data[1].inheritable = 0 + } + } +} + +func (c *capsFile) StringCap(which CapType) (ret string) { + return mkStringCap(c, which) +} + +func (c *capsFile) String() (ret string) { + return mkString(c, INHERITABLE) +} + +func (c *capsFile) Load() (err error) { + return getVfsCap(c.path, &c.data) +} + +func (c *capsFile) Apply(kind CapType) (err error) { + if kind&CAPS == CAPS { + return setVfsCap(c.path, &c.data) + } + return +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/syndtr/gocapability/capability/capability_noop.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/syndtr/gocapability/capability/capability_noop.go new file mode 100644 index 0000000000..9bb3070c5e --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/syndtr/gocapability/capability/capability_noop.go @@ -0,0 +1,19 @@ +// Copyright (c) 2013, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// +build !linux + +package capability + +import "errors" + +func newPid(pid int) (Capabilities, error) { + return nil, errors.New("not supported") +} + +func newFile(path string) (Capabilities, error) { + return nil, errors.New("not supported") +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/syndtr/gocapability/capability/enum.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/syndtr/gocapability/capability/enum.go new file mode 100644 index 0000000000..693817317b --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/syndtr/gocapability/capability/enum.go @@ -0,0 +1,268 @@ +// Copyright (c) 2013, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package capability + +type CapType uint + +func (c CapType) String() string { + switch c { + case EFFECTIVE: + return "effective" + case PERMITTED: + return "permitted" + case INHERITABLE: + return "inheritable" + case BOUNDING: + return "bounding" + case CAPS: + return "caps" + case AMBIENT: + return "ambient" + } + return "unknown" +} + +const ( + EFFECTIVE CapType = 1 << iota + PERMITTED + INHERITABLE + BOUNDING + AMBIENT + + CAPS = EFFECTIVE | PERMITTED | INHERITABLE + BOUNDS = BOUNDING + AMBS = AMBIENT +) + +//go:generate go run enumgen/gen.go +type Cap int + +// POSIX-draft defined capabilities. +const ( + // In a system with the [_POSIX_CHOWN_RESTRICTED] option defined, this + // overrides the restriction of changing file ownership and group + // ownership. + CAP_CHOWN = Cap(0) + + // Override all DAC access, including ACL execute access if + // [_POSIX_ACL] is defined. Excluding DAC access covered by + // CAP_LINUX_IMMUTABLE. + CAP_DAC_OVERRIDE = Cap(1) + + // Overrides all DAC restrictions regarding read and search on files + // and directories, including ACL restrictions if [_POSIX_ACL] is + // defined. Excluding DAC access covered by CAP_LINUX_IMMUTABLE. + CAP_DAC_READ_SEARCH = Cap(2) + + // Overrides all restrictions about allowed operations on files, where + // file owner ID must be equal to the user ID, except where CAP_FSETID + // is applicable. It doesn't override MAC and DAC restrictions. + CAP_FOWNER = Cap(3) + + // Overrides the following restrictions that the effective user ID + // shall match the file owner ID when setting the S_ISUID and S_ISGID + // bits on that file; that the effective group ID (or one of the + // supplementary group IDs) shall match the file owner ID when setting + // the S_ISGID bit on that file; that the S_ISUID and S_ISGID bits are + // cleared on successful return from chown(2) (not implemented). + CAP_FSETID = Cap(4) + + // Overrides the restriction that the real or effective user ID of a + // process sending a signal must match the real or effective user ID + // of the process receiving the signal. + CAP_KILL = Cap(5) + + // Allows setgid(2) manipulation + // Allows setgroups(2) + // Allows forged gids on socket credentials passing. + CAP_SETGID = Cap(6) + + // Allows set*uid(2) manipulation (including fsuid). + // Allows forged pids on socket credentials passing. + CAP_SETUID = Cap(7) + + // Linux-specific capabilities + + // Without VFS support for capabilities: + // Transfer any capability in your permitted set to any pid, + // remove any capability in your permitted set from any pid + // With VFS support for capabilities (neither of above, but) + // Add any capability from current's capability bounding set + // to the current process' inheritable set + // Allow taking bits out of capability bounding set + // Allow modification of the securebits for a process + CAP_SETPCAP = Cap(8) + + // Allow modification of S_IMMUTABLE and S_APPEND file attributes + CAP_LINUX_IMMUTABLE = Cap(9) + + // Allows binding to TCP/UDP sockets below 1024 + // Allows binding to ATM VCIs below 32 + CAP_NET_BIND_SERVICE = Cap(10) + + // Allow broadcasting, listen to multicast + CAP_NET_BROADCAST = Cap(11) + + // Allow interface configuration + // Allow administration of IP firewall, masquerading and accounting + // Allow setting debug option on sockets + // Allow modification of routing tables + // Allow setting arbitrary process / process group ownership on + // sockets + // Allow binding to any address for transparent proxying (also via NET_RAW) + // Allow setting TOS (type of service) + // Allow setting promiscuous mode + // Allow clearing driver statistics + // Allow multicasting + // Allow read/write of device-specific registers + // Allow activation of ATM control sockets + CAP_NET_ADMIN = Cap(12) + + // Allow use of RAW sockets + // Allow use of PACKET sockets + // Allow binding to any address for transparent proxying (also via NET_ADMIN) + CAP_NET_RAW = Cap(13) + + // Allow locking of shared memory segments + // Allow mlock and mlockall (which doesn't really have anything to do + // with IPC) + CAP_IPC_LOCK = Cap(14) + + // Override IPC ownership checks + CAP_IPC_OWNER = Cap(15) + + // Insert and remove kernel modules - modify kernel without limit + CAP_SYS_MODULE = Cap(16) + + // Allow ioperm/iopl access + // Allow sending USB messages to any device via /proc/bus/usb + CAP_SYS_RAWIO = Cap(17) + + // Allow use of chroot() + CAP_SYS_CHROOT = Cap(18) + + // Allow ptrace() of any process + CAP_SYS_PTRACE = Cap(19) + + // Allow configuration of process accounting + CAP_SYS_PACCT = Cap(20) + + // Allow configuration of the secure attention key + // Allow administration of the random device + // Allow examination and configuration of disk quotas + // Allow setting the domainname + // Allow setting the hostname + // Allow calling bdflush() + // Allow mount() and umount(), setting up new smb connection + // Allow some autofs root ioctls + // Allow nfsservctl + // Allow VM86_REQUEST_IRQ + // Allow to read/write pci config on alpha + // Allow irix_prctl on mips (setstacksize) + // Allow flushing all cache on m68k (sys_cacheflush) + // Allow removing semaphores + // Used instead of CAP_CHOWN to "chown" IPC message queues, semaphores + // and shared memory + // Allow locking/unlocking of shared memory segment + // Allow turning swap on/off + // Allow forged pids on socket credentials passing + // Allow setting readahead and flushing buffers on block devices + // Allow setting geometry in floppy driver + // Allow turning DMA on/off in xd driver + // Allow administration of md devices (mostly the above, but some + // extra ioctls) + // Allow tuning the ide driver + // Allow access to the nvram device + // Allow administration of apm_bios, serial and bttv (TV) device + // Allow manufacturer commands in isdn CAPI support driver + // Allow reading non-standardized portions of pci configuration space + // Allow DDI debug ioctl on sbpcd driver + // Allow setting up serial ports + // Allow sending raw qic-117 commands + // Allow enabling/disabling tagged queuing on SCSI controllers and sending + // arbitrary SCSI commands + // Allow setting encryption key on loopback filesystem + // Allow setting zone reclaim policy + CAP_SYS_ADMIN = Cap(21) + + // Allow use of reboot() + CAP_SYS_BOOT = Cap(22) + + // Allow raising priority and setting priority on other (different + // UID) processes + // Allow use of FIFO and round-robin (realtime) scheduling on own + // processes and setting the scheduling algorithm used by another + // process. + // Allow setting cpu affinity on other processes + CAP_SYS_NICE = Cap(23) + + // Override resource limits. Set resource limits. + // Override quota limits. + // Override reserved space on ext2 filesystem + // Modify data journaling mode on ext3 filesystem (uses journaling + // resources) + // NOTE: ext2 honors fsuid when checking for resource overrides, so + // you can override using fsuid too + // Override size restrictions on IPC message queues + // Allow more than 64hz interrupts from the real-time clock + // Override max number of consoles on console allocation + // Override max number of keymaps + CAP_SYS_RESOURCE = Cap(24) + + // Allow manipulation of system clock + // Allow irix_stime on mips + // Allow setting the real-time clock + CAP_SYS_TIME = Cap(25) + + // Allow configuration of tty devices + // Allow vhangup() of tty + CAP_SYS_TTY_CONFIG = Cap(26) + + // Allow the privileged aspects of mknod() + CAP_MKNOD = Cap(27) + + // Allow taking of leases on files + CAP_LEASE = Cap(28) + + CAP_AUDIT_WRITE = Cap(29) + CAP_AUDIT_CONTROL = Cap(30) + CAP_SETFCAP = Cap(31) + + // Override MAC access. + // The base kernel enforces no MAC policy. + // An LSM may enforce a MAC policy, and if it does and it chooses + // to implement capability based overrides of that policy, this is + // the capability it should use to do so. + CAP_MAC_OVERRIDE = Cap(32) + + // Allow MAC configuration or state changes. + // The base kernel requires no MAC configuration. + // An LSM may enforce a MAC policy, and if it does and it chooses + // to implement capability based checks on modifications to that + // policy or the data required to maintain it, this is the + // capability it should use to do so. + CAP_MAC_ADMIN = Cap(33) + + // Allow configuring the kernel's syslog (printk behaviour) + CAP_SYSLOG = Cap(34) + + // Allow triggering something that will wake the system + CAP_WAKE_ALARM = Cap(35) + + // Allow preventing system suspends + CAP_BLOCK_SUSPEND = Cap(36) + + // Allow reading audit messages from the kernel + CAP_AUDIT_READ = Cap(37) +) + +var ( + // Highest valid capability of the running kernel. + CAP_LAST_CAP = Cap(63) + + capUpperMask = ^uint32(0) +) diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/syndtr/gocapability/capability/enum_gen.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/syndtr/gocapability/capability/enum_gen.go new file mode 100644 index 0000000000..b9e6d2d5e1 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/syndtr/gocapability/capability/enum_gen.go @@ -0,0 +1,129 @@ +// generated file; DO NOT EDIT - use go generate in directory with source + +package capability + +func (c Cap) String() string { + switch c { + case CAP_CHOWN: + return "chown" + case CAP_DAC_OVERRIDE: + return "dac_override" + case CAP_DAC_READ_SEARCH: + return "dac_read_search" + case CAP_FOWNER: + return "fowner" + case CAP_FSETID: + return "fsetid" + case CAP_KILL: + return "kill" + case CAP_SETGID: + return "setgid" + case CAP_SETUID: + return "setuid" + case CAP_SETPCAP: + return "setpcap" + case CAP_LINUX_IMMUTABLE: + return "linux_immutable" + case CAP_NET_BIND_SERVICE: + return "net_bind_service" + case CAP_NET_BROADCAST: + return "net_broadcast" + case CAP_NET_ADMIN: + return "net_admin" + case CAP_NET_RAW: + return "net_raw" + case CAP_IPC_LOCK: + return "ipc_lock" + case CAP_IPC_OWNER: + return "ipc_owner" + case CAP_SYS_MODULE: + return "sys_module" + case CAP_SYS_RAWIO: + return "sys_rawio" + case CAP_SYS_CHROOT: + return "sys_chroot" + case CAP_SYS_PTRACE: + return "sys_ptrace" + case CAP_SYS_PACCT: + return "sys_pacct" + case CAP_SYS_ADMIN: + return "sys_admin" + case CAP_SYS_BOOT: + return "sys_boot" + case CAP_SYS_NICE: + return "sys_nice" + case CAP_SYS_RESOURCE: + return "sys_resource" + case CAP_SYS_TIME: + return "sys_time" + case CAP_SYS_TTY_CONFIG: + return "sys_tty_config" + case CAP_MKNOD: + return "mknod" + case CAP_LEASE: + return "lease" + case CAP_AUDIT_WRITE: + return "audit_write" + case CAP_AUDIT_CONTROL: + return "audit_control" + case CAP_SETFCAP: + return "setfcap" + case CAP_MAC_OVERRIDE: + return "mac_override" + case CAP_MAC_ADMIN: + return "mac_admin" + case CAP_SYSLOG: + return "syslog" + case CAP_WAKE_ALARM: + return "wake_alarm" + case CAP_BLOCK_SUSPEND: + return "block_suspend" + case CAP_AUDIT_READ: + return "audit_read" + } + return "unknown" +} + +// List returns list of all supported capabilities +func List() []Cap { + return []Cap{ + CAP_CHOWN, + CAP_DAC_OVERRIDE, + CAP_DAC_READ_SEARCH, + CAP_FOWNER, + CAP_FSETID, + CAP_KILL, + CAP_SETGID, + CAP_SETUID, + CAP_SETPCAP, + CAP_LINUX_IMMUTABLE, + CAP_NET_BIND_SERVICE, + CAP_NET_BROADCAST, + CAP_NET_ADMIN, + CAP_NET_RAW, + CAP_IPC_LOCK, + CAP_IPC_OWNER, + CAP_SYS_MODULE, + CAP_SYS_RAWIO, + CAP_SYS_CHROOT, + CAP_SYS_PTRACE, + CAP_SYS_PACCT, + CAP_SYS_ADMIN, + CAP_SYS_BOOT, + CAP_SYS_NICE, + CAP_SYS_RESOURCE, + CAP_SYS_TIME, + CAP_SYS_TTY_CONFIG, + CAP_MKNOD, + CAP_LEASE, + CAP_AUDIT_WRITE, + CAP_AUDIT_CONTROL, + CAP_SETFCAP, + CAP_MAC_OVERRIDE, + CAP_MAC_ADMIN, + CAP_SYSLOG, + CAP_WAKE_ALARM, + CAP_BLOCK_SUSPEND, + CAP_AUDIT_READ, + } +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/syndtr/gocapability/capability/syscall_linux.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/syndtr/gocapability/capability/syscall_linux.go new file mode 100644 index 0000000000..eb7170083a --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/syndtr/gocapability/capability/syscall_linux.go @@ -0,0 +1,154 @@ +// Copyright (c) 2013, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package capability + +import ( + "syscall" + "unsafe" +) + +type capHeader struct { + version uint32 + pid int +} + +type capData struct { + effective uint32 + permitted uint32 + inheritable uint32 +} + +func capget(hdr *capHeader, data *capData) (err error) { + _, _, e1 := syscall.Syscall(syscall.SYS_CAPGET, uintptr(unsafe.Pointer(hdr)), uintptr(unsafe.Pointer(data)), 0) + if e1 != 0 { + err = e1 + } + return +} + +func capset(hdr *capHeader, data *capData) (err error) { + _, _, e1 := syscall.Syscall(syscall.SYS_CAPSET, uintptr(unsafe.Pointer(hdr)), uintptr(unsafe.Pointer(data)), 0) + if e1 != 0 { + err = e1 + } + return +} + +// not yet in syscall +const ( + pr_CAP_AMBIENT = 47 + pr_CAP_AMBIENT_IS_SET = uintptr(1) + pr_CAP_AMBIENT_RAISE = uintptr(2) + pr_CAP_AMBIENT_LOWER = uintptr(3) + pr_CAP_AMBIENT_CLEAR_ALL = uintptr(4) +) + +func prctl(option int, arg2, arg3, arg4, arg5 uintptr) (err error) { + _, _, e1 := syscall.Syscall6(syscall.SYS_PRCTL, uintptr(option), arg2, arg3, arg4, arg5, 0) + if e1 != 0 { + err = e1 + } + return +} + +const ( + vfsXattrName = "security.capability" + + vfsCapVerMask = 0xff000000 + vfsCapVer1 = 0x01000000 + vfsCapVer2 = 0x02000000 + + vfsCapFlagMask = ^vfsCapVerMask + vfsCapFlageffective = 0x000001 + + vfscapDataSizeV1 = 4 * (1 + 2*1) + vfscapDataSizeV2 = 4 * (1 + 2*2) +) + +type vfscapData struct { + magic uint32 + data [2]struct { + permitted uint32 + inheritable uint32 + } + effective [2]uint32 + version int8 +} + +var ( + _vfsXattrName *byte +) + +func init() { + _vfsXattrName, _ = syscall.BytePtrFromString(vfsXattrName) +} + +func getVfsCap(path string, dest *vfscapData) (err error) { + var _p0 *byte + _p0, err = syscall.BytePtrFromString(path) + if err != nil { + return + } + r0, _, e1 := syscall.Syscall6(syscall.SYS_GETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_vfsXattrName)), uintptr(unsafe.Pointer(dest)), vfscapDataSizeV2, 0, 0) + if e1 != 0 { + if e1 == syscall.ENODATA { + dest.version = 2 + return + } + err = e1 + } + switch dest.magic & vfsCapVerMask { + case vfsCapVer1: + dest.version = 1 + if r0 != vfscapDataSizeV1 { + return syscall.EINVAL + } + dest.data[1].permitted = 0 + dest.data[1].inheritable = 0 + case vfsCapVer2: + dest.version = 2 + if r0 != vfscapDataSizeV2 { + return syscall.EINVAL + } + default: + return syscall.EINVAL + } + if dest.magic&vfsCapFlageffective != 0 { + dest.effective[0] = dest.data[0].permitted | dest.data[0].inheritable + dest.effective[1] = dest.data[1].permitted | dest.data[1].inheritable + } else { + dest.effective[0] = 0 + dest.effective[1] = 0 + } + return +} + +func setVfsCap(path string, data *vfscapData) (err error) { + var _p0 *byte + _p0, err = syscall.BytePtrFromString(path) + if err != nil { + return + } + var size uintptr + if data.version == 1 { + data.magic = vfsCapVer1 + size = vfscapDataSizeV1 + } else if data.version == 2 { + data.magic = vfsCapVer2 + if data.effective[0] != 0 || data.effective[1] != 0 { + data.magic |= vfsCapFlageffective + } + size = vfscapDataSizeV2 + } else { + return syscall.EINVAL + } + _, _, e1 := syscall.Syscall6(syscall.SYS_SETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_vfsXattrName)), uintptr(unsafe.Pointer(data)), size, 0, 0) + if e1 != 0 { + err = e1 + } + return +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/urfave/cli/LICENSE b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/urfave/cli/LICENSE new file mode 100644 index 0000000000..42a597e29b --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/urfave/cli/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2016 Jeremy Saenz & Contributors + +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. diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/urfave/cli/README.md b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/urfave/cli/README.md new file mode 100644 index 0000000000..34055fe744 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/urfave/cli/README.md @@ -0,0 +1,1391 @@ +cli +=== + +[![Build Status](https://travis-ci.org/urfave/cli.svg?branch=master)](https://travis-ci.org/urfave/cli) +[![Windows Build Status](https://ci.appveyor.com/api/projects/status/rtgk5xufi932pb2v?svg=true)](https://ci.appveyor.com/project/urfave/cli) +[![GoDoc](https://godoc.org/github.com/urfave/cli?status.svg)](https://godoc.org/github.com/urfave/cli) +[![codebeat](https://codebeat.co/badges/0a8f30aa-f975-404b-b878-5fab3ae1cc5f)](https://codebeat.co/projects/jackfan.us.kg-urfave-cli) +[![Go Report Card](https://goreportcard.com/badge/urfave/cli)](https://goreportcard.com/report/urfave/cli) +[![top level coverage](https://gocover.io/_badge/github.com/urfave/cli?0 "top level coverage")](http://gocover.io/github.com/urfave/cli) / +[![altsrc coverage](https://gocover.io/_badge/github.com/urfave/cli/altsrc?0 "altsrc coverage")](http://gocover.io/github.com/urfave/cli/altsrc) + +**Notice:** This is the library formerly known as +`github.com/codegangsta/cli` -- Github will automatically redirect requests +to this repository, but we recommend updating your references for clarity. + +cli is a simple, fast, and fun package for building command line apps in Go. The +goal is to enable developers to write fast and distributable command line +applications in an expressive way. + + + +- [Overview](#overview) +- [Installation](#installation) + * [Supported platforms](#supported-platforms) + * [Using the `v2` branch](#using-the-v2-branch) + * [Pinning to the `v1` releases](#pinning-to-the-v1-releases) +- [Getting Started](#getting-started) +- [Examples](#examples) + * [Arguments](#arguments) + * [Flags](#flags) + + [Placeholder Values](#placeholder-values) + + [Alternate Names](#alternate-names) + + [Ordering](#ordering) + + [Values from the Environment](#values-from-the-environment) + + [Values from alternate input sources (YAML, TOML, and others)](#values-from-alternate-input-sources-yaml-toml-and-others) + + [Precedence](#precedence) + * [Subcommands](#subcommands) + * [Subcommands categories](#subcommands-categories) + * [Exit code](#exit-code) + * [Bash Completion](#bash-completion) + + [Enabling](#enabling) + + [Distribution](#distribution) + + [Customization](#customization) + * [Generated Help Text](#generated-help-text) + + [Customization](#customization-1) + * [Version Flag](#version-flag) + + [Customization](#customization-2) + + [Full API Example](#full-api-example) +- [Contribution Guidelines](#contribution-guidelines) + + + +## Overview + +Command line apps are usually so tiny that there is absolutely no reason why +your code should *not* be self-documenting. Things like generating help text and +parsing command flags/options should not hinder productivity when writing a +command line app. + +**This is where cli comes into play.** cli makes command line programming fun, +organized, and expressive! + +## Installation + +Make sure you have a working Go environment. Go version 1.2+ is supported. [See +the install instructions for Go](http://golang.org/doc/install.html). + +To install cli, simply run: +``` +$ go get github.com/urfave/cli +``` + +Make sure your `PATH` includes the `$GOPATH/bin` directory so your commands can +be easily used: +``` +export PATH=$PATH:$GOPATH/bin +``` + +### Supported platforms + +cli is tested against multiple versions of Go on Linux, and against the latest +released version of Go on OS X and Windows. For full details, see +[`./.travis.yml`](./.travis.yml) and [`./appveyor.yml`](./appveyor.yml). + +### Using the `v2` branch + +**Warning**: The `v2` branch is currently unreleased and considered unstable. + +There is currently a long-lived branch named `v2` that is intended to land as +the new `master` branch once development there has settled down. The current +`master` branch (mirrored as `v1`) is being manually merged into `v2` on +an irregular human-based schedule, but generally if one wants to "upgrade" to +`v2` *now* and accept the volatility (read: "awesomeness") that comes along with +that, please use whatever version pinning of your preference, such as via +`gopkg.in`: + +``` +$ go get gopkg.in/urfave/cli.v2 +``` + +``` go +... +import ( + "gopkg.in/urfave/cli.v2" // imports as package "cli" +) +... +``` + +### Pinning to the `v1` releases + +Similarly to the section above describing use of the `v2` branch, if one wants +to avoid any unexpected compatibility pains once `v2` becomes `master`, then +pinning to `v1` is an acceptable option, e.g.: + +``` +$ go get gopkg.in/urfave/cli.v1 +``` + +``` go +... +import ( + "gopkg.in/urfave/cli.v1" // imports as package "cli" +) +... +``` + +This will pull the latest tagged `v1` release (e.g. `v1.18.1` at the time of writing). + +## Getting Started + +One of the philosophies behind cli is that an API should be playful and full of +discovery. So a cli app can be as little as one line of code in `main()`. + + +``` go +package main + +import ( + "os" + + "github.com/urfave/cli" +) + +func main() { + cli.NewApp().Run(os.Args) +} +``` + +This app will run and show help text, but is not very useful. Let's give an +action to execute and some help documentation: + + +``` go +package main + +import ( + "fmt" + "os" + + "github.com/urfave/cli" +) + +func main() { + app := cli.NewApp() + app.Name = "boom" + app.Usage = "make an explosive entrance" + app.Action = func(c *cli.Context) error { + fmt.Println("boom! I say!") + return nil + } + + app.Run(os.Args) +} +``` + +Running this already gives you a ton of functionality, plus support for things +like subcommands and flags, which are covered below. + +## Examples + +Being a programmer can be a lonely job. Thankfully by the power of automation +that is not the case! Let's create a greeter app to fend off our demons of +loneliness! + +Start by creating a directory named `greet`, and within it, add a file, +`greet.go` with the following code in it: + + +``` go +package main + +import ( + "fmt" + "os" + + "github.com/urfave/cli" +) + +func main() { + app := cli.NewApp() + app.Name = "greet" + app.Usage = "fight the loneliness!" + app.Action = func(c *cli.Context) error { + fmt.Println("Hello friend!") + return nil + } + + app.Run(os.Args) +} +``` + +Install our command to the `$GOPATH/bin` directory: + +``` +$ go install +``` + +Finally run our new command: + +``` +$ greet +Hello friend! +``` + +cli also generates neat help text: + +``` +$ greet help +NAME: + greet - fight the loneliness! + +USAGE: + greet [global options] command [command options] [arguments...] + +VERSION: + 0.0.0 + +COMMANDS: + help, h Shows a list of commands or help for one command + +GLOBAL OPTIONS + --version Shows version information +``` + +### Arguments + +You can lookup arguments by calling the `Args` function on `cli.Context`, e.g.: + + +``` go +package main + +import ( + "fmt" + "os" + + "github.com/urfave/cli" +) + +func main() { + app := cli.NewApp() + + app.Action = func(c *cli.Context) error { + fmt.Printf("Hello %q", c.Args().Get(0)) + return nil + } + + app.Run(os.Args) +} +``` + +### Flags + +Setting and querying flags is simple. + + +``` go +package main + +import ( + "fmt" + "os" + + "github.com/urfave/cli" +) + +func main() { + app := cli.NewApp() + + app.Flags = []cli.Flag { + cli.StringFlag{ + Name: "lang", + Value: "english", + Usage: "language for the greeting", + }, + } + + app.Action = func(c *cli.Context) error { + name := "Nefertiti" + if c.NArg() > 0 { + name = c.Args().Get(0) + } + if c.String("lang") == "spanish" { + fmt.Println("Hola", name) + } else { + fmt.Println("Hello", name) + } + return nil + } + + app.Run(os.Args) +} +``` + +You can also set a destination variable for a flag, to which the content will be +scanned. + + +``` go +package main + +import ( + "os" + "fmt" + + "github.com/urfave/cli" +) + +func main() { + var language string + + app := cli.NewApp() + + app.Flags = []cli.Flag { + cli.StringFlag{ + Name: "lang", + Value: "english", + Usage: "language for the greeting", + Destination: &language, + }, + } + + app.Action = func(c *cli.Context) error { + name := "someone" + if c.NArg() > 0 { + name = c.Args()[0] + } + if language == "spanish" { + fmt.Println("Hola", name) + } else { + fmt.Println("Hello", name) + } + return nil + } + + app.Run(os.Args) +} +``` + +See full list of flags at http://godoc.org/github.com/urfave/cli + +#### Placeholder Values + +Sometimes it's useful to specify a flag's value within the usage string itself. +Such placeholders are indicated with back quotes. + +For example this: + + +```go +package main + +import ( + "os" + + "github.com/urfave/cli" +) + +func main() { + app := cli.NewApp() + + app.Flags = []cli.Flag{ + cli.StringFlag{ + Name: "config, c", + Usage: "Load configuration from `FILE`", + }, + } + + app.Run(os.Args) +} +``` + +Will result in help output like: + +``` +--config FILE, -c FILE Load configuration from FILE +``` + +Note that only the first placeholder is used. Subsequent back-quoted words will +be left as-is. + +#### Alternate Names + +You can set alternate (or short) names for flags by providing a comma-delimited +list for the `Name`. e.g. + + +``` go +package main + +import ( + "os" + + "github.com/urfave/cli" +) + +func main() { + app := cli.NewApp() + + app.Flags = []cli.Flag { + cli.StringFlag{ + Name: "lang, l", + Value: "english", + Usage: "language for the greeting", + }, + } + + app.Run(os.Args) +} +``` + +That flag can then be set with `--lang spanish` or `-l spanish`. Note that +giving two different forms of the same flag in the same command invocation is an +error. + +#### Ordering + +Flags for the application and commands are shown in the order they are defined. +However, it's possible to sort them from outside this library by using `FlagsByName` +or `CommandsByName` with `sort`. + +For example this: + + +``` go +package main + +import ( + "os" + "sort" + + "github.com/urfave/cli" +) + +func main() { + app := cli.NewApp() + + app.Flags = []cli.Flag { + cli.StringFlag{ + Name: "lang, l", + Value: "english", + Usage: "Language for the greeting", + }, + cli.StringFlag{ + Name: "config, c", + Usage: "Load configuration from `FILE`", + }, + } + + app.Commands = []cli.Command{ + { + Name: "complete", + Aliases: []string{"c"}, + Usage: "complete a task on the list", + Action: func(c *cli.Context) error { + return nil + }, + }, + { + Name: "add", + Aliases: []string{"a"}, + Usage: "add a task to the list", + Action: func(c *cli.Context) error { + return nil + }, + }, + } + + sort.Sort(cli.FlagsByName(app.Flags)) + sort.Sort(cli.CommandsByName(app.Commands)) + + app.Run(os.Args) +} +``` + +Will result in help output like: + +``` +--config FILE, -c FILE Load configuration from FILE +--lang value, -l value Language for the greeting (default: "english") +``` + +#### Values from the Environment + +You can also have the default value set from the environment via `EnvVar`. e.g. + + +``` go +package main + +import ( + "os" + + "github.com/urfave/cli" +) + +func main() { + app := cli.NewApp() + + app.Flags = []cli.Flag { + cli.StringFlag{ + Name: "lang, l", + Value: "english", + Usage: "language for the greeting", + EnvVar: "APP_LANG", + }, + } + + app.Run(os.Args) +} +``` + +The `EnvVar` may also be given as a comma-delimited "cascade", where the first +environment variable that resolves is used as the default. + + +``` go +package main + +import ( + "os" + + "github.com/urfave/cli" +) + +func main() { + app := cli.NewApp() + + app.Flags = []cli.Flag { + cli.StringFlag{ + Name: "lang, l", + Value: "english", + Usage: "language for the greeting", + EnvVar: "LEGACY_COMPAT_LANG,APP_LANG,LANG", + }, + } + + app.Run(os.Args) +} +``` + +#### Values from alternate input sources (YAML, TOML, and others) + +There is a separate package altsrc that adds support for getting flag values +from other file input sources. + +Currently supported input source formats: +* YAML +* TOML + +In order to get values for a flag from an alternate input source the following +code would be added to wrap an existing cli.Flag like below: + +``` go + altsrc.NewIntFlag(cli.IntFlag{Name: "test"}) +``` + +Initialization must also occur for these flags. Below is an example initializing +getting data from a yaml file below. + +``` go + command.Before = altsrc.InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load")) +``` + +The code above will use the "load" string as a flag name to get the file name of +a yaml file from the cli.Context. It will then use that file name to initialize +the yaml input source for any flags that are defined on that command. As a note +the "load" flag used would also have to be defined on the command flags in order +for this code snipped to work. + +Currently only the aboved specified formats are supported but developers can +add support for other input sources by implementing the +altsrc.InputSourceContext for their given sources. + +Here is a more complete sample of a command using YAML support: + + +``` go +package notmain + +import ( + "fmt" + "os" + + "github.com/urfave/cli" + "github.com/urfave/cli/altsrc" +) + +func main() { + app := cli.NewApp() + + flags := []cli.Flag{ + altsrc.NewIntFlag(cli.IntFlag{Name: "test"}), + cli.StringFlag{Name: "load"}, + } + + app.Action = func(c *cli.Context) error { + fmt.Println("yaml ist rad") + return nil + } + + app.Before = altsrc.InitInputSourceWithContext(flags, altsrc.NewYamlSourceFromFlagFunc("load")) + app.Flags = flags + + app.Run(os.Args) +} +``` + +#### Precedence + +The precedence for flag value sources is as follows (highest to lowest): + +0. Command line flag value from user +0. Environment variable (if specified) +0. Configuration file (if specified) +0. Default defined on the flag + +### Subcommands + +Subcommands can be defined for a more git-like command line app. + + +```go +package main + +import ( + "fmt" + "os" + + "github.com/urfave/cli" +) + +func main() { + app := cli.NewApp() + + app.Commands = []cli.Command{ + { + Name: "add", + Aliases: []string{"a"}, + Usage: "add a task to the list", + Action: func(c *cli.Context) error { + fmt.Println("added task: ", c.Args().First()) + return nil + }, + }, + { + Name: "complete", + Aliases: []string{"c"}, + Usage: "complete a task on the list", + Action: func(c *cli.Context) error { + fmt.Println("completed task: ", c.Args().First()) + return nil + }, + }, + { + Name: "template", + Aliases: []string{"t"}, + Usage: "options for task templates", + Subcommands: []cli.Command{ + { + Name: "add", + Usage: "add a new template", + Action: func(c *cli.Context) error { + fmt.Println("new task template: ", c.Args().First()) + return nil + }, + }, + { + Name: "remove", + Usage: "remove an existing template", + Action: func(c *cli.Context) error { + fmt.Println("removed task template: ", c.Args().First()) + return nil + }, + }, + }, + }, + } + + app.Run(os.Args) +} +``` + +### Subcommands categories + +For additional organization in apps that have many subcommands, you can +associate a category for each command to group them together in the help +output. + +E.g. + +```go +package main + +import ( + "os" + + "github.com/urfave/cli" +) + +func main() { + app := cli.NewApp() + + app.Commands = []cli.Command{ + { + Name: "noop", + }, + { + Name: "add", + Category: "Template actions", + }, + { + Name: "remove", + Category: "Template actions", + }, + } + + app.Run(os.Args) +} +``` + +Will include: + +``` +COMMANDS: + noop + + Template actions: + add + remove +``` + +### Exit code + +Calling `App.Run` will not automatically call `os.Exit`, which means that by +default the exit code will "fall through" to being `0`. An explicit exit code +may be set by returning a non-nil error that fulfills `cli.ExitCoder`, *or* a +`cli.MultiError` that includes an error that fulfills `cli.ExitCoder`, e.g.: + +``` go +package main + +import ( + "os" + + "github.com/urfave/cli" +) + +func main() { + app := cli.NewApp() + app.Flags = []cli.Flag{ + cli.BoolTFlag{ + Name: "ginger-crouton", + Usage: "is it in the soup?", + }, + } + app.Action = func(ctx *cli.Context) error { + if !ctx.Bool("ginger-crouton") { + return cli.NewExitError("it is not in the soup", 86) + } + return nil + } + + app.Run(os.Args) +} +``` + +### Bash Completion + +You can enable completion commands by setting the `EnableBashCompletion` +flag on the `App` object. By default, this setting will only auto-complete to +show an app's subcommands, but you can write your own completion methods for +the App or its subcommands. + + +``` go +package main + +import ( + "fmt" + "os" + + "github.com/urfave/cli" +) + +func main() { + tasks := []string{"cook", "clean", "laundry", "eat", "sleep", "code"} + + app := cli.NewApp() + app.EnableBashCompletion = true + app.Commands = []cli.Command{ + { + Name: "complete", + Aliases: []string{"c"}, + Usage: "complete a task on the list", + Action: func(c *cli.Context) error { + fmt.Println("completed task: ", c.Args().First()) + return nil + }, + BashComplete: func(c *cli.Context) { + // This will complete if no args are passed + if c.NArg() > 0 { + return + } + for _, t := range tasks { + fmt.Println(t) + } + }, + }, + } + + app.Run(os.Args) +} +``` + +#### Enabling + +Source the `autocomplete/bash_autocomplete` file in your `.bashrc` file while +setting the `PROG` variable to the name of your program: + +`PROG=myprogram source /.../cli/autocomplete/bash_autocomplete` + +#### Distribution + +Copy `autocomplete/bash_autocomplete` into `/etc/bash_completion.d/` and rename +it to the name of the program you wish to add autocomplete support for (or +automatically install it there if you are distributing a package). Don't forget +to source the file to make it active in the current shell. + +``` +sudo cp src/bash_autocomplete /etc/bash_completion.d/ +source /etc/bash_completion.d/ +``` + +Alternatively, you can just document that users should source the generic +`autocomplete/bash_autocomplete` in their bash configuration with `$PROG` set +to the name of their program (as above). + +#### Customization + +The default bash completion flag (`--generate-bash-completion`) is defined as +`cli.BashCompletionFlag`, and may be redefined if desired, e.g.: + + +``` go +package main + +import ( + "os" + + "github.com/urfave/cli" +) + +func main() { + cli.BashCompletionFlag = cli.BoolFlag{ + Name: "compgen", + Hidden: true, + } + + app := cli.NewApp() + app.EnableBashCompletion = true + app.Commands = []cli.Command{ + { + Name: "wat", + }, + } + app.Run(os.Args) +} +``` + +### Generated Help Text + +The default help flag (`-h/--help`) is defined as `cli.HelpFlag` and is checked +by the cli internals in order to print generated help text for the app, command, +or subcommand, and break execution. + +#### Customization + +All of the help text generation may be customized, and at multiple levels. The +templates are exposed as variables `AppHelpTemplate`, `CommandHelpTemplate`, and +`SubcommandHelpTemplate` which may be reassigned or augmented, and full override +is possible by assigning a compatible func to the `cli.HelpPrinter` variable, +e.g.: + + +``` go +package main + +import ( + "fmt" + "io" + "os" + + "github.com/urfave/cli" +) + +func main() { + // EXAMPLE: Append to an existing template + cli.AppHelpTemplate = fmt.Sprintf(`%s + +WEBSITE: http://awesometown.example.com + +SUPPORT: support@awesometown.example.com + +`, cli.AppHelpTemplate) + + // EXAMPLE: Override a template + cli.AppHelpTemplate = `NAME: + {{.Name}} - {{.Usage}} +USAGE: + {{.HelpName}} {{if .VisibleFlags}}[global options]{{end}}{{if .Commands}} command [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}} + {{if len .Authors}} +AUTHOR: + {{range .Authors}}{{ . }}{{end}} + {{end}}{{if .Commands}} +COMMANDS: +{{range .Commands}}{{if not .HideHelp}} {{join .Names ", "}}{{ "\t"}}{{.Usage}}{{ "\n" }}{{end}}{{end}}{{end}}{{if .VisibleFlags}} +GLOBAL OPTIONS: + {{range .VisibleFlags}}{{.}} + {{end}}{{end}}{{if .Copyright }} +COPYRIGHT: + {{.Copyright}} + {{end}}{{if .Version}} +VERSION: + {{.Version}} + {{end}} +` + + // EXAMPLE: Replace the `HelpPrinter` func + cli.HelpPrinter = func(w io.Writer, templ string, data interface{}) { + fmt.Println("Ha HA. I pwnd the help!!1") + } + + cli.NewApp().Run(os.Args) +} +``` + +The default flag may be customized to something other than `-h/--help` by +setting `cli.HelpFlag`, e.g.: + + +``` go +package main + +import ( + "os" + + "github.com/urfave/cli" +) + +func main() { + cli.HelpFlag = cli.BoolFlag{ + Name: "halp, haaaaalp", + Usage: "HALP", + EnvVar: "SHOW_HALP,HALPPLZ", + } + + cli.NewApp().Run(os.Args) +} +``` + +### Version Flag + +The default version flag (`-v/--version`) is defined as `cli.VersionFlag`, which +is checked by the cli internals in order to print the `App.Version` via +`cli.VersionPrinter` and break execution. + +#### Customization + +The default flag may be customized to something other than `-v/--version` by +setting `cli.VersionFlag`, e.g.: + + +``` go +package main + +import ( + "os" + + "github.com/urfave/cli" +) + +func main() { + cli.VersionFlag = cli.BoolFlag{ + Name: "print-version, V", + Usage: "print only the version", + } + + app := cli.NewApp() + app.Name = "partay" + app.Version = "19.99.0" + app.Run(os.Args) +} +``` + +Alternatively, the version printer at `cli.VersionPrinter` may be overridden, e.g.: + + +``` go +package main + +import ( + "fmt" + "os" + + "github.com/urfave/cli" +) + +var ( + Revision = "fafafaf" +) + +func main() { + cli.VersionPrinter = func(c *cli.Context) { + fmt.Printf("version=%s revision=%s\n", c.App.Version, Revision) + } + + app := cli.NewApp() + app.Name = "partay" + app.Version = "19.99.0" + app.Run(os.Args) +} +``` + +#### Full API Example + +**Notice**: This is a contrived (functioning) example meant strictly for API +demonstration purposes. Use of one's imagination is encouraged. + + +``` go +package main + +import ( + "errors" + "flag" + "fmt" + "io" + "io/ioutil" + "os" + "time" + + "github.com/urfave/cli" +) + +func init() { + cli.AppHelpTemplate += "\nCUSTOMIZED: you bet ur muffins\n" + cli.CommandHelpTemplate += "\nYMMV\n" + cli.SubcommandHelpTemplate += "\nor something\n" + + cli.HelpFlag = cli.BoolFlag{Name: "halp"} + cli.BashCompletionFlag = cli.BoolFlag{Name: "compgen", Hidden: true} + cli.VersionFlag = cli.BoolFlag{Name: "print-version, V"} + + cli.HelpPrinter = func(w io.Writer, templ string, data interface{}) { + fmt.Fprintf(w, "best of luck to you\n") + } + cli.VersionPrinter = func(c *cli.Context) { + fmt.Fprintf(c.App.Writer, "version=%s\n", c.App.Version) + } + cli.OsExiter = func(c int) { + fmt.Fprintf(cli.ErrWriter, "refusing to exit %d\n", c) + } + cli.ErrWriter = ioutil.Discard + cli.FlagStringer = func(fl cli.Flag) string { + return fmt.Sprintf("\t\t%s", fl.GetName()) + } +} + +type hexWriter struct{} + +func (w *hexWriter) Write(p []byte) (int, error) { + for _, b := range p { + fmt.Printf("%x", b) + } + fmt.Printf("\n") + + return len(p), nil +} + +type genericType struct{ + s string +} + +func (g *genericType) Set(value string) error { + g.s = value + return nil +} + +func (g *genericType) String() string { + return g.s +} + +func main() { + app := cli.NewApp() + app.Name = "kənˈtrīv" + app.Version = "19.99.0" + app.Compiled = time.Now() + app.Authors = []cli.Author{ + cli.Author{ + Name: "Example Human", + Email: "human@example.com", + }, + } + app.Copyright = "(c) 1999 Serious Enterprise" + app.HelpName = "contrive" + app.Usage = "demonstrate available API" + app.UsageText = "contrive - demonstrating the available API" + app.ArgsUsage = "[args and such]" + app.Commands = []cli.Command{ + cli.Command{ + Name: "doo", + Aliases: []string{"do"}, + Category: "motion", + Usage: "do the doo", + UsageText: "doo - does the dooing", + Description: "no really, there is a lot of dooing to be done", + ArgsUsage: "[arrgh]", + Flags: []cli.Flag{ + cli.BoolFlag{Name: "forever, forevvarr"}, + }, + Subcommands: cli.Commands{ + cli.Command{ + Name: "wop", + Action: wopAction, + }, + }, + SkipFlagParsing: false, + HideHelp: false, + Hidden: false, + HelpName: "doo!", + BashComplete: func(c *cli.Context) { + fmt.Fprintf(c.App.Writer, "--better\n") + }, + Before: func(c *cli.Context) error { + fmt.Fprintf(c.App.Writer, "brace for impact\n") + return nil + }, + After: func(c *cli.Context) error { + fmt.Fprintf(c.App.Writer, "did we lose anyone?\n") + return nil + }, + Action: func(c *cli.Context) error { + c.Command.FullName() + c.Command.HasName("wop") + c.Command.Names() + c.Command.VisibleFlags() + fmt.Fprintf(c.App.Writer, "dodododododoodododddooooododododooo\n") + if c.Bool("forever") { + c.Command.Run(c) + } + return nil + }, + OnUsageError: func(c *cli.Context, err error, isSubcommand bool) error { + fmt.Fprintf(c.App.Writer, "for shame\n") + return err + }, + }, + } + app.Flags = []cli.Flag{ + cli.BoolFlag{Name: "fancy"}, + cli.BoolTFlag{Name: "fancier"}, + cli.DurationFlag{Name: "howlong, H", Value: time.Second * 3}, + cli.Float64Flag{Name: "howmuch"}, + cli.GenericFlag{Name: "wat", Value: &genericType{}}, + cli.Int64Flag{Name: "longdistance"}, + cli.Int64SliceFlag{Name: "intervals"}, + cli.IntFlag{Name: "distance"}, + cli.IntSliceFlag{Name: "times"}, + cli.StringFlag{Name: "dance-move, d"}, + cli.StringSliceFlag{Name: "names, N"}, + cli.UintFlag{Name: "age"}, + cli.Uint64Flag{Name: "bigage"}, + } + app.EnableBashCompletion = true + app.HideHelp = false + app.HideVersion = false + app.BashComplete = func(c *cli.Context) { + fmt.Fprintf(c.App.Writer, "lipstick\nkiss\nme\nlipstick\nringo\n") + } + app.Before = func(c *cli.Context) error { + fmt.Fprintf(c.App.Writer, "HEEEERE GOES\n") + return nil + } + app.After = func(c *cli.Context) error { + fmt.Fprintf(c.App.Writer, "Phew!\n") + return nil + } + app.CommandNotFound = func(c *cli.Context, command string) { + fmt.Fprintf(c.App.Writer, "Thar be no %q here.\n", command) + } + app.OnUsageError = func(c *cli.Context, err error, isSubcommand bool) error { + if isSubcommand { + return err + } + + fmt.Fprintf(c.App.Writer, "WRONG: %#v\n", err) + return nil + } + app.Action = func(c *cli.Context) error { + cli.DefaultAppComplete(c) + cli.HandleExitCoder(errors.New("not an exit coder, though")) + cli.ShowAppHelp(c) + cli.ShowCommandCompletions(c, "nope") + cli.ShowCommandHelp(c, "also-nope") + cli.ShowCompletions(c) + cli.ShowSubcommandHelp(c) + cli.ShowVersion(c) + + categories := c.App.Categories() + categories.AddCommand("sounds", cli.Command{ + Name: "bloop", + }) + + for _, category := range c.App.Categories() { + fmt.Fprintf(c.App.Writer, "%s\n", category.Name) + fmt.Fprintf(c.App.Writer, "%#v\n", category.Commands) + fmt.Fprintf(c.App.Writer, "%#v\n", category.VisibleCommands()) + } + + fmt.Printf("%#v\n", c.App.Command("doo")) + if c.Bool("infinite") { + c.App.Run([]string{"app", "doo", "wop"}) + } + + if c.Bool("forevar") { + c.App.RunAsSubcommand(c) + } + c.App.Setup() + fmt.Printf("%#v\n", c.App.VisibleCategories()) + fmt.Printf("%#v\n", c.App.VisibleCommands()) + fmt.Printf("%#v\n", c.App.VisibleFlags()) + + fmt.Printf("%#v\n", c.Args().First()) + if len(c.Args()) > 0 { + fmt.Printf("%#v\n", c.Args()[1]) + } + fmt.Printf("%#v\n", c.Args().Present()) + fmt.Printf("%#v\n", c.Args().Tail()) + + set := flag.NewFlagSet("contrive", 0) + nc := cli.NewContext(c.App, set, c) + + fmt.Printf("%#v\n", nc.Args()) + fmt.Printf("%#v\n", nc.Bool("nope")) + fmt.Printf("%#v\n", nc.BoolT("nerp")) + fmt.Printf("%#v\n", nc.Duration("howlong")) + fmt.Printf("%#v\n", nc.Float64("hay")) + fmt.Printf("%#v\n", nc.Generic("bloop")) + fmt.Printf("%#v\n", nc.Int64("bonk")) + fmt.Printf("%#v\n", nc.Int64Slice("burnks")) + fmt.Printf("%#v\n", nc.Int("bips")) + fmt.Printf("%#v\n", nc.IntSlice("blups")) + fmt.Printf("%#v\n", nc.String("snurt")) + fmt.Printf("%#v\n", nc.StringSlice("snurkles")) + fmt.Printf("%#v\n", nc.Uint("flub")) + fmt.Printf("%#v\n", nc.Uint64("florb")) + fmt.Printf("%#v\n", nc.GlobalBool("global-nope")) + fmt.Printf("%#v\n", nc.GlobalBoolT("global-nerp")) + fmt.Printf("%#v\n", nc.GlobalDuration("global-howlong")) + fmt.Printf("%#v\n", nc.GlobalFloat64("global-hay")) + fmt.Printf("%#v\n", nc.GlobalGeneric("global-bloop")) + fmt.Printf("%#v\n", nc.GlobalInt("global-bips")) + fmt.Printf("%#v\n", nc.GlobalIntSlice("global-blups")) + fmt.Printf("%#v\n", nc.GlobalString("global-snurt")) + fmt.Printf("%#v\n", nc.GlobalStringSlice("global-snurkles")) + + fmt.Printf("%#v\n", nc.FlagNames()) + fmt.Printf("%#v\n", nc.GlobalFlagNames()) + fmt.Printf("%#v\n", nc.GlobalIsSet("wat")) + fmt.Printf("%#v\n", nc.GlobalSet("wat", "nope")) + fmt.Printf("%#v\n", nc.NArg()) + fmt.Printf("%#v\n", nc.NumFlags()) + fmt.Printf("%#v\n", nc.Parent()) + + nc.Set("wat", "also-nope") + + ec := cli.NewExitError("ohwell", 86) + fmt.Fprintf(c.App.Writer, "%d", ec.ExitCode()) + fmt.Printf("made it!\n") + return ec + } + + if os.Getenv("HEXY") != "" { + app.Writer = &hexWriter{} + app.ErrWriter = &hexWriter{} + } + + app.Metadata = map[string]interface{}{ + "layers": "many", + "explicable": false, + "whatever-values": 19.99, + } + + app.Run(os.Args) +} + +func wopAction(c *cli.Context) error { + fmt.Fprintf(c.App.Writer, ":wave: over here, eh\n") + return nil +} +``` + +## Contribution Guidelines + +Feel free to put up a pull request to fix a bug or maybe add a feature. I will +give it a code review and make sure that it does not break backwards +compatibility. If I or any other collaborators agree that it is in line with +the vision of the project, we will work with you to get the code into +a mergeable state and merge it into the master branch. + +If you have contributed something significant to the project, we will most +likely add you as a collaborator. As a collaborator you are given the ability +to merge others pull requests. It is very important that new code does not +break existing code, so be careful about what code you do choose to merge. + +If you feel like you have contributed to the project but have not yet been +added as a collaborator, we probably forgot to add you, please open an issue. diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/urfave/cli/app.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/urfave/cli/app.go new file mode 100644 index 0000000000..60599b0465 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/urfave/cli/app.go @@ -0,0 +1,509 @@ +package cli + +import ( + "fmt" + "io" + "io/ioutil" + "os" + "path/filepath" + "sort" + "time" +) + +var ( + changeLogURL = "https://github.com/urfave/cli/blob/master/CHANGELOG.md" + appActionDeprecationURL = fmt.Sprintf("%s#deprecated-cli-app-action-signature", changeLogURL) + runAndExitOnErrorDeprecationURL = fmt.Sprintf("%s#deprecated-cli-app-runandexitonerror", changeLogURL) + + contactSysadmin = "This is an error in the application. Please contact the distributor of this application if this is not you." + + errInvalidActionType = NewExitError("ERROR invalid Action type. "+ + fmt.Sprintf("Must be `func(*Context`)` or `func(*Context) error). %s", contactSysadmin)+ + fmt.Sprintf("See %s", appActionDeprecationURL), 2) +) + +// App is the main structure of a cli application. It is recommended that +// an app be created with the cli.NewApp() function +type App struct { + // The name of the program. Defaults to path.Base(os.Args[0]) + Name string + // Full name of command for help, defaults to Name + HelpName string + // Description of the program. + Usage string + // Text to override the USAGE section of help + UsageText string + // Description of the program argument format. + ArgsUsage string + // Version of the program + Version string + // Description of the program + Description string + // List of commands to execute + Commands []Command + // List of flags to parse + Flags []Flag + // Boolean to enable bash completion commands + EnableBashCompletion bool + // Boolean to hide built-in help command + HideHelp bool + // Boolean to hide built-in version flag and the VERSION section of help + HideVersion bool + // Populate on app startup, only gettable through method Categories() + categories CommandCategories + // An action to execute when the bash-completion flag is set + BashComplete BashCompleteFunc + // An action to execute before any subcommands are run, but after the context is ready + // If a non-nil error is returned, no subcommands are run + Before BeforeFunc + // An action to execute after any subcommands are run, but after the subcommand has finished + // It is run even if Action() panics + After AfterFunc + + // The action to execute when no subcommands are specified + // Expects a `cli.ActionFunc` but will accept the *deprecated* signature of `func(*cli.Context) {}` + // *Note*: support for the deprecated `Action` signature will be removed in a future version + Action interface{} + + // Execute this function if the proper command cannot be found + CommandNotFound CommandNotFoundFunc + // Execute this function if an usage error occurs + OnUsageError OnUsageErrorFunc + // Compilation date + Compiled time.Time + // List of all authors who contributed + Authors []Author + // Copyright of the binary if any + Copyright string + // Name of Author (Note: Use App.Authors, this is deprecated) + Author string + // Email of Author (Note: Use App.Authors, this is deprecated) + Email string + // Writer writer to write output to + Writer io.Writer + // ErrWriter writes error output + ErrWriter io.Writer + // Execute this function to handle ExitErrors. If not provided, HandleExitCoder is provided to + // function as a default, so this is optional. + ExitErrHandler ExitErrHandlerFunc + // Other custom info + Metadata map[string]interface{} + // Carries a function which returns app specific info. + ExtraInfo func() map[string]string + // CustomAppHelpTemplate the text template for app help topic. + // cli.go uses text/template to render templates. You can + // render custom help text by setting this variable. + CustomAppHelpTemplate string + + didSetup bool +} + +// Tries to find out when this binary was compiled. +// Returns the current time if it fails to find it. +func compileTime() time.Time { + info, err := os.Stat(os.Args[0]) + if err != nil { + return time.Now() + } + return info.ModTime() +} + +// NewApp creates a new cli Application with some reasonable defaults for Name, +// Usage, Version and Action. +func NewApp() *App { + return &App{ + Name: filepath.Base(os.Args[0]), + HelpName: filepath.Base(os.Args[0]), + Usage: "A new cli application", + UsageText: "", + Version: "0.0.0", + BashComplete: DefaultAppComplete, + Action: helpCommand.Action, + Compiled: compileTime(), + Writer: os.Stdout, + } +} + +// Setup runs initialization code to ensure all data structures are ready for +// `Run` or inspection prior to `Run`. It is internally called by `Run`, but +// will return early if setup has already happened. +func (a *App) Setup() { + if a.didSetup { + return + } + + a.didSetup = true + + if a.Author != "" || a.Email != "" { + a.Authors = append(a.Authors, Author{Name: a.Author, Email: a.Email}) + } + + newCmds := []Command{} + for _, c := range a.Commands { + if c.HelpName == "" { + c.HelpName = fmt.Sprintf("%s %s", a.HelpName, c.Name) + } + newCmds = append(newCmds, c) + } + a.Commands = newCmds + + if a.Command(helpCommand.Name) == nil && !a.HideHelp { + a.Commands = append(a.Commands, helpCommand) + if (HelpFlag != BoolFlag{}) { + a.appendFlag(HelpFlag) + } + } + + if !a.HideVersion { + a.appendFlag(VersionFlag) + } + + a.categories = CommandCategories{} + for _, command := range a.Commands { + a.categories = a.categories.AddCommand(command.Category, command) + } + sort.Sort(a.categories) + + if a.Metadata == nil { + a.Metadata = make(map[string]interface{}) + } + + if a.Writer == nil { + a.Writer = os.Stdout + } +} + +// Run is the entry point to the cli app. Parses the arguments slice and routes +// to the proper flag/args combination +func (a *App) Run(arguments []string) (err error) { + a.Setup() + + // handle the completion flag separately from the flagset since + // completion could be attempted after a flag, but before its value was put + // on the command line. this causes the flagset to interpret the completion + // flag name as the value of the flag before it which is undesirable + // note that we can only do this because the shell autocomplete function + // always appends the completion flag at the end of the command + shellComplete, arguments := checkShellCompleteFlag(a, arguments) + + // parse flags + set, err := flagSet(a.Name, a.Flags) + if err != nil { + return err + } + + set.SetOutput(ioutil.Discard) + err = set.Parse(arguments[1:]) + nerr := normalizeFlags(a.Flags, set) + context := NewContext(a, set, nil) + if nerr != nil { + fmt.Fprintln(a.Writer, nerr) + ShowAppHelp(context) + return nerr + } + context.shellComplete = shellComplete + + if checkCompletions(context) { + return nil + } + + if err != nil { + if a.OnUsageError != nil { + err := a.OnUsageError(context, err, false) + a.handleExitCoder(context, err) + return err + } + fmt.Fprintf(a.Writer, "%s %s\n\n", "Incorrect Usage.", err.Error()) + ShowAppHelp(context) + return err + } + + if !a.HideHelp && checkHelp(context) { + ShowAppHelp(context) + return nil + } + + if !a.HideVersion && checkVersion(context) { + ShowVersion(context) + return nil + } + + if a.After != nil { + defer func() { + if afterErr := a.After(context); afterErr != nil { + if err != nil { + err = NewMultiError(err, afterErr) + } else { + err = afterErr + } + } + }() + } + + if a.Before != nil { + beforeErr := a.Before(context) + if beforeErr != nil { + fmt.Fprintf(a.Writer, "%v\n\n", beforeErr) + ShowAppHelp(context) + a.handleExitCoder(context, beforeErr) + err = beforeErr + return err + } + } + + args := context.Args() + if args.Present() { + name := args.First() + c := a.Command(name) + if c != nil { + return c.Run(context) + } + } + + if a.Action == nil { + a.Action = helpCommand.Action + } + + // Run default Action + err = HandleAction(a.Action, context) + + a.handleExitCoder(context, err) + return err +} + +// RunAndExitOnError calls .Run() and exits non-zero if an error was returned +// +// Deprecated: instead you should return an error that fulfills cli.ExitCoder +// to cli.App.Run. This will cause the application to exit with the given eror +// code in the cli.ExitCoder +func (a *App) RunAndExitOnError() { + if err := a.Run(os.Args); err != nil { + fmt.Fprintln(a.errWriter(), err) + OsExiter(1) + } +} + +// RunAsSubcommand invokes the subcommand given the context, parses ctx.Args() to +// generate command-specific flags +func (a *App) RunAsSubcommand(ctx *Context) (err error) { + // append help to commands + if len(a.Commands) > 0 { + if a.Command(helpCommand.Name) == nil && !a.HideHelp { + a.Commands = append(a.Commands, helpCommand) + if (HelpFlag != BoolFlag{}) { + a.appendFlag(HelpFlag) + } + } + } + + newCmds := []Command{} + for _, c := range a.Commands { + if c.HelpName == "" { + c.HelpName = fmt.Sprintf("%s %s", a.HelpName, c.Name) + } + newCmds = append(newCmds, c) + } + a.Commands = newCmds + + // parse flags + set, err := flagSet(a.Name, a.Flags) + if err != nil { + return err + } + + set.SetOutput(ioutil.Discard) + err = set.Parse(ctx.Args().Tail()) + nerr := normalizeFlags(a.Flags, set) + context := NewContext(a, set, ctx) + + if nerr != nil { + fmt.Fprintln(a.Writer, nerr) + fmt.Fprintln(a.Writer) + if len(a.Commands) > 0 { + ShowSubcommandHelp(context) + } else { + ShowCommandHelp(ctx, context.Args().First()) + } + return nerr + } + + if checkCompletions(context) { + return nil + } + + if err != nil { + if a.OnUsageError != nil { + err = a.OnUsageError(context, err, true) + a.handleExitCoder(context, err) + return err + } + fmt.Fprintf(a.Writer, "%s %s\n\n", "Incorrect Usage.", err.Error()) + ShowSubcommandHelp(context) + return err + } + + if len(a.Commands) > 0 { + if checkSubcommandHelp(context) { + return nil + } + } else { + if checkCommandHelp(ctx, context.Args().First()) { + return nil + } + } + + if a.After != nil { + defer func() { + afterErr := a.After(context) + if afterErr != nil { + a.handleExitCoder(context, err) + if err != nil { + err = NewMultiError(err, afterErr) + } else { + err = afterErr + } + } + }() + } + + if a.Before != nil { + beforeErr := a.Before(context) + if beforeErr != nil { + a.handleExitCoder(context, beforeErr) + err = beforeErr + return err + } + } + + args := context.Args() + if args.Present() { + name := args.First() + c := a.Command(name) + if c != nil { + return c.Run(context) + } + } + + // Run default Action + err = HandleAction(a.Action, context) + + a.handleExitCoder(context, err) + return err +} + +// Command returns the named command on App. Returns nil if the command does not exist +func (a *App) Command(name string) *Command { + for _, c := range a.Commands { + if c.HasName(name) { + return &c + } + } + + return nil +} + +// Categories returns a slice containing all the categories with the commands they contain +func (a *App) Categories() CommandCategories { + return a.categories +} + +// VisibleCategories returns a slice of categories and commands that are +// Hidden=false +func (a *App) VisibleCategories() []*CommandCategory { + ret := []*CommandCategory{} + for _, category := range a.categories { + if visible := func() *CommandCategory { + for _, command := range category.Commands { + if !command.Hidden { + return category + } + } + return nil + }(); visible != nil { + ret = append(ret, visible) + } + } + return ret +} + +// VisibleCommands returns a slice of the Commands with Hidden=false +func (a *App) VisibleCommands() []Command { + ret := []Command{} + for _, command := range a.Commands { + if !command.Hidden { + ret = append(ret, command) + } + } + return ret +} + +// VisibleFlags returns a slice of the Flags with Hidden=false +func (a *App) VisibleFlags() []Flag { + return visibleFlags(a.Flags) +} + +func (a *App) hasFlag(flag Flag) bool { + for _, f := range a.Flags { + if flag == f { + return true + } + } + + return false +} + +func (a *App) errWriter() io.Writer { + + // When the app ErrWriter is nil use the package level one. + if a.ErrWriter == nil { + return ErrWriter + } + + return a.ErrWriter +} + +func (a *App) appendFlag(flag Flag) { + if !a.hasFlag(flag) { + a.Flags = append(a.Flags, flag) + } +} + +func (a *App) handleExitCoder(context *Context, err error) { + if a.ExitErrHandler != nil { + a.ExitErrHandler(context, err) + } else { + HandleExitCoder(err) + } +} + +// Author represents someone who has contributed to a cli project. +type Author struct { + Name string // The Authors name + Email string // The Authors email +} + +// String makes Author comply to the Stringer interface, to allow an easy print in the templating process +func (a Author) String() string { + e := "" + if a.Email != "" { + e = " <" + a.Email + ">" + } + + return fmt.Sprintf("%v%v", a.Name, e) +} + +// HandleAction attempts to figure out which Action signature was used. If +// it's an ActionFunc or a func with the legacy signature for Action, the func +// is run! +func HandleAction(action interface{}, context *Context) (err error) { + if a, ok := action.(ActionFunc); ok { + return a(context) + } else if a, ok := action.(func(*Context) error); ok { + return a(context) + } else if a, ok := action.(func(*Context)); ok { // deprecated function signature + a(context) + return nil + } + + return errInvalidActionType +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/urfave/cli/category.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/urfave/cli/category.go new file mode 100644 index 0000000000..1a6055023e --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/urfave/cli/category.go @@ -0,0 +1,44 @@ +package cli + +// CommandCategories is a slice of *CommandCategory. +type CommandCategories []*CommandCategory + +// CommandCategory is a category containing commands. +type CommandCategory struct { + Name string + Commands Commands +} + +func (c CommandCategories) Less(i, j int) bool { + return c[i].Name < c[j].Name +} + +func (c CommandCategories) Len() int { + return len(c) +} + +func (c CommandCategories) Swap(i, j int) { + c[i], c[j] = c[j], c[i] +} + +// AddCommand adds a command to a category. +func (c CommandCategories) AddCommand(category string, command Command) CommandCategories { + for _, commandCategory := range c { + if commandCategory.Name == category { + commandCategory.Commands = append(commandCategory.Commands, command) + return c + } + } + return append(c, &CommandCategory{Name: category, Commands: []Command{command}}) +} + +// VisibleCommands returns a slice of the Commands with Hidden=false +func (c *CommandCategory) VisibleCommands() []Command { + ret := []Command{} + for _, command := range c.Commands { + if !command.Hidden { + ret = append(ret, command) + } + } + return ret +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/urfave/cli/cli.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/urfave/cli/cli.go new file mode 100644 index 0000000000..90c07eb8ef --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/urfave/cli/cli.go @@ -0,0 +1,22 @@ +// Package cli provides a minimal framework for creating and organizing command line +// Go applications. cli is designed to be easy to understand and write, the most simple +// cli application can be written as follows: +// func main() { +// cli.NewApp().Run(os.Args) +// } +// +// Of course this application does not do much, so let's make this an actual application: +// func main() { +// app := cli.NewApp() +// app.Name = "greet" +// app.Usage = "say a greeting" +// app.Action = func(c *cli.Context) error { +// println("Greetings") +// return nil +// } +// +// app.Run(os.Args) +// } +package cli + +//go:generate python ./generate-flag-types cli -i flag-types.json -o flag_generated.go diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/urfave/cli/command.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/urfave/cli/command.go new file mode 100644 index 0000000000..502fc9f301 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/urfave/cli/command.go @@ -0,0 +1,304 @@ +package cli + +import ( + "fmt" + "io/ioutil" + "sort" + "strings" +) + +// Command is a subcommand for a cli.App. +type Command struct { + // The name of the command + Name string + // short name of the command. Typically one character (deprecated, use `Aliases`) + ShortName string + // A list of aliases for the command + Aliases []string + // A short description of the usage of this command + Usage string + // Custom text to show on USAGE section of help + UsageText string + // A longer explanation of how the command works + Description string + // A short description of the arguments of this command + ArgsUsage string + // The category the command is part of + Category string + // The function to call when checking for bash command completions + BashComplete BashCompleteFunc + // An action to execute before any sub-subcommands are run, but after the context is ready + // If a non-nil error is returned, no sub-subcommands are run + Before BeforeFunc + // An action to execute after any subcommands are run, but after the subcommand has finished + // It is run even if Action() panics + After AfterFunc + // The function to call when this command is invoked + Action interface{} + // TODO: replace `Action: interface{}` with `Action: ActionFunc` once some kind + // of deprecation period has passed, maybe? + + // Execute this function if a usage error occurs. + OnUsageError OnUsageErrorFunc + // List of child commands + Subcommands Commands + // List of flags to parse + Flags []Flag + // Treat all flags as normal arguments if true + SkipFlagParsing bool + // Skip argument reordering which attempts to move flags before arguments, + // but only works if all flags appear after all arguments. This behavior was + // removed n version 2 since it only works under specific conditions so we + // backport here by exposing it as an option for compatibility. + SkipArgReorder bool + // Boolean to hide built-in help command + HideHelp bool + // Boolean to hide this command from help or completion + Hidden bool + + // Full name of command for help, defaults to full command name, including parent commands. + HelpName string + commandNamePath []string + + // CustomHelpTemplate the text template for the command help topic. + // cli.go uses text/template to render templates. You can + // render custom help text by setting this variable. + CustomHelpTemplate string +} + +type CommandsByName []Command + +func (c CommandsByName) Len() int { + return len(c) +} + +func (c CommandsByName) Less(i, j int) bool { + return c[i].Name < c[j].Name +} + +func (c CommandsByName) Swap(i, j int) { + c[i], c[j] = c[j], c[i] +} + +// FullName returns the full name of the command. +// For subcommands this ensures that parent commands are part of the command path +func (c Command) FullName() string { + if c.commandNamePath == nil { + return c.Name + } + return strings.Join(c.commandNamePath, " ") +} + +// Commands is a slice of Command +type Commands []Command + +// Run invokes the command given the context, parses ctx.Args() to generate command-specific flags +func (c Command) Run(ctx *Context) (err error) { + if len(c.Subcommands) > 0 { + return c.startApp(ctx) + } + + if !c.HideHelp && (HelpFlag != BoolFlag{}) { + // append help to flags + c.Flags = append( + c.Flags, + HelpFlag, + ) + } + + set, err := flagSet(c.Name, c.Flags) + if err != nil { + return err + } + set.SetOutput(ioutil.Discard) + + if c.SkipFlagParsing { + err = set.Parse(append([]string{"--"}, ctx.Args().Tail()...)) + } else if !c.SkipArgReorder { + firstFlagIndex := -1 + terminatorIndex := -1 + for index, arg := range ctx.Args() { + if arg == "--" { + terminatorIndex = index + break + } else if arg == "-" { + // Do nothing. A dash alone is not really a flag. + continue + } else if strings.HasPrefix(arg, "-") && firstFlagIndex == -1 { + firstFlagIndex = index + } + } + + if firstFlagIndex > -1 { + args := ctx.Args() + regularArgs := make([]string, len(args[1:firstFlagIndex])) + copy(regularArgs, args[1:firstFlagIndex]) + + var flagArgs []string + if terminatorIndex > -1 { + flagArgs = args[firstFlagIndex:terminatorIndex] + regularArgs = append(regularArgs, args[terminatorIndex:]...) + } else { + flagArgs = args[firstFlagIndex:] + } + + err = set.Parse(append(flagArgs, regularArgs...)) + } else { + err = set.Parse(ctx.Args().Tail()) + } + } else { + err = set.Parse(ctx.Args().Tail()) + } + + nerr := normalizeFlags(c.Flags, set) + if nerr != nil { + fmt.Fprintln(ctx.App.Writer, nerr) + fmt.Fprintln(ctx.App.Writer) + ShowCommandHelp(ctx, c.Name) + return nerr + } + + context := NewContext(ctx.App, set, ctx) + context.Command = c + if checkCommandCompletions(context, c.Name) { + return nil + } + + if err != nil { + if c.OnUsageError != nil { + err := c.OnUsageError(context, err, false) + context.App.handleExitCoder(context, err) + return err + } + fmt.Fprintln(context.App.Writer, "Incorrect Usage:", err.Error()) + fmt.Fprintln(context.App.Writer) + ShowCommandHelp(context, c.Name) + return err + } + + if checkCommandHelp(context, c.Name) { + return nil + } + + if c.After != nil { + defer func() { + afterErr := c.After(context) + if afterErr != nil { + context.App.handleExitCoder(context, err) + if err != nil { + err = NewMultiError(err, afterErr) + } else { + err = afterErr + } + } + }() + } + + if c.Before != nil { + err = c.Before(context) + if err != nil { + ShowCommandHelp(context, c.Name) + context.App.handleExitCoder(context, err) + return err + } + } + + if c.Action == nil { + c.Action = helpSubcommand.Action + } + + err = HandleAction(c.Action, context) + + if err != nil { + context.App.handleExitCoder(context, err) + } + return err +} + +// Names returns the names including short names and aliases. +func (c Command) Names() []string { + names := []string{c.Name} + + if c.ShortName != "" { + names = append(names, c.ShortName) + } + + return append(names, c.Aliases...) +} + +// HasName returns true if Command.Name or Command.ShortName matches given name +func (c Command) HasName(name string) bool { + for _, n := range c.Names() { + if n == name { + return true + } + } + return false +} + +func (c Command) startApp(ctx *Context) error { + app := NewApp() + app.Metadata = ctx.App.Metadata + // set the name and usage + app.Name = fmt.Sprintf("%s %s", ctx.App.Name, c.Name) + if c.HelpName == "" { + app.HelpName = c.HelpName + } else { + app.HelpName = app.Name + } + + app.Usage = c.Usage + app.Description = c.Description + app.ArgsUsage = c.ArgsUsage + + // set CommandNotFound + app.CommandNotFound = ctx.App.CommandNotFound + app.CustomAppHelpTemplate = c.CustomHelpTemplate + + // set the flags and commands + app.Commands = c.Subcommands + app.Flags = c.Flags + app.HideHelp = c.HideHelp + + app.Version = ctx.App.Version + app.HideVersion = ctx.App.HideVersion + app.Compiled = ctx.App.Compiled + app.Author = ctx.App.Author + app.Email = ctx.App.Email + app.Writer = ctx.App.Writer + app.ErrWriter = ctx.App.ErrWriter + + app.categories = CommandCategories{} + for _, command := range c.Subcommands { + app.categories = app.categories.AddCommand(command.Category, command) + } + + sort.Sort(app.categories) + + // bash completion + app.EnableBashCompletion = ctx.App.EnableBashCompletion + if c.BashComplete != nil { + app.BashComplete = c.BashComplete + } + + // set the actions + app.Before = c.Before + app.After = c.After + if c.Action != nil { + app.Action = c.Action + } else { + app.Action = helpSubcommand.Action + } + app.OnUsageError = c.OnUsageError + + for index, cc := range app.Commands { + app.Commands[index].commandNamePath = []string{c.Name, cc.Name} + } + + return app.RunAsSubcommand(ctx) +} + +// VisibleFlags returns a slice of the Flags with Hidden=false +func (c Command) VisibleFlags() []Flag { + return visibleFlags(c.Flags) +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/urfave/cli/context.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/urfave/cli/context.go new file mode 100644 index 0000000000..012b9b5869 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/urfave/cli/context.go @@ -0,0 +1,278 @@ +package cli + +import ( + "errors" + "flag" + "reflect" + "strings" + "syscall" +) + +// Context is a type that is passed through to +// each Handler action in a cli application. Context +// can be used to retrieve context-specific Args and +// parsed command-line options. +type Context struct { + App *App + Command Command + shellComplete bool + flagSet *flag.FlagSet + setFlags map[string]bool + parentContext *Context +} + +// NewContext creates a new context. For use in when invoking an App or Command action. +func NewContext(app *App, set *flag.FlagSet, parentCtx *Context) *Context { + c := &Context{App: app, flagSet: set, parentContext: parentCtx} + + if parentCtx != nil { + c.shellComplete = parentCtx.shellComplete + } + + return c +} + +// NumFlags returns the number of flags set +func (c *Context) NumFlags() int { + return c.flagSet.NFlag() +} + +// Set sets a context flag to a value. +func (c *Context) Set(name, value string) error { + c.setFlags = nil + return c.flagSet.Set(name, value) +} + +// GlobalSet sets a context flag to a value on the global flagset +func (c *Context) GlobalSet(name, value string) error { + globalContext(c).setFlags = nil + return globalContext(c).flagSet.Set(name, value) +} + +// IsSet determines if the flag was actually set +func (c *Context) IsSet(name string) bool { + if c.setFlags == nil { + c.setFlags = make(map[string]bool) + + c.flagSet.Visit(func(f *flag.Flag) { + c.setFlags[f.Name] = true + }) + + c.flagSet.VisitAll(func(f *flag.Flag) { + if _, ok := c.setFlags[f.Name]; ok { + return + } + c.setFlags[f.Name] = false + }) + + // XXX hack to support IsSet for flags with EnvVar + // + // There isn't an easy way to do this with the current implementation since + // whether a flag was set via an environment variable is very difficult to + // determine here. Instead, we intend to introduce a backwards incompatible + // change in version 2 to add `IsSet` to the Flag interface to push the + // responsibility closer to where the information required to determine + // whether a flag is set by non-standard means such as environment + // variables is available. + // + // See https://github.com/urfave/cli/issues/294 for additional discussion + flags := c.Command.Flags + if c.Command.Name == "" { // cannot == Command{} since it contains slice types + if c.App != nil { + flags = c.App.Flags + } + } + for _, f := range flags { + eachName(f.GetName(), func(name string) { + if isSet, ok := c.setFlags[name]; isSet || !ok { + return + } + + val := reflect.ValueOf(f) + if val.Kind() == reflect.Ptr { + val = val.Elem() + } + + envVarValue := val.FieldByName("EnvVar") + if !envVarValue.IsValid() { + return + } + + eachName(envVarValue.String(), func(envVar string) { + envVar = strings.TrimSpace(envVar) + if _, ok := syscall.Getenv(envVar); ok { + c.setFlags[name] = true + return + } + }) + }) + } + } + + return c.setFlags[name] +} + +// GlobalIsSet determines if the global flag was actually set +func (c *Context) GlobalIsSet(name string) bool { + ctx := c + if ctx.parentContext != nil { + ctx = ctx.parentContext + } + + for ; ctx != nil; ctx = ctx.parentContext { + if ctx.IsSet(name) { + return true + } + } + return false +} + +// FlagNames returns a slice of flag names used in this context. +func (c *Context) FlagNames() (names []string) { + for _, flag := range c.Command.Flags { + name := strings.Split(flag.GetName(), ",")[0] + if name == "help" { + continue + } + names = append(names, name) + } + return +} + +// GlobalFlagNames returns a slice of global flag names used by the app. +func (c *Context) GlobalFlagNames() (names []string) { + for _, flag := range c.App.Flags { + name := strings.Split(flag.GetName(), ",")[0] + if name == "help" || name == "version" { + continue + } + names = append(names, name) + } + return +} + +// Parent returns the parent context, if any +func (c *Context) Parent() *Context { + return c.parentContext +} + +// value returns the value of the flag coressponding to `name` +func (c *Context) value(name string) interface{} { + return c.flagSet.Lookup(name).Value.(flag.Getter).Get() +} + +// Args contains apps console arguments +type Args []string + +// Args returns the command line arguments associated with the context. +func (c *Context) Args() Args { + args := Args(c.flagSet.Args()) + return args +} + +// NArg returns the number of the command line arguments. +func (c *Context) NArg() int { + return len(c.Args()) +} + +// Get returns the nth argument, or else a blank string +func (a Args) Get(n int) string { + if len(a) > n { + return a[n] + } + return "" +} + +// First returns the first argument, or else a blank string +func (a Args) First() string { + return a.Get(0) +} + +// Tail returns the rest of the arguments (not the first one) +// or else an empty string slice +func (a Args) Tail() []string { + if len(a) >= 2 { + return []string(a)[1:] + } + return []string{} +} + +// Present checks if there are any arguments present +func (a Args) Present() bool { + return len(a) != 0 +} + +// Swap swaps arguments at the given indexes +func (a Args) Swap(from, to int) error { + if from >= len(a) || to >= len(a) { + return errors.New("index out of range") + } + a[from], a[to] = a[to], a[from] + return nil +} + +func globalContext(ctx *Context) *Context { + if ctx == nil { + return nil + } + + for { + if ctx.parentContext == nil { + return ctx + } + ctx = ctx.parentContext + } +} + +func lookupGlobalFlagSet(name string, ctx *Context) *flag.FlagSet { + if ctx.parentContext != nil { + ctx = ctx.parentContext + } + for ; ctx != nil; ctx = ctx.parentContext { + if f := ctx.flagSet.Lookup(name); f != nil { + return ctx.flagSet + } + } + return nil +} + +func copyFlag(name string, ff *flag.Flag, set *flag.FlagSet) { + switch ff.Value.(type) { + case *StringSlice: + default: + set.Set(name, ff.Value.String()) + } +} + +func normalizeFlags(flags []Flag, set *flag.FlagSet) error { + visited := make(map[string]bool) + set.Visit(func(f *flag.Flag) { + visited[f.Name] = true + }) + for _, f := range flags { + parts := strings.Split(f.GetName(), ",") + if len(parts) == 1 { + continue + } + var ff *flag.Flag + for _, name := range parts { + name = strings.Trim(name, " ") + if visited[name] { + if ff != nil { + return errors.New("Cannot use two forms of the same flag: " + name + " " + ff.Name) + } + ff = set.Lookup(name) + } + } + if ff == nil { + continue + } + for _, name := range parts { + name = strings.Trim(name, " ") + if !visited[name] { + copyFlag(name, ff, set) + } + } + } + return nil +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/urfave/cli/errors.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/urfave/cli/errors.go new file mode 100644 index 0000000000..562b2953cf --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/urfave/cli/errors.go @@ -0,0 +1,115 @@ +package cli + +import ( + "fmt" + "io" + "os" + "strings" +) + +// OsExiter is the function used when the app exits. If not set defaults to os.Exit. +var OsExiter = os.Exit + +// ErrWriter is used to write errors to the user. This can be anything +// implementing the io.Writer interface and defaults to os.Stderr. +var ErrWriter io.Writer = os.Stderr + +// MultiError is an error that wraps multiple errors. +type MultiError struct { + Errors []error +} + +// NewMultiError creates a new MultiError. Pass in one or more errors. +func NewMultiError(err ...error) MultiError { + return MultiError{Errors: err} +} + +// Error implements the error interface. +func (m MultiError) Error() string { + errs := make([]string, len(m.Errors)) + for i, err := range m.Errors { + errs[i] = err.Error() + } + + return strings.Join(errs, "\n") +} + +type ErrorFormatter interface { + Format(s fmt.State, verb rune) +} + +// ExitCoder is the interface checked by `App` and `Command` for a custom exit +// code +type ExitCoder interface { + error + ExitCode() int +} + +// ExitError fulfills both the builtin `error` interface and `ExitCoder` +type ExitError struct { + exitCode int + message interface{} +} + +// NewExitError makes a new *ExitError +func NewExitError(message interface{}, exitCode int) *ExitError { + return &ExitError{ + exitCode: exitCode, + message: message, + } +} + +// Error returns the string message, fulfilling the interface required by +// `error` +func (ee *ExitError) Error() string { + return fmt.Sprintf("%v", ee.message) +} + +// ExitCode returns the exit code, fulfilling the interface required by +// `ExitCoder` +func (ee *ExitError) ExitCode() int { + return ee.exitCode +} + +// HandleExitCoder checks if the error fulfills the ExitCoder interface, and if +// so prints the error to stderr (if it is non-empty) and calls OsExiter with the +// given exit code. If the given error is a MultiError, then this func is +// called on all members of the Errors slice and calls OsExiter with the last exit code. +func HandleExitCoder(err error) { + if err == nil { + return + } + + if exitErr, ok := err.(ExitCoder); ok { + if err.Error() != "" { + if _, ok := exitErr.(ErrorFormatter); ok { + fmt.Fprintf(ErrWriter, "%+v\n", err) + } else { + fmt.Fprintln(ErrWriter, err) + } + } + OsExiter(exitErr.ExitCode()) + return + } + + if multiErr, ok := err.(MultiError); ok { + code := handleMultiError(multiErr) + OsExiter(code) + return + } +} + +func handleMultiError(multiErr MultiError) int { + code := 1 + for _, merr := range multiErr.Errors { + if multiErr2, ok := merr.(MultiError); ok { + code = handleMultiError(multiErr2) + } else { + fmt.Fprintln(ErrWriter, merr) + if exitErr, ok := merr.(ExitCoder); ok { + code = exitErr.ExitCode() + } + } + } + return code +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/urfave/cli/flag.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/urfave/cli/flag.go new file mode 100644 index 0000000000..b17f5b9b6f --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/urfave/cli/flag.go @@ -0,0 +1,807 @@ +package cli + +import ( + "flag" + "fmt" + "reflect" + "runtime" + "strconv" + "strings" + "syscall" + "time" +) + +const defaultPlaceholder = "value" + +// BashCompletionFlag enables bash-completion for all commands and subcommands +var BashCompletionFlag Flag = BoolFlag{ + Name: "generate-bash-completion", + Hidden: true, +} + +// VersionFlag prints the version for the application +var VersionFlag Flag = BoolFlag{ + Name: "version, v", + Usage: "print the version", +} + +// HelpFlag prints the help for all commands and subcommands +// Set to the zero value (BoolFlag{}) to disable flag -- keeps subcommand +// unless HideHelp is set to true) +var HelpFlag Flag = BoolFlag{ + Name: "help, h", + Usage: "show help", +} + +// FlagStringer converts a flag definition to a string. This is used by help +// to display a flag. +var FlagStringer FlagStringFunc = stringifyFlag + +// FlagNamePrefixer converts a full flag name and its placeholder into the help +// message flag prefix. This is used by the default FlagStringer. +var FlagNamePrefixer FlagNamePrefixFunc = prefixedNames + +// FlagEnvHinter annotates flag help message with the environment variable +// details. This is used by the default FlagStringer. +var FlagEnvHinter FlagEnvHintFunc = withEnvHint + +// FlagsByName is a slice of Flag. +type FlagsByName []Flag + +func (f FlagsByName) Len() int { + return len(f) +} + +func (f FlagsByName) Less(i, j int) bool { + return f[i].GetName() < f[j].GetName() +} + +func (f FlagsByName) Swap(i, j int) { + f[i], f[j] = f[j], f[i] +} + +// Flag is a common interface related to parsing flags in cli. +// For more advanced flag parsing techniques, it is recommended that +// this interface be implemented. +type Flag interface { + fmt.Stringer + // Apply Flag settings to the given flag set + Apply(*flag.FlagSet) + GetName() string +} + +// errorableFlag is an interface that allows us to return errors during apply +// it allows flags defined in this library to return errors in a fashion backwards compatible +// TODO remove in v2 and modify the existing Flag interface to return errors +type errorableFlag interface { + Flag + + ApplyWithError(*flag.FlagSet) error +} + +func flagSet(name string, flags []Flag) (*flag.FlagSet, error) { + set := flag.NewFlagSet(name, flag.ContinueOnError) + + for _, f := range flags { + //TODO remove in v2 when errorableFlag is removed + if ef, ok := f.(errorableFlag); ok { + if err := ef.ApplyWithError(set); err != nil { + return nil, err + } + } else { + f.Apply(set) + } + } + return set, nil +} + +func eachName(longName string, fn func(string)) { + parts := strings.Split(longName, ",") + for _, name := range parts { + name = strings.Trim(name, " ") + fn(name) + } +} + +// Generic is a generic parseable type identified by a specific flag +type Generic interface { + Set(value string) error + String() string +} + +// Apply takes the flagset and calls Set on the generic flag with the value +// provided by the user for parsing by the flag +// Ignores parsing errors +func (f GenericFlag) Apply(set *flag.FlagSet) { + f.ApplyWithError(set) +} + +// ApplyWithError takes the flagset and calls Set on the generic flag with the value +// provided by the user for parsing by the flag +func (f GenericFlag) ApplyWithError(set *flag.FlagSet) error { + val := f.Value + if f.EnvVar != "" { + for _, envVar := range strings.Split(f.EnvVar, ",") { + envVar = strings.TrimSpace(envVar) + if envVal, ok := syscall.Getenv(envVar); ok { + if err := val.Set(envVal); err != nil { + return fmt.Errorf("could not parse %s as value for flag %s: %s", envVal, f.Name, err) + } + break + } + } + } + + eachName(f.Name, func(name string) { + set.Var(f.Value, name, f.Usage) + }) + + return nil +} + +// StringSlice is an opaque type for []string to satisfy flag.Value and flag.Getter +type StringSlice []string + +// Set appends the string value to the list of values +func (f *StringSlice) Set(value string) error { + *f = append(*f, value) + return nil +} + +// String returns a readable representation of this value (for usage defaults) +func (f *StringSlice) String() string { + return fmt.Sprintf("%s", *f) +} + +// Value returns the slice of strings set by this flag +func (f *StringSlice) Value() []string { + return *f +} + +// Get returns the slice of strings set by this flag +func (f *StringSlice) Get() interface{} { + return *f +} + +// Apply populates the flag given the flag set and environment +// Ignores errors +func (f StringSliceFlag) Apply(set *flag.FlagSet) { + f.ApplyWithError(set) +} + +// ApplyWithError populates the flag given the flag set and environment +func (f StringSliceFlag) ApplyWithError(set *flag.FlagSet) error { + if f.EnvVar != "" { + for _, envVar := range strings.Split(f.EnvVar, ",") { + envVar = strings.TrimSpace(envVar) + if envVal, ok := syscall.Getenv(envVar); ok { + newVal := &StringSlice{} + for _, s := range strings.Split(envVal, ",") { + s = strings.TrimSpace(s) + if err := newVal.Set(s); err != nil { + return fmt.Errorf("could not parse %s as string value for flag %s: %s", envVal, f.Name, err) + } + } + f.Value = newVal + break + } + } + } + + eachName(f.Name, func(name string) { + if f.Value == nil { + f.Value = &StringSlice{} + } + set.Var(f.Value, name, f.Usage) + }) + + return nil +} + +// IntSlice is an opaque type for []int to satisfy flag.Value and flag.Getter +type IntSlice []int + +// Set parses the value into an integer and appends it to the list of values +func (f *IntSlice) Set(value string) error { + tmp, err := strconv.Atoi(value) + if err != nil { + return err + } + *f = append(*f, tmp) + return nil +} + +// String returns a readable representation of this value (for usage defaults) +func (f *IntSlice) String() string { + return fmt.Sprintf("%#v", *f) +} + +// Value returns the slice of ints set by this flag +func (f *IntSlice) Value() []int { + return *f +} + +// Get returns the slice of ints set by this flag +func (f *IntSlice) Get() interface{} { + return *f +} + +// Apply populates the flag given the flag set and environment +// Ignores errors +func (f IntSliceFlag) Apply(set *flag.FlagSet) { + f.ApplyWithError(set) +} + +// ApplyWithError populates the flag given the flag set and environment +func (f IntSliceFlag) ApplyWithError(set *flag.FlagSet) error { + if f.EnvVar != "" { + for _, envVar := range strings.Split(f.EnvVar, ",") { + envVar = strings.TrimSpace(envVar) + if envVal, ok := syscall.Getenv(envVar); ok { + newVal := &IntSlice{} + for _, s := range strings.Split(envVal, ",") { + s = strings.TrimSpace(s) + if err := newVal.Set(s); err != nil { + return fmt.Errorf("could not parse %s as int slice value for flag %s: %s", envVal, f.Name, err) + } + } + f.Value = newVal + break + } + } + } + + eachName(f.Name, func(name string) { + if f.Value == nil { + f.Value = &IntSlice{} + } + set.Var(f.Value, name, f.Usage) + }) + + return nil +} + +// Int64Slice is an opaque type for []int to satisfy flag.Value and flag.Getter +type Int64Slice []int64 + +// Set parses the value into an integer and appends it to the list of values +func (f *Int64Slice) Set(value string) error { + tmp, err := strconv.ParseInt(value, 10, 64) + if err != nil { + return err + } + *f = append(*f, tmp) + return nil +} + +// String returns a readable representation of this value (for usage defaults) +func (f *Int64Slice) String() string { + return fmt.Sprintf("%#v", *f) +} + +// Value returns the slice of ints set by this flag +func (f *Int64Slice) Value() []int64 { + return *f +} + +// Get returns the slice of ints set by this flag +func (f *Int64Slice) Get() interface{} { + return *f +} + +// Apply populates the flag given the flag set and environment +// Ignores errors +func (f Int64SliceFlag) Apply(set *flag.FlagSet) { + f.ApplyWithError(set) +} + +// ApplyWithError populates the flag given the flag set and environment +func (f Int64SliceFlag) ApplyWithError(set *flag.FlagSet) error { + if f.EnvVar != "" { + for _, envVar := range strings.Split(f.EnvVar, ",") { + envVar = strings.TrimSpace(envVar) + if envVal, ok := syscall.Getenv(envVar); ok { + newVal := &Int64Slice{} + for _, s := range strings.Split(envVal, ",") { + s = strings.TrimSpace(s) + if err := newVal.Set(s); err != nil { + return fmt.Errorf("could not parse %s as int64 slice value for flag %s: %s", envVal, f.Name, err) + } + } + f.Value = newVal + break + } + } + } + + eachName(f.Name, func(name string) { + if f.Value == nil { + f.Value = &Int64Slice{} + } + set.Var(f.Value, name, f.Usage) + }) + return nil +} + +// Apply populates the flag given the flag set and environment +// Ignores errors +func (f BoolFlag) Apply(set *flag.FlagSet) { + f.ApplyWithError(set) +} + +// ApplyWithError populates the flag given the flag set and environment +func (f BoolFlag) ApplyWithError(set *flag.FlagSet) error { + val := false + if f.EnvVar != "" { + for _, envVar := range strings.Split(f.EnvVar, ",") { + envVar = strings.TrimSpace(envVar) + if envVal, ok := syscall.Getenv(envVar); ok { + if envVal == "" { + val = false + break + } + + envValBool, err := strconv.ParseBool(envVal) + if err != nil { + return fmt.Errorf("could not parse %s as bool value for flag %s: %s", envVal, f.Name, err) + } + + val = envValBool + break + } + } + } + + eachName(f.Name, func(name string) { + if f.Destination != nil { + set.BoolVar(f.Destination, name, val, f.Usage) + return + } + set.Bool(name, val, f.Usage) + }) + + return nil +} + +// Apply populates the flag given the flag set and environment +// Ignores errors +func (f BoolTFlag) Apply(set *flag.FlagSet) { + f.ApplyWithError(set) +} + +// ApplyWithError populates the flag given the flag set and environment +func (f BoolTFlag) ApplyWithError(set *flag.FlagSet) error { + val := true + if f.EnvVar != "" { + for _, envVar := range strings.Split(f.EnvVar, ",") { + envVar = strings.TrimSpace(envVar) + if envVal, ok := syscall.Getenv(envVar); ok { + if envVal == "" { + val = false + break + } + + envValBool, err := strconv.ParseBool(envVal) + if err != nil { + return fmt.Errorf("could not parse %s as bool value for flag %s: %s", envVal, f.Name, err) + } + + val = envValBool + break + } + } + } + + eachName(f.Name, func(name string) { + if f.Destination != nil { + set.BoolVar(f.Destination, name, val, f.Usage) + return + } + set.Bool(name, val, f.Usage) + }) + + return nil +} + +// Apply populates the flag given the flag set and environment +// Ignores errors +func (f StringFlag) Apply(set *flag.FlagSet) { + f.ApplyWithError(set) +} + +// ApplyWithError populates the flag given the flag set and environment +func (f StringFlag) ApplyWithError(set *flag.FlagSet) error { + if f.EnvVar != "" { + for _, envVar := range strings.Split(f.EnvVar, ",") { + envVar = strings.TrimSpace(envVar) + if envVal, ok := syscall.Getenv(envVar); ok { + f.Value = envVal + break + } + } + } + + eachName(f.Name, func(name string) { + if f.Destination != nil { + set.StringVar(f.Destination, name, f.Value, f.Usage) + return + } + set.String(name, f.Value, f.Usage) + }) + + return nil +} + +// Apply populates the flag given the flag set and environment +// Ignores errors +func (f IntFlag) Apply(set *flag.FlagSet) { + f.ApplyWithError(set) +} + +// ApplyWithError populates the flag given the flag set and environment +func (f IntFlag) ApplyWithError(set *flag.FlagSet) error { + if f.EnvVar != "" { + for _, envVar := range strings.Split(f.EnvVar, ",") { + envVar = strings.TrimSpace(envVar) + if envVal, ok := syscall.Getenv(envVar); ok { + envValInt, err := strconv.ParseInt(envVal, 0, 64) + if err != nil { + return fmt.Errorf("could not parse %s as int value for flag %s: %s", envVal, f.Name, err) + } + f.Value = int(envValInt) + break + } + } + } + + eachName(f.Name, func(name string) { + if f.Destination != nil { + set.IntVar(f.Destination, name, f.Value, f.Usage) + return + } + set.Int(name, f.Value, f.Usage) + }) + + return nil +} + +// Apply populates the flag given the flag set and environment +// Ignores errors +func (f Int64Flag) Apply(set *flag.FlagSet) { + f.ApplyWithError(set) +} + +// ApplyWithError populates the flag given the flag set and environment +func (f Int64Flag) ApplyWithError(set *flag.FlagSet) error { + if f.EnvVar != "" { + for _, envVar := range strings.Split(f.EnvVar, ",") { + envVar = strings.TrimSpace(envVar) + if envVal, ok := syscall.Getenv(envVar); ok { + envValInt, err := strconv.ParseInt(envVal, 0, 64) + if err != nil { + return fmt.Errorf("could not parse %s as int value for flag %s: %s", envVal, f.Name, err) + } + + f.Value = envValInt + break + } + } + } + + eachName(f.Name, func(name string) { + if f.Destination != nil { + set.Int64Var(f.Destination, name, f.Value, f.Usage) + return + } + set.Int64(name, f.Value, f.Usage) + }) + + return nil +} + +// Apply populates the flag given the flag set and environment +// Ignores errors +func (f UintFlag) Apply(set *flag.FlagSet) { + f.ApplyWithError(set) +} + +// ApplyWithError populates the flag given the flag set and environment +func (f UintFlag) ApplyWithError(set *flag.FlagSet) error { + if f.EnvVar != "" { + for _, envVar := range strings.Split(f.EnvVar, ",") { + envVar = strings.TrimSpace(envVar) + if envVal, ok := syscall.Getenv(envVar); ok { + envValInt, err := strconv.ParseUint(envVal, 0, 64) + if err != nil { + return fmt.Errorf("could not parse %s as uint value for flag %s: %s", envVal, f.Name, err) + } + + f.Value = uint(envValInt) + break + } + } + } + + eachName(f.Name, func(name string) { + if f.Destination != nil { + set.UintVar(f.Destination, name, f.Value, f.Usage) + return + } + set.Uint(name, f.Value, f.Usage) + }) + + return nil +} + +// Apply populates the flag given the flag set and environment +// Ignores errors +func (f Uint64Flag) Apply(set *flag.FlagSet) { + f.ApplyWithError(set) +} + +// ApplyWithError populates the flag given the flag set and environment +func (f Uint64Flag) ApplyWithError(set *flag.FlagSet) error { + if f.EnvVar != "" { + for _, envVar := range strings.Split(f.EnvVar, ",") { + envVar = strings.TrimSpace(envVar) + if envVal, ok := syscall.Getenv(envVar); ok { + envValInt, err := strconv.ParseUint(envVal, 0, 64) + if err != nil { + return fmt.Errorf("could not parse %s as uint64 value for flag %s: %s", envVal, f.Name, err) + } + + f.Value = uint64(envValInt) + break + } + } + } + + eachName(f.Name, func(name string) { + if f.Destination != nil { + set.Uint64Var(f.Destination, name, f.Value, f.Usage) + return + } + set.Uint64(name, f.Value, f.Usage) + }) + + return nil +} + +// Apply populates the flag given the flag set and environment +// Ignores errors +func (f DurationFlag) Apply(set *flag.FlagSet) { + f.ApplyWithError(set) +} + +// ApplyWithError populates the flag given the flag set and environment +func (f DurationFlag) ApplyWithError(set *flag.FlagSet) error { + if f.EnvVar != "" { + for _, envVar := range strings.Split(f.EnvVar, ",") { + envVar = strings.TrimSpace(envVar) + if envVal, ok := syscall.Getenv(envVar); ok { + envValDuration, err := time.ParseDuration(envVal) + if err != nil { + return fmt.Errorf("could not parse %s as duration for flag %s: %s", envVal, f.Name, err) + } + + f.Value = envValDuration + break + } + } + } + + eachName(f.Name, func(name string) { + if f.Destination != nil { + set.DurationVar(f.Destination, name, f.Value, f.Usage) + return + } + set.Duration(name, f.Value, f.Usage) + }) + + return nil +} + +// Apply populates the flag given the flag set and environment +// Ignores errors +func (f Float64Flag) Apply(set *flag.FlagSet) { + f.ApplyWithError(set) +} + +// ApplyWithError populates the flag given the flag set and environment +func (f Float64Flag) ApplyWithError(set *flag.FlagSet) error { + if f.EnvVar != "" { + for _, envVar := range strings.Split(f.EnvVar, ",") { + envVar = strings.TrimSpace(envVar) + if envVal, ok := syscall.Getenv(envVar); ok { + envValFloat, err := strconv.ParseFloat(envVal, 10) + if err != nil { + return fmt.Errorf("could not parse %s as float64 value for flag %s: %s", envVal, f.Name, err) + } + + f.Value = float64(envValFloat) + break + } + } + } + + eachName(f.Name, func(name string) { + if f.Destination != nil { + set.Float64Var(f.Destination, name, f.Value, f.Usage) + return + } + set.Float64(name, f.Value, f.Usage) + }) + + return nil +} + +func visibleFlags(fl []Flag) []Flag { + visible := []Flag{} + for _, flag := range fl { + field := flagValue(flag).FieldByName("Hidden") + if !field.IsValid() || !field.Bool() { + visible = append(visible, flag) + } + } + return visible +} + +func prefixFor(name string) (prefix string) { + if len(name) == 1 { + prefix = "-" + } else { + prefix = "--" + } + + return +} + +// Returns the placeholder, if any, and the unquoted usage string. +func unquoteUsage(usage string) (string, string) { + for i := 0; i < len(usage); i++ { + if usage[i] == '`' { + for j := i + 1; j < len(usage); j++ { + if usage[j] == '`' { + name := usage[i+1 : j] + usage = usage[:i] + name + usage[j+1:] + return name, usage + } + } + break + } + } + return "", usage +} + +func prefixedNames(fullName, placeholder string) string { + var prefixed string + parts := strings.Split(fullName, ",") + for i, name := range parts { + name = strings.Trim(name, " ") + prefixed += prefixFor(name) + name + if placeholder != "" { + prefixed += " " + placeholder + } + if i < len(parts)-1 { + prefixed += ", " + } + } + return prefixed +} + +func withEnvHint(envVar, str string) string { + envText := "" + if envVar != "" { + prefix := "$" + suffix := "" + sep := ", $" + if runtime.GOOS == "windows" { + prefix = "%" + suffix = "%" + sep = "%, %" + } + envText = fmt.Sprintf(" [%s%s%s]", prefix, strings.Join(strings.Split(envVar, ","), sep), suffix) + } + return str + envText +} + +func flagValue(f Flag) reflect.Value { + fv := reflect.ValueOf(f) + for fv.Kind() == reflect.Ptr { + fv = reflect.Indirect(fv) + } + return fv +} + +func stringifyFlag(f Flag) string { + fv := flagValue(f) + + switch f.(type) { + case IntSliceFlag: + return FlagEnvHinter(fv.FieldByName("EnvVar").String(), + stringifyIntSliceFlag(f.(IntSliceFlag))) + case Int64SliceFlag: + return FlagEnvHinter(fv.FieldByName("EnvVar").String(), + stringifyInt64SliceFlag(f.(Int64SliceFlag))) + case StringSliceFlag: + return FlagEnvHinter(fv.FieldByName("EnvVar").String(), + stringifyStringSliceFlag(f.(StringSliceFlag))) + } + + placeholder, usage := unquoteUsage(fv.FieldByName("Usage").String()) + + needsPlaceholder := false + defaultValueString := "" + + if val := fv.FieldByName("Value"); val.IsValid() { + needsPlaceholder = true + defaultValueString = fmt.Sprintf(" (default: %v)", val.Interface()) + + if val.Kind() == reflect.String && val.String() != "" { + defaultValueString = fmt.Sprintf(" (default: %q)", val.String()) + } + } + + if defaultValueString == " (default: )" { + defaultValueString = "" + } + + if needsPlaceholder && placeholder == "" { + placeholder = defaultPlaceholder + } + + usageWithDefault := strings.TrimSpace(fmt.Sprintf("%s%s", usage, defaultValueString)) + + return FlagEnvHinter(fv.FieldByName("EnvVar").String(), + fmt.Sprintf("%s\t%s", FlagNamePrefixer(fv.FieldByName("Name").String(), placeholder), usageWithDefault)) +} + +func stringifyIntSliceFlag(f IntSliceFlag) string { + defaultVals := []string{} + if f.Value != nil && len(f.Value.Value()) > 0 { + for _, i := range f.Value.Value() { + defaultVals = append(defaultVals, fmt.Sprintf("%d", i)) + } + } + + return stringifySliceFlag(f.Usage, f.Name, defaultVals) +} + +func stringifyInt64SliceFlag(f Int64SliceFlag) string { + defaultVals := []string{} + if f.Value != nil && len(f.Value.Value()) > 0 { + for _, i := range f.Value.Value() { + defaultVals = append(defaultVals, fmt.Sprintf("%d", i)) + } + } + + return stringifySliceFlag(f.Usage, f.Name, defaultVals) +} + +func stringifyStringSliceFlag(f StringSliceFlag) string { + defaultVals := []string{} + if f.Value != nil && len(f.Value.Value()) > 0 { + for _, s := range f.Value.Value() { + if len(s) > 0 { + defaultVals = append(defaultVals, fmt.Sprintf("%q", s)) + } + } + } + + return stringifySliceFlag(f.Usage, f.Name, defaultVals) +} + +func stringifySliceFlag(usage, name string, defaultVals []string) string { + placeholder, usage := unquoteUsage(usage) + if placeholder == "" { + placeholder = defaultPlaceholder + } + + defaultVal := "" + if len(defaultVals) > 0 { + defaultVal = fmt.Sprintf(" (default: %s)", strings.Join(defaultVals, ", ")) + } + + usageWithDefault := strings.TrimSpace(fmt.Sprintf("%s%s", usage, defaultVal)) + return fmt.Sprintf("%s\t%s", FlagNamePrefixer(name, placeholder), usageWithDefault) +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/urfave/cli/flag_generated.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/urfave/cli/flag_generated.go new file mode 100644 index 0000000000..491b61956c --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/urfave/cli/flag_generated.go @@ -0,0 +1,627 @@ +package cli + +import ( + "flag" + "strconv" + "time" +) + +// WARNING: This file is generated! + +// BoolFlag is a flag with type bool +type BoolFlag struct { + Name string + Usage string + EnvVar string + Hidden bool + Destination *bool +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f BoolFlag) String() string { + return FlagStringer(f) +} + +// GetName returns the name of the flag +func (f BoolFlag) GetName() string { + return f.Name +} + +// Bool looks up the value of a local BoolFlag, returns +// false if not found +func (c *Context) Bool(name string) bool { + return lookupBool(name, c.flagSet) +} + +// GlobalBool looks up the value of a global BoolFlag, returns +// false if not found +func (c *Context) GlobalBool(name string) bool { + if fs := lookupGlobalFlagSet(name, c); fs != nil { + return lookupBool(name, fs) + } + return false +} + +func lookupBool(name string, set *flag.FlagSet) bool { + f := set.Lookup(name) + if f != nil { + parsed, err := strconv.ParseBool(f.Value.String()) + if err != nil { + return false + } + return parsed + } + return false +} + +// BoolTFlag is a flag with type bool that is true by default +type BoolTFlag struct { + Name string + Usage string + EnvVar string + Hidden bool + Destination *bool +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f BoolTFlag) String() string { + return FlagStringer(f) +} + +// GetName returns the name of the flag +func (f BoolTFlag) GetName() string { + return f.Name +} + +// BoolT looks up the value of a local BoolTFlag, returns +// false if not found +func (c *Context) BoolT(name string) bool { + return lookupBoolT(name, c.flagSet) +} + +// GlobalBoolT looks up the value of a global BoolTFlag, returns +// false if not found +func (c *Context) GlobalBoolT(name string) bool { + if fs := lookupGlobalFlagSet(name, c); fs != nil { + return lookupBoolT(name, fs) + } + return false +} + +func lookupBoolT(name string, set *flag.FlagSet) bool { + f := set.Lookup(name) + if f != nil { + parsed, err := strconv.ParseBool(f.Value.String()) + if err != nil { + return false + } + return parsed + } + return false +} + +// DurationFlag is a flag with type time.Duration (see https://golang.org/pkg/time/#ParseDuration) +type DurationFlag struct { + Name string + Usage string + EnvVar string + Hidden bool + Value time.Duration + Destination *time.Duration +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f DurationFlag) String() string { + return FlagStringer(f) +} + +// GetName returns the name of the flag +func (f DurationFlag) GetName() string { + return f.Name +} + +// Duration looks up the value of a local DurationFlag, returns +// 0 if not found +func (c *Context) Duration(name string) time.Duration { + return lookupDuration(name, c.flagSet) +} + +// GlobalDuration looks up the value of a global DurationFlag, returns +// 0 if not found +func (c *Context) GlobalDuration(name string) time.Duration { + if fs := lookupGlobalFlagSet(name, c); fs != nil { + return lookupDuration(name, fs) + } + return 0 +} + +func lookupDuration(name string, set *flag.FlagSet) time.Duration { + f := set.Lookup(name) + if f != nil { + parsed, err := time.ParseDuration(f.Value.String()) + if err != nil { + return 0 + } + return parsed + } + return 0 +} + +// Float64Flag is a flag with type float64 +type Float64Flag struct { + Name string + Usage string + EnvVar string + Hidden bool + Value float64 + Destination *float64 +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f Float64Flag) String() string { + return FlagStringer(f) +} + +// GetName returns the name of the flag +func (f Float64Flag) GetName() string { + return f.Name +} + +// Float64 looks up the value of a local Float64Flag, returns +// 0 if not found +func (c *Context) Float64(name string) float64 { + return lookupFloat64(name, c.flagSet) +} + +// GlobalFloat64 looks up the value of a global Float64Flag, returns +// 0 if not found +func (c *Context) GlobalFloat64(name string) float64 { + if fs := lookupGlobalFlagSet(name, c); fs != nil { + return lookupFloat64(name, fs) + } + return 0 +} + +func lookupFloat64(name string, set *flag.FlagSet) float64 { + f := set.Lookup(name) + if f != nil { + parsed, err := strconv.ParseFloat(f.Value.String(), 64) + if err != nil { + return 0 + } + return parsed + } + return 0 +} + +// GenericFlag is a flag with type Generic +type GenericFlag struct { + Name string + Usage string + EnvVar string + Hidden bool + Value Generic +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f GenericFlag) String() string { + return FlagStringer(f) +} + +// GetName returns the name of the flag +func (f GenericFlag) GetName() string { + return f.Name +} + +// Generic looks up the value of a local GenericFlag, returns +// nil if not found +func (c *Context) Generic(name string) interface{} { + return lookupGeneric(name, c.flagSet) +} + +// GlobalGeneric looks up the value of a global GenericFlag, returns +// nil if not found +func (c *Context) GlobalGeneric(name string) interface{} { + if fs := lookupGlobalFlagSet(name, c); fs != nil { + return lookupGeneric(name, fs) + } + return nil +} + +func lookupGeneric(name string, set *flag.FlagSet) interface{} { + f := set.Lookup(name) + if f != nil { + parsed, err := f.Value, error(nil) + if err != nil { + return nil + } + return parsed + } + return nil +} + +// Int64Flag is a flag with type int64 +type Int64Flag struct { + Name string + Usage string + EnvVar string + Hidden bool + Value int64 + Destination *int64 +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f Int64Flag) String() string { + return FlagStringer(f) +} + +// GetName returns the name of the flag +func (f Int64Flag) GetName() string { + return f.Name +} + +// Int64 looks up the value of a local Int64Flag, returns +// 0 if not found +func (c *Context) Int64(name string) int64 { + return lookupInt64(name, c.flagSet) +} + +// GlobalInt64 looks up the value of a global Int64Flag, returns +// 0 if not found +func (c *Context) GlobalInt64(name string) int64 { + if fs := lookupGlobalFlagSet(name, c); fs != nil { + return lookupInt64(name, fs) + } + return 0 +} + +func lookupInt64(name string, set *flag.FlagSet) int64 { + f := set.Lookup(name) + if f != nil { + parsed, err := strconv.ParseInt(f.Value.String(), 0, 64) + if err != nil { + return 0 + } + return parsed + } + return 0 +} + +// IntFlag is a flag with type int +type IntFlag struct { + Name string + Usage string + EnvVar string + Hidden bool + Value int + Destination *int +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f IntFlag) String() string { + return FlagStringer(f) +} + +// GetName returns the name of the flag +func (f IntFlag) GetName() string { + return f.Name +} + +// Int looks up the value of a local IntFlag, returns +// 0 if not found +func (c *Context) Int(name string) int { + return lookupInt(name, c.flagSet) +} + +// GlobalInt looks up the value of a global IntFlag, returns +// 0 if not found +func (c *Context) GlobalInt(name string) int { + if fs := lookupGlobalFlagSet(name, c); fs != nil { + return lookupInt(name, fs) + } + return 0 +} + +func lookupInt(name string, set *flag.FlagSet) int { + f := set.Lookup(name) + if f != nil { + parsed, err := strconv.ParseInt(f.Value.String(), 0, 64) + if err != nil { + return 0 + } + return int(parsed) + } + return 0 +} + +// IntSliceFlag is a flag with type *IntSlice +type IntSliceFlag struct { + Name string + Usage string + EnvVar string + Hidden bool + Value *IntSlice +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f IntSliceFlag) String() string { + return FlagStringer(f) +} + +// GetName returns the name of the flag +func (f IntSliceFlag) GetName() string { + return f.Name +} + +// IntSlice looks up the value of a local IntSliceFlag, returns +// nil if not found +func (c *Context) IntSlice(name string) []int { + return lookupIntSlice(name, c.flagSet) +} + +// GlobalIntSlice looks up the value of a global IntSliceFlag, returns +// nil if not found +func (c *Context) GlobalIntSlice(name string) []int { + if fs := lookupGlobalFlagSet(name, c); fs != nil { + return lookupIntSlice(name, fs) + } + return nil +} + +func lookupIntSlice(name string, set *flag.FlagSet) []int { + f := set.Lookup(name) + if f != nil { + parsed, err := (f.Value.(*IntSlice)).Value(), error(nil) + if err != nil { + return nil + } + return parsed + } + return nil +} + +// Int64SliceFlag is a flag with type *Int64Slice +type Int64SliceFlag struct { + Name string + Usage string + EnvVar string + Hidden bool + Value *Int64Slice +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f Int64SliceFlag) String() string { + return FlagStringer(f) +} + +// GetName returns the name of the flag +func (f Int64SliceFlag) GetName() string { + return f.Name +} + +// Int64Slice looks up the value of a local Int64SliceFlag, returns +// nil if not found +func (c *Context) Int64Slice(name string) []int64 { + return lookupInt64Slice(name, c.flagSet) +} + +// GlobalInt64Slice looks up the value of a global Int64SliceFlag, returns +// nil if not found +func (c *Context) GlobalInt64Slice(name string) []int64 { + if fs := lookupGlobalFlagSet(name, c); fs != nil { + return lookupInt64Slice(name, fs) + } + return nil +} + +func lookupInt64Slice(name string, set *flag.FlagSet) []int64 { + f := set.Lookup(name) + if f != nil { + parsed, err := (f.Value.(*Int64Slice)).Value(), error(nil) + if err != nil { + return nil + } + return parsed + } + return nil +} + +// StringFlag is a flag with type string +type StringFlag struct { + Name string + Usage string + EnvVar string + Hidden bool + Value string + Destination *string +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f StringFlag) String() string { + return FlagStringer(f) +} + +// GetName returns the name of the flag +func (f StringFlag) GetName() string { + return f.Name +} + +// String looks up the value of a local StringFlag, returns +// "" if not found +func (c *Context) String(name string) string { + return lookupString(name, c.flagSet) +} + +// GlobalString looks up the value of a global StringFlag, returns +// "" if not found +func (c *Context) GlobalString(name string) string { + if fs := lookupGlobalFlagSet(name, c); fs != nil { + return lookupString(name, fs) + } + return "" +} + +func lookupString(name string, set *flag.FlagSet) string { + f := set.Lookup(name) + if f != nil { + parsed, err := f.Value.String(), error(nil) + if err != nil { + return "" + } + return parsed + } + return "" +} + +// StringSliceFlag is a flag with type *StringSlice +type StringSliceFlag struct { + Name string + Usage string + EnvVar string + Hidden bool + Value *StringSlice +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f StringSliceFlag) String() string { + return FlagStringer(f) +} + +// GetName returns the name of the flag +func (f StringSliceFlag) GetName() string { + return f.Name +} + +// StringSlice looks up the value of a local StringSliceFlag, returns +// nil if not found +func (c *Context) StringSlice(name string) []string { + return lookupStringSlice(name, c.flagSet) +} + +// GlobalStringSlice looks up the value of a global StringSliceFlag, returns +// nil if not found +func (c *Context) GlobalStringSlice(name string) []string { + if fs := lookupGlobalFlagSet(name, c); fs != nil { + return lookupStringSlice(name, fs) + } + return nil +} + +func lookupStringSlice(name string, set *flag.FlagSet) []string { + f := set.Lookup(name) + if f != nil { + parsed, err := (f.Value.(*StringSlice)).Value(), error(nil) + if err != nil { + return nil + } + return parsed + } + return nil +} + +// Uint64Flag is a flag with type uint64 +type Uint64Flag struct { + Name string + Usage string + EnvVar string + Hidden bool + Value uint64 + Destination *uint64 +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f Uint64Flag) String() string { + return FlagStringer(f) +} + +// GetName returns the name of the flag +func (f Uint64Flag) GetName() string { + return f.Name +} + +// Uint64 looks up the value of a local Uint64Flag, returns +// 0 if not found +func (c *Context) Uint64(name string) uint64 { + return lookupUint64(name, c.flagSet) +} + +// GlobalUint64 looks up the value of a global Uint64Flag, returns +// 0 if not found +func (c *Context) GlobalUint64(name string) uint64 { + if fs := lookupGlobalFlagSet(name, c); fs != nil { + return lookupUint64(name, fs) + } + return 0 +} + +func lookupUint64(name string, set *flag.FlagSet) uint64 { + f := set.Lookup(name) + if f != nil { + parsed, err := strconv.ParseUint(f.Value.String(), 0, 64) + if err != nil { + return 0 + } + return parsed + } + return 0 +} + +// UintFlag is a flag with type uint +type UintFlag struct { + Name string + Usage string + EnvVar string + Hidden bool + Value uint + Destination *uint +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f UintFlag) String() string { + return FlagStringer(f) +} + +// GetName returns the name of the flag +func (f UintFlag) GetName() string { + return f.Name +} + +// Uint looks up the value of a local UintFlag, returns +// 0 if not found +func (c *Context) Uint(name string) uint { + return lookupUint(name, c.flagSet) +} + +// GlobalUint looks up the value of a global UintFlag, returns +// 0 if not found +func (c *Context) GlobalUint(name string) uint { + if fs := lookupGlobalFlagSet(name, c); fs != nil { + return lookupUint(name, fs) + } + return 0 +} + +func lookupUint(name string, set *flag.FlagSet) uint { + f := set.Lookup(name) + if f != nil { + parsed, err := strconv.ParseUint(f.Value.String(), 0, 64) + if err != nil { + return 0 + } + return uint(parsed) + } + return 0 +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/urfave/cli/funcs.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/urfave/cli/funcs.go new file mode 100644 index 0000000000..b335dbf6d3 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/urfave/cli/funcs.go @@ -0,0 +1,41 @@ +package cli + +// BashCompleteFunc is an action to execute when the bash-completion flag is set +type BashCompleteFunc func(*Context) + +// BeforeFunc is an action to execute before any subcommands are run, but after +// the context is ready if a non-nil error is returned, no subcommands are run +type BeforeFunc func(*Context) error + +// AfterFunc is an action to execute after any subcommands are run, but after the +// subcommand has finished it is run even if Action() panics +type AfterFunc func(*Context) error + +// ActionFunc is the action to execute when no subcommands are specified +type ActionFunc func(*Context) error + +// CommandNotFoundFunc is executed if the proper command cannot be found +type CommandNotFoundFunc func(*Context, string) + +// OnUsageErrorFunc is executed if an usage error occurs. This is useful for displaying +// customized usage error messages. This function is able to replace the +// original error messages. If this function is not set, the "Incorrect usage" +// is displayed and the execution is interrupted. +type OnUsageErrorFunc func(context *Context, err error, isSubcommand bool) error + +// ExitErrHandlerFunc is executed if provided in order to handle ExitError values +// returned by Actions and Before/After functions. +type ExitErrHandlerFunc func(context *Context, err error) + +// FlagStringFunc is used by the help generation to display a flag, which is +// expected to be a single line. +type FlagStringFunc func(Flag) string + +// FlagNamePrefixFunc is used by the default FlagStringFunc to create prefix +// text for a flag's full name. +type FlagNamePrefixFunc func(fullName, placeholder string) string + +// FlagEnvHintFunc is used by the default FlagStringFunc to annotate flag help +// with the environment variable details. +type FlagEnvHintFunc func(envVar, str string) string + diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/urfave/cli/help.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/urfave/cli/help.go new file mode 100644 index 0000000000..ed084fc1d6 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/urfave/cli/help.go @@ -0,0 +1,339 @@ +package cli + +import ( + "fmt" + "io" + "os" + "strings" + "text/tabwriter" + "text/template" +) + +// AppHelpTemplate is the text template for the Default help topic. +// cli.go uses text/template to render templates. You can +// render custom help text by setting this variable. +var AppHelpTemplate = `NAME: + {{.Name}}{{if .Usage}} - {{.Usage}}{{end}} + +USAGE: + {{if .UsageText}}{{.UsageText}}{{else}}{{.HelpName}} {{if .VisibleFlags}}[global options]{{end}}{{if .Commands}} command [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}{{if .Version}}{{if not .HideVersion}} + +VERSION: + {{.Version}}{{end}}{{end}}{{if .Description}} + +DESCRIPTION: + {{.Description}}{{end}}{{if len .Authors}} + +AUTHOR{{with $length := len .Authors}}{{if ne 1 $length}}S{{end}}{{end}}: + {{range $index, $author := .Authors}}{{if $index}} + {{end}}{{$author}}{{end}}{{end}}{{if .VisibleCommands}} + +COMMANDS:{{range .VisibleCategories}}{{if .Name}} + + {{.Name}}:{{end}}{{range .VisibleCommands}} + {{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}{{end}}{{end}}{{if .VisibleFlags}} + +GLOBAL OPTIONS: + {{range $index, $option := .VisibleFlags}}{{if $index}} + {{end}}{{$option}}{{end}}{{end}}{{if .Copyright}} + +COPYRIGHT: + {{.Copyright}}{{end}} +` + +// CommandHelpTemplate is the text template for the command help topic. +// cli.go uses text/template to render templates. You can +// render custom help text by setting this variable. +var CommandHelpTemplate = `NAME: + {{.HelpName}} - {{.Usage}} + +USAGE: + {{if .UsageText}}{{.UsageText}}{{else}}{{.HelpName}}{{if .VisibleFlags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}{{if .Category}} + +CATEGORY: + {{.Category}}{{end}}{{if .Description}} + +DESCRIPTION: + {{.Description}}{{end}}{{if .VisibleFlags}} + +OPTIONS: + {{range .VisibleFlags}}{{.}} + {{end}}{{end}} +` + +// SubcommandHelpTemplate is the text template for the subcommand help topic. +// cli.go uses text/template to render templates. You can +// render custom help text by setting this variable. +var SubcommandHelpTemplate = `NAME: + {{.HelpName}} - {{if .Description}}{{.Description}}{{else}}{{.Usage}}{{end}} + +USAGE: + {{if .UsageText}}{{.UsageText}}{{else}}{{.HelpName}} command{{if .VisibleFlags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}} + +COMMANDS:{{range .VisibleCategories}}{{if .Name}} + {{.Name}}:{{end}}{{range .VisibleCommands}} + {{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}} +{{end}}{{if .VisibleFlags}} +OPTIONS: + {{range .VisibleFlags}}{{.}} + {{end}}{{end}} +` + +var helpCommand = Command{ + Name: "help", + Aliases: []string{"h"}, + Usage: "Shows a list of commands or help for one command", + ArgsUsage: "[command]", + Action: func(c *Context) error { + args := c.Args() + if args.Present() { + return ShowCommandHelp(c, args.First()) + } + + ShowAppHelp(c) + return nil + }, +} + +var helpSubcommand = Command{ + Name: "help", + Aliases: []string{"h"}, + Usage: "Shows a list of commands or help for one command", + ArgsUsage: "[command]", + Action: func(c *Context) error { + args := c.Args() + if args.Present() { + return ShowCommandHelp(c, args.First()) + } + + return ShowSubcommandHelp(c) + }, +} + +// Prints help for the App or Command +type helpPrinter func(w io.Writer, templ string, data interface{}) + +// Prints help for the App or Command with custom template function. +type helpPrinterCustom func(w io.Writer, templ string, data interface{}, customFunc map[string]interface{}) + +// HelpPrinter is a function that writes the help output. If not set a default +// is used. The function signature is: +// func(w io.Writer, templ string, data interface{}) +var HelpPrinter helpPrinter = printHelp + +// HelpPrinterCustom is same as HelpPrinter but +// takes a custom function for template function map. +var HelpPrinterCustom helpPrinterCustom = printHelpCustom + +// VersionPrinter prints the version for the App +var VersionPrinter = printVersion + +// ShowAppHelpAndExit - Prints the list of subcommands for the app and exits with exit code. +func ShowAppHelpAndExit(c *Context, exitCode int) { + ShowAppHelp(c) + os.Exit(exitCode) +} + +// ShowAppHelp is an action that displays the help. +func ShowAppHelp(c *Context) (err error) { + if c.App.CustomAppHelpTemplate == "" { + HelpPrinter(c.App.Writer, AppHelpTemplate, c.App) + return + } + customAppData := func() map[string]interface{} { + if c.App.ExtraInfo == nil { + return nil + } + return map[string]interface{}{ + "ExtraInfo": c.App.ExtraInfo, + } + } + HelpPrinterCustom(c.App.Writer, c.App.CustomAppHelpTemplate, c.App, customAppData()) + return nil +} + +// DefaultAppComplete prints the list of subcommands as the default app completion method +func DefaultAppComplete(c *Context) { + for _, command := range c.App.Commands { + if command.Hidden { + continue + } + for _, name := range command.Names() { + fmt.Fprintln(c.App.Writer, name) + } + } +} + +// ShowCommandHelpAndExit - exits with code after showing help +func ShowCommandHelpAndExit(c *Context, command string, code int) { + ShowCommandHelp(c, command) + os.Exit(code) +} + +// ShowCommandHelp prints help for the given command +func ShowCommandHelp(ctx *Context, command string) error { + // show the subcommand help for a command with subcommands + if command == "" { + HelpPrinter(ctx.App.Writer, SubcommandHelpTemplate, ctx.App) + return nil + } + + for _, c := range ctx.App.Commands { + if c.HasName(command) { + if c.CustomHelpTemplate != "" { + HelpPrinterCustom(ctx.App.Writer, c.CustomHelpTemplate, c, nil) + } else { + HelpPrinter(ctx.App.Writer, CommandHelpTemplate, c) + } + return nil + } + } + + if ctx.App.CommandNotFound == nil { + return NewExitError(fmt.Sprintf("No help topic for '%v'", command), 3) + } + + ctx.App.CommandNotFound(ctx, command) + return nil +} + +// ShowSubcommandHelp prints help for the given subcommand +func ShowSubcommandHelp(c *Context) error { + return ShowCommandHelp(c, c.Command.Name) +} + +// ShowVersion prints the version number of the App +func ShowVersion(c *Context) { + VersionPrinter(c) +} + +func printVersion(c *Context) { + fmt.Fprintf(c.App.Writer, "%v version %v\n", c.App.Name, c.App.Version) +} + +// ShowCompletions prints the lists of commands within a given context +func ShowCompletions(c *Context) { + a := c.App + if a != nil && a.BashComplete != nil { + a.BashComplete(c) + } +} + +// ShowCommandCompletions prints the custom completions for a given command +func ShowCommandCompletions(ctx *Context, command string) { + c := ctx.App.Command(command) + if c != nil && c.BashComplete != nil { + c.BashComplete(ctx) + } +} + +func printHelpCustom(out io.Writer, templ string, data interface{}, customFunc map[string]interface{}) { + funcMap := template.FuncMap{ + "join": strings.Join, + } + if customFunc != nil { + for key, value := range customFunc { + funcMap[key] = value + } + } + + w := tabwriter.NewWriter(out, 1, 8, 2, ' ', 0) + t := template.Must(template.New("help").Funcs(funcMap).Parse(templ)) + err := t.Execute(w, data) + if err != nil { + // If the writer is closed, t.Execute will fail, and there's nothing + // we can do to recover. + if os.Getenv("CLI_TEMPLATE_ERROR_DEBUG") != "" { + fmt.Fprintf(ErrWriter, "CLI TEMPLATE ERROR: %#v\n", err) + } + return + } + w.Flush() +} + +func printHelp(out io.Writer, templ string, data interface{}) { + printHelpCustom(out, templ, data, nil) +} + +func checkVersion(c *Context) bool { + found := false + if VersionFlag.GetName() != "" { + eachName(VersionFlag.GetName(), func(name string) { + if c.GlobalBool(name) || c.Bool(name) { + found = true + } + }) + } + return found +} + +func checkHelp(c *Context) bool { + found := false + if HelpFlag.GetName() != "" { + eachName(HelpFlag.GetName(), func(name string) { + if c.GlobalBool(name) || c.Bool(name) { + found = true + } + }) + } + return found +} + +func checkCommandHelp(c *Context, name string) bool { + if c.Bool("h") || c.Bool("help") { + ShowCommandHelp(c, name) + return true + } + + return false +} + +func checkSubcommandHelp(c *Context) bool { + if c.Bool("h") || c.Bool("help") { + ShowSubcommandHelp(c) + return true + } + + return false +} + +func checkShellCompleteFlag(a *App, arguments []string) (bool, []string) { + if !a.EnableBashCompletion { + return false, arguments + } + + pos := len(arguments) - 1 + lastArg := arguments[pos] + + if lastArg != "--"+BashCompletionFlag.GetName() { + return false, arguments + } + + return true, arguments[:pos] +} + +func checkCompletions(c *Context) bool { + if !c.shellComplete { + return false + } + + if args := c.Args(); args.Present() { + name := args.First() + if cmd := c.App.Command(name); cmd != nil { + // let the command handle the completion + return false + } + } + + ShowCompletions(c) + return true +} + +func checkCommandCompletions(c *Context, name string) bool { + if !c.shellComplete { + return false + } + + ShowCommandCompletions(c, name) + return true +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonpointer/LICENSE-APACHE-2.0.txt b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonpointer/LICENSE-APACHE-2.0.txt new file mode 100644 index 0000000000..55ede8a42c --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonpointer/LICENSE-APACHE-2.0.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2015 xeipuuv + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonpointer/README.md b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonpointer/README.md new file mode 100644 index 0000000000..00059242ca --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonpointer/README.md @@ -0,0 +1,41 @@ +# gojsonpointer +An implementation of JSON Pointer - Go language + +## Usage + jsonText := `{ + "name": "Bobby B", + "occupation": { + "title" : "King", + "years" : 15, + "heir" : "Joffrey B" + } + }` + + var jsonDocument map[string]interface{} + json.Unmarshal([]byte(jsonText), &jsonDocument) + + //create a JSON pointer + pointerString := "/occupation/title" + pointer, _ := NewJsonPointer(pointerString) + + //SET a new value for the "title" in the document + pointer.Set(jsonDocument, "Supreme Leader of Westeros") + + //GET the new "title" from the document + title, _, _ := pointer.Get(jsonDocument) + fmt.Println(title) //outputs "Supreme Leader of Westeros" + + //DELETE the "heir" from the document + deletePointer := NewJsonPointer("/occupation/heir") + deletePointer.Delete(jsonDocument) + + b, _ := json.Marshal(jsonDocument) + fmt.Println(string(b)) + //outputs `{"name":"Bobby B","occupation":{"title":"Supreme Leader of Westeros","years":15}}` + + +## References +http://tools.ietf.org/html/draft-ietf-appsawg-json-pointer-07 + +### Note +The 4.Evaluation part of the previous reference, starting with 'If the currently referenced value is a JSON array, the reference token MUST contain either...' is not implemented. diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonpointer/pointer.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonpointer/pointer.go new file mode 100644 index 0000000000..7faf5d7f94 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonpointer/pointer.go @@ -0,0 +1,211 @@ +// Copyright 2015 xeipuuv ( https://github.com/xeipuuv ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// author xeipuuv +// author-github https://github.com/xeipuuv +// author-mail xeipuuv@gmail.com +// +// repository-name gojsonpointer +// repository-desc An implementation of JSON Pointer - Go language +// +// description Main and unique file. +// +// created 25-02-2013 + +package gojsonpointer + +import ( + "errors" + "fmt" + "reflect" + "strconv" + "strings" +) + +const ( + const_empty_pointer = `` + const_pointer_separator = `/` + + const_invalid_start = `JSON pointer must be empty or start with a "` + const_pointer_separator + `"` +) + +type implStruct struct { + mode string // "SET" or "GET" + + inDocument interface{} + + setInValue interface{} + + getOutNode interface{} + getOutKind reflect.Kind + outError error +} + +type JsonPointer struct { + referenceTokens []string +} + +// NewJsonPointer parses the given string JSON pointer and returns an object +func NewJsonPointer(jsonPointerString string) (p JsonPointer, err error) { + + // Pointer to the root of the document + if len(jsonPointerString) == 0 { + // Keep referenceTokens nil + return + } + if jsonPointerString[0] != '/' { + return p, errors.New(const_invalid_start) + } + + p.referenceTokens = strings.Split(jsonPointerString[1:], const_pointer_separator) + return +} + +// Uses the pointer to retrieve a value from a JSON document +func (p *JsonPointer) Get(document interface{}) (interface{}, reflect.Kind, error) { + + is := &implStruct{mode: "GET", inDocument: document} + p.implementation(is) + return is.getOutNode, is.getOutKind, is.outError + +} + +// Uses the pointer to update a value from a JSON document +func (p *JsonPointer) Set(document interface{}, value interface{}) (interface{}, error) { + + is := &implStruct{mode: "SET", inDocument: document, setInValue: value} + p.implementation(is) + return document, is.outError + +} + +// Uses the pointer to delete a value from a JSON document +func (p *JsonPointer) Delete(document interface{}) (interface{}, error) { + is := &implStruct{mode: "DEL", inDocument: document} + p.implementation(is) + return document, is.outError +} + +// Both Get and Set functions use the same implementation to avoid code duplication +func (p *JsonPointer) implementation(i *implStruct) { + + kind := reflect.Invalid + + // Full document when empty + if len(p.referenceTokens) == 0 { + i.getOutNode = i.inDocument + i.outError = nil + i.getOutKind = kind + i.outError = nil + return + } + + node := i.inDocument + + previousNodes := make([]interface{}, len(p.referenceTokens)) + previousTokens := make([]string, len(p.referenceTokens)) + + for ti, token := range p.referenceTokens { + + isLastToken := ti == len(p.referenceTokens)-1 + previousNodes[ti] = node + previousTokens[ti] = token + + switch v := node.(type) { + + case map[string]interface{}: + decodedToken := decodeReferenceToken(token) + if _, ok := v[decodedToken]; ok { + node = v[decodedToken] + if isLastToken && i.mode == "SET" { + v[decodedToken] = i.setInValue + } else if isLastToken && i.mode =="DEL" { + delete(v,decodedToken) + } + } else if (isLastToken && i.mode == "SET") { + v[decodedToken] = i.setInValue + } else { + i.outError = fmt.Errorf("Object has no key '%s'", decodedToken) + i.getOutKind = reflect.Map + i.getOutNode = nil + return + } + + case []interface{}: + tokenIndex, err := strconv.Atoi(token) + if err != nil { + i.outError = fmt.Errorf("Invalid array index '%s'", token) + i.getOutKind = reflect.Slice + i.getOutNode = nil + return + } + if tokenIndex < 0 || tokenIndex >= len(v) { + i.outError = fmt.Errorf("Out of bound array[0,%d] index '%d'", len(v), tokenIndex) + i.getOutKind = reflect.Slice + i.getOutNode = nil + return + } + + node = v[tokenIndex] + if isLastToken && i.mode == "SET" { + v[tokenIndex] = i.setInValue + } else if isLastToken && i.mode =="DEL" { + v[tokenIndex] = v[len(v)-1] + v[len(v)-1] = nil + v = v[:len(v)-1] + previousNodes[ti-1].(map[string]interface{})[previousTokens[ti-1]] = v + } + + default: + i.outError = fmt.Errorf("Invalid token reference '%s'", token) + i.getOutKind = reflect.ValueOf(node).Kind() + i.getOutNode = nil + return + } + + } + + i.getOutNode = node + i.getOutKind = reflect.ValueOf(node).Kind() + i.outError = nil +} + +// Pointer to string representation function +func (p *JsonPointer) String() string { + + if len(p.referenceTokens) == 0 { + return const_empty_pointer + } + + pointerString := const_pointer_separator + strings.Join(p.referenceTokens, const_pointer_separator) + + return pointerString +} + +// Specific JSON pointer encoding here +// ~0 => ~ +// ~1 => / +// ... and vice versa + +func decodeReferenceToken(token string) string { + step1 := strings.Replace(token, `~1`, `/`, -1) + step2 := strings.Replace(step1, `~0`, `~`, -1) + return step2 +} + +func encodeReferenceToken(token string) string { + step1 := strings.Replace(token, `~`, `~0`, -1) + step2 := strings.Replace(step1, `/`, `~1`, -1) + return step2 +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonreference/LICENSE-APACHE-2.0.txt b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonreference/LICENSE-APACHE-2.0.txt new file mode 100644 index 0000000000..55ede8a42c --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonreference/LICENSE-APACHE-2.0.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2015 xeipuuv + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonreference/README.md b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonreference/README.md new file mode 100644 index 0000000000..9ab6e1eb13 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonreference/README.md @@ -0,0 +1,10 @@ +# gojsonreference +An implementation of JSON Reference - Go language + +## Dependencies +https://github.com/xeipuuv/gojsonpointer + +## References +http://tools.ietf.org/html/draft-ietf-appsawg-json-pointer-07 + +http://tools.ietf.org/html/draft-pbryan-zyp-json-ref-03 diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonreference/reference.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonreference/reference.go new file mode 100644 index 0000000000..6457291301 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonreference/reference.go @@ -0,0 +1,147 @@ +// Copyright 2015 xeipuuv ( https://github.com/xeipuuv ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// author xeipuuv +// author-github https://github.com/xeipuuv +// author-mail xeipuuv@gmail.com +// +// repository-name gojsonreference +// repository-desc An implementation of JSON Reference - Go language +// +// description Main and unique file. +// +// created 26-02-2013 + +package gojsonreference + +import ( + "errors" + "net/url" + "path/filepath" + "runtime" + "strings" + + "github.com/xeipuuv/gojsonpointer" +) + +const ( + const_fragment_char = `#` +) + +func NewJsonReference(jsonReferenceString string) (JsonReference, error) { + + var r JsonReference + err := r.parse(jsonReferenceString) + return r, err + +} + +type JsonReference struct { + referenceUrl *url.URL + referencePointer gojsonpointer.JsonPointer + + HasFullUrl bool + HasUrlPathOnly bool + HasFragmentOnly bool + HasFileScheme bool + HasFullFilePath bool +} + +func (r *JsonReference) GetUrl() *url.URL { + return r.referenceUrl +} + +func (r *JsonReference) GetPointer() *gojsonpointer.JsonPointer { + return &r.referencePointer +} + +func (r *JsonReference) String() string { + + if r.referenceUrl != nil { + return r.referenceUrl.String() + } + + if r.HasFragmentOnly { + return const_fragment_char + r.referencePointer.String() + } + + return r.referencePointer.String() +} + +func (r *JsonReference) IsCanonical() bool { + return (r.HasFileScheme && r.HasFullFilePath) || (!r.HasFileScheme && r.HasFullUrl) +} + +// "Constructor", parses the given string JSON reference +func (r *JsonReference) parse(jsonReferenceString string) (err error) { + + r.referenceUrl, err = url.Parse(jsonReferenceString) + if err != nil { + return + } + refUrl := r.referenceUrl + + if refUrl.Scheme != "" && refUrl.Host != "" { + r.HasFullUrl = true + } else { + if refUrl.Path != "" { + r.HasUrlPathOnly = true + } else if refUrl.RawQuery == "" && refUrl.Fragment != "" { + r.HasFragmentOnly = true + } + } + + r.HasFileScheme = refUrl.Scheme == "file" + if runtime.GOOS == "windows" { + // on Windows, a file URL may have an extra leading slash, and if it + // doesn't then its first component will be treated as the host by the + // Go runtime + if refUrl.Host == "" && strings.HasPrefix(refUrl.Path, "/") { + r.HasFullFilePath = filepath.IsAbs(refUrl.Path[1:]) + } else { + r.HasFullFilePath = filepath.IsAbs(refUrl.Host + refUrl.Path) + } + } else { + r.HasFullFilePath = filepath.IsAbs(refUrl.Path) + } + + // invalid json-pointer error means url has no json-pointer fragment. simply ignore error + r.referencePointer, _ = gojsonpointer.NewJsonPointer(refUrl.Fragment) + + return +} + +// Creates a new reference from a parent and a child +// If the child cannot inherit from the parent, an error is returned +func (r *JsonReference) Inherits(child JsonReference) (*JsonReference, error) { + if child.GetUrl() == nil { + return nil, errors.New("childUrl is nil!") + } + + if r.GetUrl() == nil { + return nil, errors.New("parentUrl is nil!") + } + + // Get a copy of the parent url to make sure we do not modify the original. + // URL reference resolving fails if the fragment of the child is empty, but the parent's is not. + // The fragment of the child must be used, so the fragment of the parent is manually removed. + parentUrl := *r.GetUrl() + parentUrl.Fragment = "" + + ref, err := NewJsonReference(parentUrl.ResolveReference(child.GetUrl()).String()) + if err != nil { + return nil, err + } + return &ref, err +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/LICENSE-APACHE-2.0.txt b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/LICENSE-APACHE-2.0.txt new file mode 100644 index 0000000000..55ede8a42c --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/LICENSE-APACHE-2.0.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2015 xeipuuv + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/README.md b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/README.md new file mode 100644 index 0000000000..b890eee1d6 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/README.md @@ -0,0 +1,351 @@ +[![GoDoc](https://godoc.org/github.com/xeipuuv/gojsonschema?status.svg)](https://godoc.org/github.com/xeipuuv/gojsonschema) +[![Build Status](https://travis-ci.org/xeipuuv/gojsonschema.svg)](https://travis-ci.org/xeipuuv/gojsonschema) + +# gojsonschema + +## Description + +An implementation of JSON Schema for the Go programming language. Supports draft-04, draft-06 and draft-07. + +References : + +* http://json-schema.org +* http://json-schema.org/latest/json-schema-core.html +* http://json-schema.org/latest/json-schema-validation.html + +## Installation + +``` +go get github.com/xeipuuv/gojsonschema +``` + +Dependencies : +* [github.com/xeipuuv/gojsonpointer](https://github.com/xeipuuv/gojsonpointer) +* [github.com/xeipuuv/gojsonreference](https://github.com/xeipuuv/gojsonreference) +* [github.com/stretchr/testify/assert](https://github.com/stretchr/testify#assert-package) + +## Usage + +### Example + +```go + +package main + +import ( + "fmt" + "github.com/xeipuuv/gojsonschema" +) + +func main() { + + schemaLoader := gojsonschema.NewReferenceLoader("file:///home/me/schema.json") + documentLoader := gojsonschema.NewReferenceLoader("file:///home/me/document.json") + + result, err := gojsonschema.Validate(schemaLoader, documentLoader) + if err != nil { + panic(err.Error()) + } + + if result.Valid() { + fmt.Printf("The document is valid\n") + } else { + fmt.Printf("The document is not valid. see errors :\n") + for _, desc := range result.Errors() { + fmt.Printf("- %s\n", desc) + } + } + +} + + +``` + +#### Loaders + +There are various ways to load your JSON data. +In order to load your schemas and documents, +first declare an appropriate loader : + +* Web / HTTP, using a reference : + +```go +loader := gojsonschema.NewReferenceLoader("http://www.some_host.com/schema.json") +``` + +* Local file, using a reference : + +```go +loader := gojsonschema.NewReferenceLoader("file:///home/me/schema.json") +``` + +References use the URI scheme, the prefix (file://) and a full path to the file are required. + +* JSON strings : + +```go +loader := gojsonschema.NewStringLoader(`{"type": "string"}`) +``` + +* Custom Go types : + +```go +m := map[string]interface{}{"type": "string"} +loader := gojsonschema.NewGoLoader(m) +``` + +And + +```go +type Root struct { + Users []User `json:"users"` +} + +type User struct { + Name string `json:"name"` +} + +... + +data := Root{} +data.Users = append(data.Users, User{"John"}) +data.Users = append(data.Users, User{"Sophia"}) +data.Users = append(data.Users, User{"Bill"}) + +loader := gojsonschema.NewGoLoader(data) +``` + +#### Validation + +Once the loaders are set, validation is easy : + +```go +result, err := gojsonschema.Validate(schemaLoader, documentLoader) +``` + +Alternatively, you might want to load a schema only once and process to multiple validations : + +```go +schema, err := gojsonschema.NewSchema(schemaLoader) +... +result1, err := schema.Validate(documentLoader1) +... +result2, err := schema.Validate(documentLoader2) +... +// etc ... +``` + +To check the result : + +```go + if result.Valid() { + fmt.Printf("The document is valid\n") + } else { + fmt.Printf("The document is not valid. see errors :\n") + for _, err := range result.Errors() { + // Err implements the ResultError interface + fmt.Printf("- %s\n", err) + } + } +``` + +## Working with Errors + +The library handles string error codes which you can customize by creating your own gojsonschema.locale and setting it +```go +gojsonschema.Locale = YourCustomLocale{} +``` + +However, each error contains additional contextual information. + +Newer versions of `gojsonschema` may have new additional errors, so code that uses a custom locale will need to be updated when this happens. + +**err.Type()**: *string* Returns the "type" of error that occurred. Note you can also type check. See below + +Note: An error of RequiredType has an err.Type() return value of "required" + + "required": RequiredError + "invalid_type": InvalidTypeError + "number_any_of": NumberAnyOfError + "number_one_of": NumberOneOfError + "number_all_of": NumberAllOfError + "number_not": NumberNotError + "missing_dependency": MissingDependencyError + "internal": InternalError + "const": ConstEror + "enum": EnumError + "array_no_additional_items": ArrayNoAdditionalItemsError + "array_min_items": ArrayMinItemsError + "array_max_items": ArrayMaxItemsError + "unique": ItemsMustBeUniqueError + "contains" : ArrayContainsError + "array_min_properties": ArrayMinPropertiesError + "array_max_properties": ArrayMaxPropertiesError + "additional_property_not_allowed": AdditionalPropertyNotAllowedError + "invalid_property_pattern": InvalidPropertyPatternError + "invalid_property_name": InvalidPropertyNameError + "string_gte": StringLengthGTEError + "string_lte": StringLengthLTEError + "pattern": DoesNotMatchPatternError + "multiple_of": MultipleOfError + "number_gte": NumberGTEError + "number_gt": NumberGTError + "number_lte": NumberLTEError + "number_lt": NumberLTError + +**err.Value()**: *interface{}* Returns the value given + +**err.Context()**: *gojsonschema.JsonContext* Returns the context. This has a String() method that will print something like this: (root).firstName + +**err.Field()**: *string* Returns the fieldname in the format firstName, or for embedded properties, person.firstName. This returns the same as the String() method on *err.Context()* but removes the (root). prefix. + +**err.Description()**: *string* The error description. This is based on the locale you are using. See the beginning of this section for overwriting the locale with a custom implementation. + +**err.DescriptionFormat()**: *string* The error description format. This is relevant if you are adding custom validation errors afterwards to the result. + +**err.Details()**: *gojsonschema.ErrorDetails* Returns a map[string]interface{} of additional error details specific to the error. For example, GTE errors will have a "min" value, LTE will have a "max" value. See errors.go for a full description of all the error details. Every error always contains a "field" key that holds the value of *err.Field()* + +Note in most cases, the err.Details() will be used to generate replacement strings in your locales, and not used directly. These strings follow the text/template format i.e. +``` +{{.field}} must be greater than or equal to {{.min}} +``` + +The library allows you to specify custom template functions, should you require more complex error message handling. +```go +gojsonschema.ErrorTemplateFuncs = map[string]interface{}{ + "allcaps": func(s string) string { + return strings.ToUpper(s) + }, +} +``` + +Given the above definition, you can use the custom function `"allcaps"` in your localization templates: +``` +{{allcaps .field}} must be greater than or equal to {{.min}} +``` + +The above error message would then be rendered with the `field` value in capital letters. For example: +``` +"PASSWORD must be greater than or equal to 8" +``` + +Learn more about what types of template functions you can use in `ErrorTemplateFuncs` by referring to Go's [text/template FuncMap](https://golang.org/pkg/text/template/#FuncMap) type. + +## Formats +JSON Schema allows for optional "format" property to validate instances against well-known formats. gojsonschema ships with all of the formats defined in the spec that you can use like this: +````json +{"type": "string", "format": "email"} +```` +Available formats: date-time, hostname, email, ipv4, ipv6, uri, uri-reference, uuid, regex. Some of the new formats in draft-06 and draft-07 are not yet implemented. + +For repetitive or more complex formats, you can create custom format checkers and add them to gojsonschema like this: + +```go +// Define the format checker +type RoleFormatChecker struct {} + +// Ensure it meets the gojsonschema.FormatChecker interface +func (f RoleFormatChecker) IsFormat(input interface{}) bool { + + asString, ok := input.(string) + if ok == false { + return false + } + + return strings.HasPrefix("ROLE_", asString) +} + +// Add it to the library +gojsonschema.FormatCheckers.Add("role", RoleFormatChecker{}) +```` + +Now to use in your json schema: +````json +{"type": "string", "format": "role"} +```` + +Another example would be to check if the provided integer matches an id on database: + +JSON schema: +```json +{"type": "integer", "format": "ValidUserId"} +``` + +```go +// Define the format checker +type ValidUserIdFormatChecker struct {} + +// Ensure it meets the gojsonschema.FormatChecker interface +func (f ValidUserIdFormatChecker) IsFormat(input interface{}) bool { + + asFloat64, ok := input.(float64) // Numbers are always float64 here + if ok == false { + return false + } + + // XXX + // do the magic on the database looking for the int(asFloat64) + + return true +} + +// Add it to the library +gojsonschema.FormatCheckers.Add("ValidUserId", ValidUserIdFormatChecker{}) +```` + +## Additional custom validation +After the validation has run and you have the results, you may add additional +errors using `Result.AddError`. This is useful to maintain the same format within the resultset instead +of having to add special exceptions for your own errors. Below is an example. + +```go +type AnswerInvalidError struct { + gojsonschema.ResultErrorFields +} + +func newAnswerInvalidError(context *gojsonschema.JsonContext, value interface{}, details gojsonschema.ErrorDetails) *AnswerInvalidError { + err := AnswerInvalidError{} + err.SetContext(context) + err.SetType("custom_invalid_error") + // it is important to use SetDescriptionFormat() as this is used to call SetDescription() after it has been parsed + // using the description of err will be overridden by this. + err.SetDescriptionFormat("Answer to the Ultimate Question of Life, the Universe, and Everything is {{.answer}}") + err.SetValue(value) + err.SetDetails(details) + + return &err +} + +func main() { + // ... + schema, err := gojsonschema.NewSchema(schemaLoader) + result, err := gojsonschema.Validate(schemaLoader, documentLoader) + + if true { // some validation + jsonContext := gojsonschema.NewJsonContext("question", nil) + errDetail := gojsonschema.ErrorDetails{ + "answer": 42, + } + result.AddError( + newAnswerInvalidError( + gojsonschema.NewJsonContext("answer", jsonContext), + 52, + errDetail, + ), + errDetail, + ) + } + + return result, err + +} +``` + +This is especially useful if you want to add validation beyond what the +json schema drafts can provide such business specific logic. + +## Uses + +gojsonschema uses the following test suite : + +https://github.com/json-schema/JSON-Schema-Test-Suite diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/errors.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/errors.go new file mode 100644 index 0000000000..2f326a2228 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/errors.go @@ -0,0 +1,324 @@ +package gojsonschema + +import ( + "bytes" + "sync" + "text/template" +) + +var errorTemplates errorTemplate = errorTemplate{template.New("errors-new"), sync.RWMutex{}} + +// template.Template is not thread-safe for writing, so some locking is done +// sync.RWMutex is used for efficiently locking when new templates are created +type errorTemplate struct { + *template.Template + sync.RWMutex +} + +type ( + // RequiredError. ErrorDetails: property string + RequiredError struct { + ResultErrorFields + } + + // InvalidTypeError. ErrorDetails: expected, given + InvalidTypeError struct { + ResultErrorFields + } + + // NumberAnyOfError. ErrorDetails: - + NumberAnyOfError struct { + ResultErrorFields + } + + // NumberOneOfError. ErrorDetails: - + NumberOneOfError struct { + ResultErrorFields + } + + // NumberAllOfError. ErrorDetails: - + NumberAllOfError struct { + ResultErrorFields + } + + // NumberNotError. ErrorDetails: - + NumberNotError struct { + ResultErrorFields + } + + // MissingDependencyError. ErrorDetails: dependency + MissingDependencyError struct { + ResultErrorFields + } + + // InternalError. ErrorDetails: error + InternalError struct { + ResultErrorFields + } + + // ConstError. ErrorDetails: allowed + ConstError struct { + ResultErrorFields + } + + // EnumError. ErrorDetails: allowed + EnumError struct { + ResultErrorFields + } + + // ArrayNoAdditionalItemsError. ErrorDetails: - + ArrayNoAdditionalItemsError struct { + ResultErrorFields + } + + // ArrayMinItemsError. ErrorDetails: min + ArrayMinItemsError struct { + ResultErrorFields + } + + // ArrayMaxItemsError. ErrorDetails: max + ArrayMaxItemsError struct { + ResultErrorFields + } + + // ItemsMustBeUniqueError. ErrorDetails: type + ItemsMustBeUniqueError struct { + ResultErrorFields + } + + // ArrayContainsError. ErrorDetails: + ArrayContainsError struct { + ResultErrorFields + } + + // ArrayMinPropertiesError. ErrorDetails: min + ArrayMinPropertiesError struct { + ResultErrorFields + } + + // ArrayMaxPropertiesError. ErrorDetails: max + ArrayMaxPropertiesError struct { + ResultErrorFields + } + + // AdditionalPropertyNotAllowedError. ErrorDetails: property + AdditionalPropertyNotAllowedError struct { + ResultErrorFields + } + + // InvalidPropertyPatternError. ErrorDetails: property, pattern + InvalidPropertyPatternError struct { + ResultErrorFields + } + + // InvalidPopertyNameError. ErrorDetails: property + InvalidPropertyNameError struct { + ResultErrorFields + } + + // StringLengthGTEError. ErrorDetails: min + StringLengthGTEError struct { + ResultErrorFields + } + + // StringLengthLTEError. ErrorDetails: max + StringLengthLTEError struct { + ResultErrorFields + } + + // DoesNotMatchPatternError. ErrorDetails: pattern + DoesNotMatchPatternError struct { + ResultErrorFields + } + + // DoesNotMatchFormatError. ErrorDetails: format + DoesNotMatchFormatError struct { + ResultErrorFields + } + + // MultipleOfError. ErrorDetails: multiple + MultipleOfError struct { + ResultErrorFields + } + + // NumberGTEError. ErrorDetails: min + NumberGTEError struct { + ResultErrorFields + } + + // NumberGTError. ErrorDetails: min + NumberGTError struct { + ResultErrorFields + } + + // NumberLTEError. ErrorDetails: max + NumberLTEError struct { + ResultErrorFields + } + + // NumberLTError. ErrorDetails: max + NumberLTError struct { + ResultErrorFields + } + + // ConditionThenError. ErrorDetails: - + ConditionThenError struct { + ResultErrorFields + } + + // ConditionElseError. ErrorDetails: - + ConditionElseError struct { + ResultErrorFields + } +) + +// newError takes a ResultError type and sets the type, context, description, details, value, and field +func newError(err ResultError, context *JsonContext, value interface{}, locale locale, details ErrorDetails) { + var t string + var d string + switch err.(type) { + case *RequiredError: + t = "required" + d = locale.Required() + case *InvalidTypeError: + t = "invalid_type" + d = locale.InvalidType() + case *NumberAnyOfError: + t = "number_any_of" + d = locale.NumberAnyOf() + case *NumberOneOfError: + t = "number_one_of" + d = locale.NumberOneOf() + case *NumberAllOfError: + t = "number_all_of" + d = locale.NumberAllOf() + case *NumberNotError: + t = "number_not" + d = locale.NumberNot() + case *MissingDependencyError: + t = "missing_dependency" + d = locale.MissingDependency() + case *InternalError: + t = "internal" + d = locale.Internal() + case *ConstError: + t = "const" + d = locale.Const() + case *EnumError: + t = "enum" + d = locale.Enum() + case *ArrayNoAdditionalItemsError: + t = "array_no_additional_items" + d = locale.ArrayNoAdditionalItems() + case *ArrayMinItemsError: + t = "array_min_items" + d = locale.ArrayMinItems() + case *ArrayMaxItemsError: + t = "array_max_items" + d = locale.ArrayMaxItems() + case *ItemsMustBeUniqueError: + t = "unique" + d = locale.Unique() + case *ArrayContainsError: + t = "contains" + d = locale.ArrayContains() + case *ArrayMinPropertiesError: + t = "array_min_properties" + d = locale.ArrayMinProperties() + case *ArrayMaxPropertiesError: + t = "array_max_properties" + d = locale.ArrayMaxProperties() + case *AdditionalPropertyNotAllowedError: + t = "additional_property_not_allowed" + d = locale.AdditionalPropertyNotAllowed() + case *InvalidPropertyPatternError: + t = "invalid_property_pattern" + d = locale.InvalidPropertyPattern() + case *InvalidPropertyNameError: + t = "invalid_property_name" + d = locale.InvalidPropertyName() + case *StringLengthGTEError: + t = "string_gte" + d = locale.StringGTE() + case *StringLengthLTEError: + t = "string_lte" + d = locale.StringLTE() + case *DoesNotMatchPatternError: + t = "pattern" + d = locale.DoesNotMatchPattern() + case *DoesNotMatchFormatError: + t = "format" + d = locale.DoesNotMatchFormat() + case *MultipleOfError: + t = "multiple_of" + d = locale.MultipleOf() + case *NumberGTEError: + t = "number_gte" + d = locale.NumberGTE() + case *NumberGTError: + t = "number_gt" + d = locale.NumberGT() + case *NumberLTEError: + t = "number_lte" + d = locale.NumberLTE() + case *NumberLTError: + t = "number_lt" + d = locale.NumberLT() + case *ConditionThenError: + t = "condition_then" + d = locale.ConditionThen() + case *ConditionElseError: + t = "condition_else" + d = locale.ConditionElse() + } + + err.SetType(t) + err.SetContext(context) + err.SetValue(value) + err.SetDetails(details) + err.SetDescriptionFormat(d) + details["field"] = err.Field() + + if _, exists := details["context"]; !exists && context != nil { + details["context"] = context.String() + } + + err.SetDescription(formatErrorDescription(err.DescriptionFormat(), details)) +} + +// formatErrorDescription takes a string in the default text/template +// format and converts it to a string with replacements. The fields come +// from the ErrorDetails struct and vary for each type of error. +func formatErrorDescription(s string, details ErrorDetails) string { + + var tpl *template.Template + var descrAsBuffer bytes.Buffer + var err error + + errorTemplates.RLock() + tpl = errorTemplates.Lookup(s) + errorTemplates.RUnlock() + + if tpl == nil { + errorTemplates.Lock() + tpl = errorTemplates.New(s) + + if ErrorTemplateFuncs != nil { + tpl.Funcs(ErrorTemplateFuncs) + } + + tpl, err = tpl.Parse(s) + errorTemplates.Unlock() + + if err != nil { + return err.Error() + } + } + + err = tpl.Execute(&descrAsBuffer, details) + if err != nil { + return err.Error() + } + + return descrAsBuffer.String() +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/format_checkers.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/format_checkers.go new file mode 100644 index 0000000000..20ead1f73e --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/format_checkers.go @@ -0,0 +1,250 @@ +package gojsonschema + +import ( + "net" + "net/url" + "regexp" + "strings" + "time" +) + +type ( + // FormatChecker is the interface all formatters added to FormatCheckerChain must implement + FormatChecker interface { + IsFormat(input interface{}) bool + } + + // FormatCheckerChain holds the formatters + FormatCheckerChain struct { + formatters map[string]FormatChecker + } + + // EmailFormatter verifies email address formats + EmailFormatChecker struct{} + + // IPV4FormatChecker verifies IP addresses in the ipv4 format + IPV4FormatChecker struct{} + + // IPV6FormatChecker verifies IP addresses in the ipv6 format + IPV6FormatChecker struct{} + + // DateTimeFormatChecker verifies date/time formats per RFC3339 5.6 + // + // Valid formats: + // Partial Time: HH:MM:SS + // Full Date: YYYY-MM-DD + // Full Time: HH:MM:SSZ-07:00 + // Date Time: YYYY-MM-DDTHH:MM:SSZ-0700 + // + // Where + // YYYY = 4DIGIT year + // MM = 2DIGIT month ; 01-12 + // DD = 2DIGIT day-month ; 01-28, 01-29, 01-30, 01-31 based on month/year + // HH = 2DIGIT hour ; 00-23 + // MM = 2DIGIT ; 00-59 + // SS = 2DIGIT ; 00-58, 00-60 based on leap second rules + // T = Literal + // Z = Literal + // + // Note: Nanoseconds are also suported in all formats + // + // http://tools.ietf.org/html/rfc3339#section-5.6 + DateTimeFormatChecker struct{} + + // URIFormatChecker validates a URI with a valid Scheme per RFC3986 + URIFormatChecker struct{} + + // URIReferenceFormatChecker validates a URI or relative-reference per RFC3986 + URIReferenceFormatChecker struct{} + + // HostnameFormatChecker validates a hostname is in the correct format + HostnameFormatChecker struct{} + + // UUIDFormatChecker validates a UUID is in the correct format + UUIDFormatChecker struct{} + + // RegexFormatChecker validates a regex is in the correct format + RegexFormatChecker struct{} +) + +var ( + // Formatters holds the valid formatters, and is a public variable + // so library users can add custom formatters + FormatCheckers = FormatCheckerChain{ + formatters: map[string]FormatChecker{ + "date-time": DateTimeFormatChecker{}, + "hostname": HostnameFormatChecker{}, + "email": EmailFormatChecker{}, + "ipv4": IPV4FormatChecker{}, + "ipv6": IPV6FormatChecker{}, + "uri": URIFormatChecker{}, + "uri-reference": URIReferenceFormatChecker{}, + "uuid": UUIDFormatChecker{}, + "regex": RegexFormatChecker{}, + }, + } + + // Regex credit: https://github.com/asaskevich/govalidator + rxEmail = regexp.MustCompile("^(((([a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+(\\.([a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+)*)|((\\x22)((((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(([\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]|\\x21|[\\x23-\\x5b]|[\\x5d-\\x7e]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(\\([\\x01-\\x09\\x0b\\x0c\\x0d-\\x7f]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}]))))*(((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(\\x22)))@((([a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(([a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])([a-zA-Z]|\\d|-|\\.|_|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*([a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.)+(([a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(([a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])([a-zA-Z]|\\d|-|\\.|_|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*([a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.?$") + + // Regex credit: https://www.socketloop.com/tutorials/golang-validate-hostname + rxHostname = regexp.MustCompile(`^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$`) + + rxUUID = regexp.MustCompile("^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$") +) + +// Add adds a FormatChecker to the FormatCheckerChain +// The name used will be the value used for the format key in your json schema +func (c *FormatCheckerChain) Add(name string, f FormatChecker) *FormatCheckerChain { + c.formatters[name] = f + + return c +} + +// Remove deletes a FormatChecker from the FormatCheckerChain (if it exists) +func (c *FormatCheckerChain) Remove(name string) *FormatCheckerChain { + delete(c.formatters, name) + + return c +} + +// Has checks to see if the FormatCheckerChain holds a FormatChecker with the given name +func (c *FormatCheckerChain) Has(name string) bool { + _, ok := c.formatters[name] + + return ok +} + +// IsFormat will check an input against a FormatChecker with the given name +// to see if it is the correct format +func (c *FormatCheckerChain) IsFormat(name string, input interface{}) bool { + f, ok := c.formatters[name] + + if !ok { + return false + } + + return f.IsFormat(input) +} + +func (f EmailFormatChecker) IsFormat(input interface{}) bool { + + asString, ok := input.(string) + if ok == false { + return false + } + + return rxEmail.MatchString(asString) +} + +// Credit: https://github.com/asaskevich/govalidator +func (f IPV4FormatChecker) IsFormat(input interface{}) bool { + + asString, ok := input.(string) + if ok == false { + return false + } + + ip := net.ParseIP(asString) + return ip != nil && strings.Contains(asString, ".") +} + +// Credit: https://github.com/asaskevich/govalidator +func (f IPV6FormatChecker) IsFormat(input interface{}) bool { + + asString, ok := input.(string) + if ok == false { + return false + } + + ip := net.ParseIP(asString) + return ip != nil && strings.Contains(asString, ":") +} + +func (f DateTimeFormatChecker) IsFormat(input interface{}) bool { + + asString, ok := input.(string) + if ok == false { + return false + } + + formats := []string{ + "15:04:05", + "15:04:05Z07:00", + "2006-01-02", + time.RFC3339, + time.RFC3339Nano, + } + + for _, format := range formats { + if _, err := time.Parse(format, asString); err == nil { + return true + } + } + + return false +} + +func (f URIFormatChecker) IsFormat(input interface{}) bool { + + asString, ok := input.(string) + if ok == false { + return false + } + + u, err := url.Parse(asString) + if err != nil || u.Scheme == "" { + return false + } + + return true +} + +func (f URIReferenceFormatChecker) IsFormat(input interface{}) bool { + + asString, ok := input.(string) + if ok == false { + return false + } + + _, err := url.Parse(asString) + return err == nil +} + +func (f HostnameFormatChecker) IsFormat(input interface{}) bool { + + asString, ok := input.(string) + if ok == false { + return false + } + + return rxHostname.MatchString(asString) && len(asString) < 256 +} + +func (f UUIDFormatChecker) IsFormat(input interface{}) bool { + + asString, ok := input.(string) + if ok == false { + return false + } + + return rxUUID.MatchString(asString) +} + +// IsFormat implements FormatChecker interface. +func (f RegexFormatChecker) IsFormat(input interface{}) bool { + + asString, ok := input.(string) + if ok == false { + return false + } + + if asString == "" { + return true + } + _, err := regexp.Compile(asString) + if err != nil { + return false + } + return true +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/internalLog.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/internalLog.go new file mode 100644 index 0000000000..4ef7a8d03e --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/internalLog.go @@ -0,0 +1,37 @@ +// Copyright 2015 xeipuuv ( https://github.com/xeipuuv ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// author xeipuuv +// author-github https://github.com/xeipuuv +// author-mail xeipuuv@gmail.com +// +// repository-name gojsonschema +// repository-desc An implementation of JSON Schema, based on IETF's draft v4 - Go language. +// +// description Very simple log wrapper. +// Used for debugging/testing purposes. +// +// created 01-01-2015 + +package gojsonschema + +import ( + "log" +) + +const internalLogEnabled = false + +func internalLog(format string, v ...interface{}) { + log.Printf(format, v...) +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/jsonContext.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/jsonContext.go new file mode 100644 index 0000000000..f40668a74c --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/jsonContext.go @@ -0,0 +1,72 @@ +// Copyright 2013 MongoDB, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// author tolsen +// author-github https://github.com/tolsen +// +// repository-name gojsonschema +// repository-desc An implementation of JSON Schema, based on IETF's draft v4 - Go language. +// +// description Implements a persistent (immutable w/ shared structure) singly-linked list of strings for the purpose of storing a json context +// +// created 04-09-2013 + +package gojsonschema + +import "bytes" + +// JsonContext implements a persistent linked-list of strings +type JsonContext struct { + head string + tail *JsonContext +} + +func NewJsonContext(head string, tail *JsonContext) *JsonContext { + return &JsonContext{head, tail} +} + +// String displays the context in reverse. +// This plays well with the data structure's persistent nature with +// Cons and a json document's tree structure. +func (c *JsonContext) String(del ...string) string { + byteArr := make([]byte, 0, c.stringLen()) + buf := bytes.NewBuffer(byteArr) + c.writeStringToBuffer(buf, del) + + return buf.String() +} + +func (c *JsonContext) stringLen() int { + length := 0 + if c.tail != nil { + length = c.tail.stringLen() + 1 // add 1 for "." + } + + length += len(c.head) + return length +} + +func (c *JsonContext) writeStringToBuffer(buf *bytes.Buffer, del []string) { + if c.tail != nil { + c.tail.writeStringToBuffer(buf, del) + + if len(del) > 0 { + buf.WriteString(del[0]) + } else { + buf.WriteString(".") + } + } + + buf.WriteString(c.head) +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/jsonLoader.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/jsonLoader.go new file mode 100644 index 0000000000..3a3b6d5c4a --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/jsonLoader.go @@ -0,0 +1,364 @@ +// Copyright 2015 xeipuuv ( https://github.com/xeipuuv ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// author xeipuuv +// author-github https://github.com/xeipuuv +// author-mail xeipuuv@gmail.com +// +// repository-name gojsonschema +// repository-desc An implementation of JSON Schema, based on IETF's draft v4 - Go language. +// +// description Different strategies to load JSON files. +// Includes References (file and HTTP), JSON strings and Go types. +// +// created 01-02-2015 + +package gojsonschema + +import ( + "bytes" + "encoding/json" + "errors" + "io" + "io/ioutil" + "net/http" + "os" + "path/filepath" + "runtime" + "strings" + + "github.com/xeipuuv/gojsonreference" +) + +var osFS = osFileSystem(os.Open) + +// JSON loader interface + +type JSONLoader interface { + JsonSource() interface{} + LoadJSON() (interface{}, error) + JsonReference() (gojsonreference.JsonReference, error) + LoaderFactory() JSONLoaderFactory +} + +type JSONLoaderFactory interface { + New(source string) JSONLoader +} + +type DefaultJSONLoaderFactory struct { +} + +type FileSystemJSONLoaderFactory struct { + fs http.FileSystem +} + +func (d DefaultJSONLoaderFactory) New(source string) JSONLoader { + return &jsonReferenceLoader{ + fs: osFS, + source: source, + } +} + +func (f FileSystemJSONLoaderFactory) New(source string) JSONLoader { + return &jsonReferenceLoader{ + fs: f.fs, + source: source, + } +} + +// osFileSystem is a functional wrapper for os.Open that implements http.FileSystem. +type osFileSystem func(string) (*os.File, error) + +func (o osFileSystem) Open(name string) (http.File, error) { + return o(name) +} + +// JSON Reference loader +// references are used to load JSONs from files and HTTP + +type jsonReferenceLoader struct { + fs http.FileSystem + source string +} + +func (l *jsonReferenceLoader) JsonSource() interface{} { + return l.source +} + +func (l *jsonReferenceLoader) JsonReference() (gojsonreference.JsonReference, error) { + return gojsonreference.NewJsonReference(l.JsonSource().(string)) +} + +func (l *jsonReferenceLoader) LoaderFactory() JSONLoaderFactory { + return &FileSystemJSONLoaderFactory{ + fs: l.fs, + } +} + +// NewReferenceLoader returns a JSON reference loader using the given source and the local OS file system. +func NewReferenceLoader(source string) *jsonReferenceLoader { + return &jsonReferenceLoader{ + fs: osFS, + source: source, + } +} + +// NewReferenceLoaderFileSystem returns a JSON reference loader using the given source and file system. +func NewReferenceLoaderFileSystem(source string, fs http.FileSystem) *jsonReferenceLoader { + return &jsonReferenceLoader{ + fs: fs, + source: source, + } +} + +func (l *jsonReferenceLoader) LoadJSON() (interface{}, error) { + + var err error + + reference, err := gojsonreference.NewJsonReference(l.JsonSource().(string)) + if err != nil { + return nil, err + } + + refToUrl := reference + refToUrl.GetUrl().Fragment = "" + + var document interface{} + + if reference.HasFileScheme { + + filename := strings.Replace(refToUrl.GetUrl().Path, "file://", "", -1) + if runtime.GOOS == "windows" { + // on Windows, a file URL may have an extra leading slash, use slashes + // instead of backslashes, and have spaces escaped + if strings.HasPrefix(filename, "/") { + filename = filename[1:] + } + filename = filepath.FromSlash(filename) + } + + document, err = l.loadFromFile(filename) + if err != nil { + return nil, err + } + + } else { + + document, err = l.loadFromHTTP(refToUrl.String()) + if err != nil { + return nil, err + } + + } + + return document, nil + +} + +func (l *jsonReferenceLoader) loadFromHTTP(address string) (interface{}, error) { + + resp, err := http.Get(address) + if err != nil { + return nil, err + } + + // must return HTTP Status 200 OK + if resp.StatusCode != http.StatusOK { + return nil, errors.New(formatErrorDescription(Locale.HttpBadStatus(), ErrorDetails{"status": resp.Status})) + } + + bodyBuff, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + return decodeJsonUsingNumber(bytes.NewReader(bodyBuff)) + +} + +func (l *jsonReferenceLoader) loadFromFile(path string) (interface{}, error) { + f, err := l.fs.Open(path) + if err != nil { + return nil, err + } + defer f.Close() + + bodyBuff, err := ioutil.ReadAll(f) + if err != nil { + return nil, err + } + + return decodeJsonUsingNumber(bytes.NewReader(bodyBuff)) + +} + +// JSON string loader + +type jsonStringLoader struct { + source string +} + +func (l *jsonStringLoader) JsonSource() interface{} { + return l.source +} + +func (l *jsonStringLoader) JsonReference() (gojsonreference.JsonReference, error) { + return gojsonreference.NewJsonReference("#") +} + +func (l *jsonStringLoader) LoaderFactory() JSONLoaderFactory { + return &DefaultJSONLoaderFactory{} +} + +func NewStringLoader(source string) *jsonStringLoader { + return &jsonStringLoader{source: source} +} + +func (l *jsonStringLoader) LoadJSON() (interface{}, error) { + + return decodeJsonUsingNumber(strings.NewReader(l.JsonSource().(string))) + +} + +// JSON bytes loader + +type jsonBytesLoader struct { + source []byte +} + +func (l *jsonBytesLoader) JsonSource() interface{} { + return l.source +} + +func (l *jsonBytesLoader) JsonReference() (gojsonreference.JsonReference, error) { + return gojsonreference.NewJsonReference("#") +} + +func (l *jsonBytesLoader) LoaderFactory() JSONLoaderFactory { + return &DefaultJSONLoaderFactory{} +} + +func NewBytesLoader(source []byte) *jsonBytesLoader { + return &jsonBytesLoader{source: source} +} + +func (l *jsonBytesLoader) LoadJSON() (interface{}, error) { + return decodeJsonUsingNumber(bytes.NewReader(l.JsonSource().([]byte))) +} + +// JSON Go (types) loader +// used to load JSONs from the code as maps, interface{}, structs ... + +type jsonGoLoader struct { + source interface{} +} + +func (l *jsonGoLoader) JsonSource() interface{} { + return l.source +} + +func (l *jsonGoLoader) JsonReference() (gojsonreference.JsonReference, error) { + return gojsonreference.NewJsonReference("#") +} + +func (l *jsonGoLoader) LoaderFactory() JSONLoaderFactory { + return &DefaultJSONLoaderFactory{} +} + +func NewGoLoader(source interface{}) *jsonGoLoader { + return &jsonGoLoader{source: source} +} + +func (l *jsonGoLoader) LoadJSON() (interface{}, error) { + + // convert it to a compliant JSON first to avoid types "mismatches" + + jsonBytes, err := json.Marshal(l.JsonSource()) + if err != nil { + return nil, err + } + + return decodeJsonUsingNumber(bytes.NewReader(jsonBytes)) + +} + +type jsonIOLoader struct { + buf *bytes.Buffer +} + +func NewReaderLoader(source io.Reader) (*jsonIOLoader, io.Reader) { + buf := &bytes.Buffer{} + return &jsonIOLoader{buf: buf}, io.TeeReader(source, buf) +} + +func NewWriterLoader(source io.Writer) (*jsonIOLoader, io.Writer) { + buf := &bytes.Buffer{} + return &jsonIOLoader{buf: buf}, io.MultiWriter(source, buf) +} + +func (l *jsonIOLoader) JsonSource() interface{} { + return l.buf.String() +} + +func (l *jsonIOLoader) LoadJSON() (interface{}, error) { + return decodeJsonUsingNumber(l.buf) +} + +func (l *jsonIOLoader) JsonReference() (gojsonreference.JsonReference, error) { + return gojsonreference.NewJsonReference("#") +} + +func (l *jsonIOLoader) LoaderFactory() JSONLoaderFactory { + return &DefaultJSONLoaderFactory{} +} + +// JSON raw loader +// In case the JSON is already marshalled to interface{} use this loader +// This is used for testing as otherwise there is no guarantee the JSON is marshalled +// "properly" by using https://golang.org/pkg/encoding/json/#Decoder.UseNumber +type jsonRawLoader struct { + source interface{} +} + +func NewRawLoader(source interface{}) *jsonRawLoader { + return &jsonRawLoader{source: source} +} +func (l *jsonRawLoader) JsonSource() interface{} { + return l.source +} +func (l *jsonRawLoader) LoadJSON() (interface{}, error) { + return l.source, nil +} +func (l *jsonRawLoader) JsonReference() (gojsonreference.JsonReference, error) { + return gojsonreference.NewJsonReference("#") +} +func (l *jsonRawLoader) LoaderFactory() JSONLoaderFactory { + return &DefaultJSONLoaderFactory{} +} + +func decodeJsonUsingNumber(r io.Reader) (interface{}, error) { + + var document interface{} + + decoder := json.NewDecoder(r) + decoder.UseNumber() + + err := decoder.Decode(&document) + if err != nil { + return nil, err + } + + return document, nil + +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/locales.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/locales.go new file mode 100644 index 0000000000..7bd9a9dce5 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/locales.go @@ -0,0 +1,313 @@ +// Copyright 2015 xeipuuv ( https://github.com/xeipuuv ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// author xeipuuv +// author-github https://github.com/xeipuuv +// author-mail xeipuuv@gmail.com +// +// repository-name gojsonschema +// repository-desc An implementation of JSON Schema, based on IETF's draft v4 - Go language. +// +// description Contains const string and messages. +// +// created 01-01-2015 + +package gojsonschema + +type ( + // locale is an interface for defining custom error strings + locale interface { + Required() string + InvalidType() string + NumberAnyOf() string + NumberOneOf() string + NumberAllOf() string + NumberNot() string + MissingDependency() string + Internal() string + Const() string + Enum() string + ArrayNotEnoughItems() string + ArrayNoAdditionalItems() string + ArrayMinItems() string + ArrayMaxItems() string + Unique() string + ArrayContains() string + ArrayMinProperties() string + ArrayMaxProperties() string + AdditionalPropertyNotAllowed() string + InvalidPropertyPattern() string + InvalidPropertyName() string + StringGTE() string + StringLTE() string + DoesNotMatchPattern() string + DoesNotMatchFormat() string + MultipleOf() string + NumberGTE() string + NumberGT() string + NumberLTE() string + NumberLT() string + + // Schema validations + RegexPattern() string + GreaterThanZero() string + MustBeOfA() string + MustBeOfAn() string + CannotBeUsedWithout() string + CannotBeGT() string + MustBeOfType() string + MustBeValidRegex() string + MustBeValidFormat() string + MustBeGTEZero() string + KeyCannotBeGreaterThan() string + KeyItemsMustBeOfType() string + KeyItemsMustBeUnique() string + ReferenceMustBeCanonical() string + NotAValidType() string + Duplicated() string + HttpBadStatus() string + ParseError() string + + ConditionThen() string + ConditionElse() string + + // ErrorFormat + ErrorFormat() string + } + + // DefaultLocale is the default locale for this package + DefaultLocale struct{} +) + +func (l DefaultLocale) Required() string { + return `{{.property}} is required` +} + +func (l DefaultLocale) InvalidType() string { + return `Invalid type. Expected: {{.expected}}, given: {{.given}}` +} + +func (l DefaultLocale) NumberAnyOf() string { + return `Must validate at least one schema (anyOf)` +} + +func (l DefaultLocale) NumberOneOf() string { + return `Must validate one and only one schema (oneOf)` +} + +func (l DefaultLocale) NumberAllOf() string { + return `Must validate all the schemas (allOf)` +} + +func (l DefaultLocale) NumberNot() string { + return `Must not validate the schema (not)` +} + +func (l DefaultLocale) MissingDependency() string { + return `Has a dependency on {{.dependency}}` +} + +func (l DefaultLocale) Internal() string { + return `Internal Error {{.error}}` +} + +func (l DefaultLocale) Const() string { + return `{{.field}} does not match: {{.allowed}}` +} + +func (l DefaultLocale) Enum() string { + return `{{.field}} must be one of the following: {{.allowed}}` +} + +func (l DefaultLocale) ArrayNoAdditionalItems() string { + return `No additional items allowed on array` +} + +func (l DefaultLocale) ArrayNotEnoughItems() string { + return `Not enough items on array to match positional list of schema` +} + +func (l DefaultLocale) ArrayMinItems() string { + return `Array must have at least {{.min}} items` +} + +func (l DefaultLocale) ArrayMaxItems() string { + return `Array must have at most {{.max}} items` +} + +func (l DefaultLocale) Unique() string { + return `{{.type}} items must be unique` +} + +func (l DefaultLocale) ArrayContains() string { + return `At least one of the items must match` +} + +func (l DefaultLocale) ArrayMinProperties() string { + return `Must have at least {{.min}} properties` +} + +func (l DefaultLocale) ArrayMaxProperties() string { + return `Must have at most {{.max}} properties` +} + +func (l DefaultLocale) AdditionalPropertyNotAllowed() string { + return `Additional property {{.property}} is not allowed` +} + +func (l DefaultLocale) InvalidPropertyPattern() string { + return `Property "{{.property}}" does not match pattern {{.pattern}}` +} + +func (l DefaultLocale) InvalidPropertyName() string { + return `Property name of "{{.property}}" does not match` +} + +func (l DefaultLocale) StringGTE() string { + return `String length must be greater than or equal to {{.min}}` +} + +func (l DefaultLocale) StringLTE() string { + return `String length must be less than or equal to {{.max}}` +} + +func (l DefaultLocale) DoesNotMatchPattern() string { + return `Does not match pattern '{{.pattern}}'` +} + +func (l DefaultLocale) DoesNotMatchFormat() string { + return `Does not match format '{{.format}}'` +} + +func (l DefaultLocale) MultipleOf() string { + return `Must be a multiple of {{.multiple}}` +} + +func (l DefaultLocale) NumberGTE() string { + return `Must be greater than or equal to {{.min}}` +} + +func (l DefaultLocale) NumberGT() string { + return `Must be greater than {{.min}}` +} + +func (l DefaultLocale) NumberLTE() string { + return `Must be less than or equal to {{.max}}` +} + +func (l DefaultLocale) NumberLT() string { + return `Must be less than {{.max}}` +} + +// Schema validators +func (l DefaultLocale) RegexPattern() string { + return `Invalid regex pattern '{{.pattern}}'` +} + +func (l DefaultLocale) GreaterThanZero() string { + return `{{.number}} must be strictly greater than 0` +} + +func (l DefaultLocale) MustBeOfA() string { + return `{{.x}} must be of a {{.y}}` +} + +func (l DefaultLocale) MustBeOfAn() string { + return `{{.x}} must be of an {{.y}}` +} + +func (l DefaultLocale) CannotBeUsedWithout() string { + return `{{.x}} cannot be used without {{.y}}` +} + +func (l DefaultLocale) CannotBeGT() string { + return `{{.x}} cannot be greater than {{.y}}` +} + +func (l DefaultLocale) MustBeOfType() string { + return `{{.key}} must be of type {{.type}}` +} + +func (l DefaultLocale) MustBeValidRegex() string { + return `{{.key}} must be a valid regex` +} + +func (l DefaultLocale) MustBeValidFormat() string { + return `{{.key}} must be a valid format {{.given}}` +} + +func (l DefaultLocale) MustBeGTEZero() string { + return `{{.key}} must be greater than or equal to 0` +} + +func (l DefaultLocale) KeyCannotBeGreaterThan() string { + return `{{.key}} cannot be greater than {{.y}}` +} + +func (l DefaultLocale) KeyItemsMustBeOfType() string { + return `{{.key}} items must be {{.type}}` +} + +func (l DefaultLocale) KeyItemsMustBeUnique() string { + return `{{.key}} items must be unique` +} + +func (l DefaultLocale) ReferenceMustBeCanonical() string { + return `Reference {{.reference}} must be canonical` +} + +func (l DefaultLocale) NotAValidType() string { + return `has a primitive type that is NOT VALID -- given: {{.given}} Expected valid values are:{{.expected}}` +} + +func (l DefaultLocale) Duplicated() string { + return `{{.type}} type is duplicated` +} + +func (l DefaultLocale) HttpBadStatus() string { + return `Could not read schema from HTTP, response status is {{.status}}` +} + +// Replacement options: field, description, context, value +func (l DefaultLocale) ErrorFormat() string { + return `{{.field}}: {{.description}}` +} + +//Parse error +func (l DefaultLocale) ParseError() string { + return `Expected: {{.expected}}, given: Invalid JSON` +} + +//If/Else +func (l DefaultLocale) ConditionThen() string { + return `Must validate "then" as "if" was valid` +} + +func (l DefaultLocale) ConditionElse() string { + return `Must validate "else" as "if" was not valid` +} + +const ( + STRING_NUMBER = "number" + STRING_ARRAY_OF_STRINGS = "array of strings" + STRING_ARRAY_OF_SCHEMAS = "array of schemas" + STRING_SCHEMA = "valid schema" + STRING_SCHEMA_OR_ARRAY_OF_STRINGS = "schema or array of strings" + STRING_PROPERTIES = "properties" + STRING_DEPENDENCY = "dependency" + STRING_PROPERTY = "property" + STRING_UNDEFINED = "undefined" + STRING_CONTEXT_ROOT = "(root)" + STRING_ROOT_SCHEMA_PROPERTY = "(root)" +) diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/result.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/result.go new file mode 100644 index 0000000000..7896f31299 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/result.go @@ -0,0 +1,195 @@ +// Copyright 2015 xeipuuv ( https://github.com/xeipuuv ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// author xeipuuv +// author-github https://github.com/xeipuuv +// author-mail xeipuuv@gmail.com +// +// repository-name gojsonschema +// repository-desc An implementation of JSON Schema, based on IETF's draft v4 - Go language. +// +// description Result and ResultError implementations. +// +// created 01-01-2015 + +package gojsonschema + +import ( + "fmt" + "strings" +) + +type ( + // ErrorDetails is a map of details specific to each error. + // While the values will vary, every error will contain a "field" value + ErrorDetails map[string]interface{} + + // ResultError is the interface that library errors must implement + ResultError interface { + Field() string + SetType(string) + Type() string + SetContext(*JsonContext) + Context() *JsonContext + SetDescription(string) + Description() string + SetDescriptionFormat(string) + DescriptionFormat() string + SetValue(interface{}) + Value() interface{} + SetDetails(ErrorDetails) + Details() ErrorDetails + String() string + } + + // ResultErrorFields holds the fields for each ResultError implementation. + // ResultErrorFields implements the ResultError interface, so custom errors + // can be defined by just embedding this type + ResultErrorFields struct { + errorType string // A string with the type of error (i.e. invalid_type) + context *JsonContext // Tree like notation of the part that failed the validation. ex (root).a.b ... + description string // A human readable error message + descriptionFormat string // A format for human readable error message + value interface{} // Value given by the JSON file that is the source of the error + details ErrorDetails + } + + Result struct { + errors []ResultError + // Scores how well the validation matched. Useful in generating + // better error messages for anyOf and oneOf. + score int + } +) + +// Field outputs the field name without the root context +// i.e. firstName or person.firstName instead of (root).firstName or (root).person.firstName +func (v *ResultErrorFields) Field() string { + if p, ok := v.Details()["property"]; ok { + if str, isString := p.(string); isString { + return str + } + } + + return strings.TrimPrefix(v.context.String(), STRING_ROOT_SCHEMA_PROPERTY+".") +} + +func (v *ResultErrorFields) SetType(errorType string) { + v.errorType = errorType +} + +func (v *ResultErrorFields) Type() string { + return v.errorType +} + +func (v *ResultErrorFields) SetContext(context *JsonContext) { + v.context = context +} + +func (v *ResultErrorFields) Context() *JsonContext { + return v.context +} + +func (v *ResultErrorFields) SetDescription(description string) { + v.description = description +} + +func (v *ResultErrorFields) Description() string { + return v.description +} + +func (v *ResultErrorFields) SetDescriptionFormat(descriptionFormat string) { + v.descriptionFormat = descriptionFormat +} + +func (v *ResultErrorFields) DescriptionFormat() string { + return v.descriptionFormat +} + +func (v *ResultErrorFields) SetValue(value interface{}) { + v.value = value +} + +func (v *ResultErrorFields) Value() interface{} { + return v.value +} + +func (v *ResultErrorFields) SetDetails(details ErrorDetails) { + v.details = details +} + +func (v *ResultErrorFields) Details() ErrorDetails { + return v.details +} + +func (v ResultErrorFields) String() string { + // as a fallback, the value is displayed go style + valueString := fmt.Sprintf("%v", v.value) + + // marshal the go value value to json + if v.value == nil { + valueString = TYPE_NULL + } else { + if vs, err := marshalToJsonString(v.value); err == nil { + if vs == nil { + valueString = TYPE_NULL + } else { + valueString = *vs + } + } + } + + return formatErrorDescription(Locale.ErrorFormat(), ErrorDetails{ + "context": v.context.String(), + "description": v.description, + "value": valueString, + "field": v.Field(), + }) +} + +func (v *Result) Valid() bool { + return len(v.errors) == 0 +} + +func (v *Result) Errors() []ResultError { + return v.errors +} + +// Add a fully filled error to the error set +// SetDescription() will be called with the result of the parsed err.DescriptionFormat() +func (v *Result) AddError(err ResultError, details ErrorDetails) { + if _, exists := details["context"]; !exists && err.Context() != nil { + details["context"] = err.Context().String() + } + + err.SetDescription(formatErrorDescription(err.DescriptionFormat(), details)) + + v.errors = append(v.errors, err) +} + +func (v *Result) addInternalError(err ResultError, context *JsonContext, value interface{}, details ErrorDetails) { + newError(err, context, value, Locale, details) + v.errors = append(v.errors, err) + v.score -= 2 // results in a net -1 when added to the +1 we get at the end of the validation function +} + +// Used to copy errors from a sub-schema to the main one +func (v *Result) mergeErrors(otherResult *Result) { + v.errors = append(v.errors, otherResult.Errors()...) + v.score += otherResult.score +} + +func (v *Result) incrementScore() { + v.score++ +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/schema.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/schema.go new file mode 100644 index 0000000000..0746a5974e --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/schema.go @@ -0,0 +1,1034 @@ +// Copyright 2015 xeipuuv ( https://github.com/xeipuuv ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// author xeipuuv +// author-github https://github.com/xeipuuv +// author-mail xeipuuv@gmail.com +// +// repository-name gojsonschema +// repository-desc An implementation of JSON Schema, based on IETF's draft v4 - Go language. +// +// description Defines Schema, the main entry to every subSchema. +// Contains the parsing logic and error checking. +// +// created 26-02-2013 + +package gojsonschema + +import ( + "errors" + "math/big" + "reflect" + "regexp" + "text/template" + + "github.com/xeipuuv/gojsonreference" +) + +var ( + // Locale is the default locale to use + // Library users can overwrite with their own implementation + Locale locale = DefaultLocale{} + + // ErrorTemplateFuncs allows you to define custom template funcs for use in localization. + ErrorTemplateFuncs template.FuncMap +) + +func NewSchema(l JSONLoader) (*Schema, error) { + ref, err := l.JsonReference() + if err != nil { + return nil, err + } + + d := Schema{} + d.pool = newSchemaPool(l.LoaderFactory()) + d.documentReference = ref + d.referencePool = newSchemaReferencePool() + + var spd *schemaPoolDocument + var doc interface{} + if ref.String() != "" { + // Get document from schema pool + spd, err = d.pool.GetDocument(d.documentReference) + if err != nil { + return nil, err + } + doc = spd.Document + } else { + // Load JSON directly + doc, err = l.LoadJSON() + if err != nil { + return nil, err + } + } + + d.pool.ParseReferences(doc, ref) + + err = d.parse(doc) + if err != nil { + return nil, err + } + + return &d, nil +} + +type Schema struct { + documentReference gojsonreference.JsonReference + rootSchema *subSchema + pool *schemaPool + referencePool *schemaReferencePool +} + +func (d *Schema) parse(document interface{}) error { + d.rootSchema = &subSchema{property: STRING_ROOT_SCHEMA_PROPERTY} + return d.parseSchema(document, d.rootSchema) +} + +func (d *Schema) SetRootSchemaName(name string) { + d.rootSchema.property = name +} + +// Parses a subSchema +// +// Pretty long function ( sorry :) )... but pretty straight forward, repetitive and boring +// Not much magic involved here, most of the job is to validate the key names and their values, +// then the values are copied into subSchema struct +// +func (d *Schema) parseSchema(documentNode interface{}, currentSchema *subSchema) error { + + // As of draft 6 "true" is equivalent to an empty schema "{}" and false equals "{"not":{}}" + if isKind(documentNode, reflect.Bool) { + b := documentNode.(bool) + if b { + documentNode = map[string]interface{}{} + } else { + documentNode = map[string]interface{}{"not": true} + } + } + + if !isKind(documentNode, reflect.Map) { + return errors.New(formatErrorDescription( + Locale.ParseError(), + ErrorDetails{ + "expected": STRING_SCHEMA, + }, + )) + } + + m := documentNode.(map[string]interface{}) + + if currentSchema.parent == nil { + currentSchema.ref = &d.documentReference + currentSchema.id = &d.documentReference + + if existsMapKey(m, KEY_SCHEMA) && false { + if !isKind(m[KEY_SCHEMA], reflect.String) { + return errors.New(formatErrorDescription( + Locale.InvalidType(), + ErrorDetails{ + "expected": TYPE_STRING, + "given": KEY_SCHEMA, + }, + )) + } + } + } + + if currentSchema.id == nil && currentSchema.parent != nil { + currentSchema.id = currentSchema.parent.id + } + + // In draft 6 the id keyword was renamed to $id + // Use the old id by default + keyID := KEY_ID_NEW + if existsMapKey(m, KEY_ID) { + keyID = KEY_ID + } + if existsMapKey(m, keyID) && !isKind(m[keyID], reflect.String) { + return errors.New(formatErrorDescription( + Locale.InvalidType(), + ErrorDetails{ + "expected": TYPE_STRING, + "given": keyID, + }, + )) + } + if k, ok := m[keyID].(string); ok { + jsonReference, err := gojsonreference.NewJsonReference(k) + if err != nil { + return err + } + if currentSchema == d.rootSchema { + currentSchema.id = &jsonReference + } else { + ref, err := currentSchema.parent.id.Inherits(jsonReference) + if err != nil { + return err + } + currentSchema.id = ref + } + } + + // definitions + if existsMapKey(m, KEY_DEFINITIONS) { + if isKind(m[KEY_DEFINITIONS], reflect.Map, reflect.Bool) { + for _, dv := range m[KEY_DEFINITIONS].(map[string]interface{}) { + if isKind(dv, reflect.Map, reflect.Bool) { + + newSchema := &subSchema{property: KEY_DEFINITIONS, parent: currentSchema} + + err := d.parseSchema(dv, newSchema) + + if err != nil { + return err + } + } else { + return errors.New(formatErrorDescription( + Locale.InvalidType(), + ErrorDetails{ + "expected": STRING_ARRAY_OF_SCHEMAS, + "given": KEY_DEFINITIONS, + }, + )) + } + } + } else { + return errors.New(formatErrorDescription( + Locale.InvalidType(), + ErrorDetails{ + "expected": STRING_ARRAY_OF_SCHEMAS, + "given": KEY_DEFINITIONS, + }, + )) + } + + } + + // title + if existsMapKey(m, KEY_TITLE) && !isKind(m[KEY_TITLE], reflect.String) { + return errors.New(formatErrorDescription( + Locale.InvalidType(), + ErrorDetails{ + "expected": TYPE_STRING, + "given": KEY_TITLE, + }, + )) + } + if k, ok := m[KEY_TITLE].(string); ok { + currentSchema.title = &k + } + + // description + if existsMapKey(m, KEY_DESCRIPTION) && !isKind(m[KEY_DESCRIPTION], reflect.String) { + return errors.New(formatErrorDescription( + Locale.InvalidType(), + ErrorDetails{ + "expected": TYPE_STRING, + "given": KEY_DESCRIPTION, + }, + )) + } + if k, ok := m[KEY_DESCRIPTION].(string); ok { + currentSchema.description = &k + } + + // $ref + if existsMapKey(m, KEY_REF) && !isKind(m[KEY_REF], reflect.String) { + return errors.New(formatErrorDescription( + Locale.InvalidType(), + ErrorDetails{ + "expected": TYPE_STRING, + "given": KEY_REF, + }, + )) + } + + if k, ok := m[KEY_REF].(string); ok { + + jsonReference, err := gojsonreference.NewJsonReference(k) + if err != nil { + return err + } + + currentSchema.ref = &jsonReference + + if sch, ok := d.referencePool.Get(currentSchema.ref.String()); ok { + currentSchema.refSchema = sch + } else { + err := d.parseReference(documentNode, currentSchema) + + if err != nil { + return err + } + + return nil + } + } + + // type + if existsMapKey(m, KEY_TYPE) { + if isKind(m[KEY_TYPE], reflect.String) { + if k, ok := m[KEY_TYPE].(string); ok { + err := currentSchema.types.Add(k) + if err != nil { + return err + } + } + } else { + if isKind(m[KEY_TYPE], reflect.Slice) { + arrayOfTypes := m[KEY_TYPE].([]interface{}) + for _, typeInArray := range arrayOfTypes { + if reflect.ValueOf(typeInArray).Kind() != reflect.String { + return errors.New(formatErrorDescription( + Locale.InvalidType(), + ErrorDetails{ + "expected": TYPE_STRING + "/" + STRING_ARRAY_OF_STRINGS, + "given": KEY_TYPE, + }, + )) + } else { + currentSchema.types.Add(typeInArray.(string)) + } + } + + } else { + return errors.New(formatErrorDescription( + Locale.InvalidType(), + ErrorDetails{ + "expected": TYPE_STRING + "/" + STRING_ARRAY_OF_STRINGS, + "given": KEY_TYPE, + }, + )) + } + } + } + + // properties + if existsMapKey(m, KEY_PROPERTIES) { + err := d.parseProperties(m[KEY_PROPERTIES], currentSchema) + if err != nil { + return err + } + } + + // additionalProperties + if existsMapKey(m, KEY_ADDITIONAL_PROPERTIES) { + if isKind(m[KEY_ADDITIONAL_PROPERTIES], reflect.Bool) { + currentSchema.additionalProperties = m[KEY_ADDITIONAL_PROPERTIES].(bool) + } else if isKind(m[KEY_ADDITIONAL_PROPERTIES], reflect.Map) { + newSchema := &subSchema{property: KEY_ADDITIONAL_PROPERTIES, parent: currentSchema, ref: currentSchema.ref} + currentSchema.additionalProperties = newSchema + err := d.parseSchema(m[KEY_ADDITIONAL_PROPERTIES], newSchema) + if err != nil { + return errors.New(err.Error()) + } + } else { + return errors.New(formatErrorDescription( + Locale.InvalidType(), + ErrorDetails{ + "expected": TYPE_BOOLEAN + "/" + STRING_SCHEMA, + "given": KEY_ADDITIONAL_PROPERTIES, + }, + )) + } + } + + // patternProperties + if existsMapKey(m, KEY_PATTERN_PROPERTIES) { + if isKind(m[KEY_PATTERN_PROPERTIES], reflect.Map) { + patternPropertiesMap := m[KEY_PATTERN_PROPERTIES].(map[string]interface{}) + if len(patternPropertiesMap) > 0 { + currentSchema.patternProperties = make(map[string]*subSchema) + for k, v := range patternPropertiesMap { + _, err := regexp.MatchString(k, "") + if err != nil { + return errors.New(formatErrorDescription( + Locale.RegexPattern(), + ErrorDetails{"pattern": k}, + )) + } + newSchema := &subSchema{property: k, parent: currentSchema, ref: currentSchema.ref} + err = d.parseSchema(v, newSchema) + if err != nil { + return errors.New(err.Error()) + } + currentSchema.patternProperties[k] = newSchema + } + } + } else { + return errors.New(formatErrorDescription( + Locale.InvalidType(), + ErrorDetails{ + "expected": STRING_SCHEMA, + "given": KEY_PATTERN_PROPERTIES, + }, + )) + } + } + + // propertyNames + if existsMapKey(m, KEY_PROPERTY_NAMES) { + if isKind(m[KEY_PROPERTY_NAMES], reflect.Map, reflect.Bool) { + newSchema := &subSchema{property: KEY_PROPERTY_NAMES, parent: currentSchema, ref: currentSchema.ref} + currentSchema.propertyNames = newSchema + err := d.parseSchema(m[KEY_PROPERTY_NAMES], newSchema) + if err != nil { + return err + } + } else { + return errors.New(formatErrorDescription( + Locale.InvalidType(), + ErrorDetails{ + "expected": STRING_SCHEMA, + "given": KEY_PATTERN_PROPERTIES, + }, + )) + } + } + + // dependencies + if existsMapKey(m, KEY_DEPENDENCIES) { + err := d.parseDependencies(m[KEY_DEPENDENCIES], currentSchema) + if err != nil { + return err + } + } + + // items + if existsMapKey(m, KEY_ITEMS) { + if isKind(m[KEY_ITEMS], reflect.Slice) { + for _, itemElement := range m[KEY_ITEMS].([]interface{}) { + if isKind(itemElement, reflect.Map, reflect.Bool) { + newSchema := &subSchema{parent: currentSchema, property: KEY_ITEMS} + newSchema.ref = currentSchema.ref + currentSchema.AddItemsChild(newSchema) + err := d.parseSchema(itemElement, newSchema) + if err != nil { + return err + } + } else { + return errors.New(formatErrorDescription( + Locale.InvalidType(), + ErrorDetails{ + "expected": STRING_SCHEMA + "/" + STRING_ARRAY_OF_SCHEMAS, + "given": KEY_ITEMS, + }, + )) + } + currentSchema.itemsChildrenIsSingleSchema = false + } + } else if isKind(m[KEY_ITEMS], reflect.Map, reflect.Bool) { + newSchema := &subSchema{parent: currentSchema, property: KEY_ITEMS} + newSchema.ref = currentSchema.ref + currentSchema.AddItemsChild(newSchema) + err := d.parseSchema(m[KEY_ITEMS], newSchema) + if err != nil { + return err + } + currentSchema.itemsChildrenIsSingleSchema = true + } else { + return errors.New(formatErrorDescription( + Locale.InvalidType(), + ErrorDetails{ + "expected": STRING_SCHEMA + "/" + STRING_ARRAY_OF_SCHEMAS, + "given": KEY_ITEMS, + }, + )) + } + } + + // additionalItems + if existsMapKey(m, KEY_ADDITIONAL_ITEMS) { + if isKind(m[KEY_ADDITIONAL_ITEMS], reflect.Bool) { + currentSchema.additionalItems = m[KEY_ADDITIONAL_ITEMS].(bool) + } else if isKind(m[KEY_ADDITIONAL_ITEMS], reflect.Map) { + newSchema := &subSchema{property: KEY_ADDITIONAL_ITEMS, parent: currentSchema, ref: currentSchema.ref} + currentSchema.additionalItems = newSchema + err := d.parseSchema(m[KEY_ADDITIONAL_ITEMS], newSchema) + if err != nil { + return errors.New(err.Error()) + } + } else { + return errors.New(formatErrorDescription( + Locale.InvalidType(), + ErrorDetails{ + "expected": TYPE_BOOLEAN + "/" + STRING_SCHEMA, + "given": KEY_ADDITIONAL_ITEMS, + }, + )) + } + } + + // validation : number / integer + + if existsMapKey(m, KEY_MULTIPLE_OF) { + multipleOfValue := mustBeNumber(m[KEY_MULTIPLE_OF]) + if multipleOfValue == nil { + return errors.New(formatErrorDescription( + Locale.InvalidType(), + ErrorDetails{ + "expected": STRING_NUMBER, + "given": KEY_MULTIPLE_OF, + }, + )) + } + if multipleOfValue.Cmp(big.NewFloat(0)) <= 0 { + return errors.New(formatErrorDescription( + Locale.GreaterThanZero(), + ErrorDetails{"number": KEY_MULTIPLE_OF}, + )) + } + currentSchema.multipleOf = multipleOfValue + } + + if existsMapKey(m, KEY_MINIMUM) { + minimumValue := mustBeNumber(m[KEY_MINIMUM]) + if minimumValue == nil { + return errors.New(formatErrorDescription( + Locale.MustBeOfA(), + ErrorDetails{"x": KEY_MINIMUM, "y": STRING_NUMBER}, + )) + } + currentSchema.minimum = minimumValue + } + + if existsMapKey(m, KEY_EXCLUSIVE_MINIMUM) { + if isKind(m[KEY_EXCLUSIVE_MINIMUM], reflect.Bool) { + if currentSchema.minimum == nil { + return errors.New(formatErrorDescription( + Locale.CannotBeUsedWithout(), + ErrorDetails{"x": KEY_EXCLUSIVE_MINIMUM, "y": KEY_MINIMUM}, + )) + } + exclusiveMinimumValue := m[KEY_EXCLUSIVE_MINIMUM].(bool) + currentSchema.exclusiveMinimum = exclusiveMinimumValue + } else if isJsonNumber(m[KEY_EXCLUSIVE_MINIMUM]) { + minimumValue := mustBeNumber(m[KEY_EXCLUSIVE_MINIMUM]) + + currentSchema.minimum = minimumValue + currentSchema.exclusiveMinimum = true + } else { + return errors.New(formatErrorDescription( + Locale.InvalidType(), + ErrorDetails{"expected": TYPE_BOOLEAN + ", " + TYPE_NUMBER, "given": KEY_EXCLUSIVE_MINIMUM}, + )) + } + } + + if existsMapKey(m, KEY_MAXIMUM) { + maximumValue := mustBeNumber(m[KEY_MAXIMUM]) + if maximumValue == nil { + return errors.New(formatErrorDescription( + Locale.MustBeOfA(), + ErrorDetails{"x": KEY_MAXIMUM, "y": STRING_NUMBER}, + )) + } + currentSchema.maximum = maximumValue + } + + if existsMapKey(m, KEY_EXCLUSIVE_MAXIMUM) { + if isKind(m[KEY_EXCLUSIVE_MAXIMUM], reflect.Bool) { + if currentSchema.maximum == nil { + return errors.New(formatErrorDescription( + Locale.CannotBeUsedWithout(), + ErrorDetails{"x": KEY_EXCLUSIVE_MAXIMUM, "y": KEY_MAXIMUM}, + )) + } + exclusiveMaximumValue := m[KEY_EXCLUSIVE_MAXIMUM].(bool) + currentSchema.exclusiveMaximum = exclusiveMaximumValue + } else if isJsonNumber(m[KEY_EXCLUSIVE_MAXIMUM]) { + maximumValue := mustBeNumber(m[KEY_EXCLUSIVE_MAXIMUM]) + + currentSchema.maximum = maximumValue + currentSchema.exclusiveMaximum = true + } else { + return errors.New(formatErrorDescription( + Locale.InvalidType(), + ErrorDetails{"expected": TYPE_BOOLEAN + ", " + TYPE_NUMBER, "given": KEY_EXCLUSIVE_MAXIMUM}, + )) + } + } + + if currentSchema.minimum != nil && currentSchema.maximum != nil { + if currentSchema.minimum.Cmp(currentSchema.maximum) == 1 { + return errors.New(formatErrorDescription( + Locale.CannotBeGT(), + ErrorDetails{"x": KEY_MINIMUM, "y": KEY_MAXIMUM}, + )) + } + } + + // validation : string + + if existsMapKey(m, KEY_MIN_LENGTH) { + minLengthIntegerValue := mustBeInteger(m[KEY_MIN_LENGTH]) + if minLengthIntegerValue == nil { + return errors.New(formatErrorDescription( + Locale.MustBeOfAn(), + ErrorDetails{"x": KEY_MIN_LENGTH, "y": TYPE_INTEGER}, + )) + } + if *minLengthIntegerValue < 0 { + return errors.New(formatErrorDescription( + Locale.MustBeGTEZero(), + ErrorDetails{"key": KEY_MIN_LENGTH}, + )) + } + currentSchema.minLength = minLengthIntegerValue + } + + if existsMapKey(m, KEY_MAX_LENGTH) { + maxLengthIntegerValue := mustBeInteger(m[KEY_MAX_LENGTH]) + if maxLengthIntegerValue == nil { + return errors.New(formatErrorDescription( + Locale.MustBeOfAn(), + ErrorDetails{"x": KEY_MAX_LENGTH, "y": TYPE_INTEGER}, + )) + } + if *maxLengthIntegerValue < 0 { + return errors.New(formatErrorDescription( + Locale.MustBeGTEZero(), + ErrorDetails{"key": KEY_MAX_LENGTH}, + )) + } + currentSchema.maxLength = maxLengthIntegerValue + } + + if currentSchema.minLength != nil && currentSchema.maxLength != nil { + if *currentSchema.minLength > *currentSchema.maxLength { + return errors.New(formatErrorDescription( + Locale.CannotBeGT(), + ErrorDetails{"x": KEY_MIN_LENGTH, "y": KEY_MAX_LENGTH}, + )) + } + } + + if existsMapKey(m, KEY_PATTERN) { + if isKind(m[KEY_PATTERN], reflect.String) { + regexpObject, err := regexp.Compile(m[KEY_PATTERN].(string)) + if err != nil { + return errors.New(formatErrorDescription( + Locale.MustBeValidRegex(), + ErrorDetails{"key": KEY_PATTERN}, + )) + } + currentSchema.pattern = regexpObject + } else { + return errors.New(formatErrorDescription( + Locale.MustBeOfA(), + ErrorDetails{"x": KEY_PATTERN, "y": TYPE_STRING}, + )) + } + } + + if existsMapKey(m, KEY_FORMAT) { + formatString, ok := m[KEY_FORMAT].(string) + if ok && FormatCheckers.Has(formatString) { + currentSchema.format = formatString + } + } + + // validation : object + + if existsMapKey(m, KEY_MIN_PROPERTIES) { + minPropertiesIntegerValue := mustBeInteger(m[KEY_MIN_PROPERTIES]) + if minPropertiesIntegerValue == nil { + return errors.New(formatErrorDescription( + Locale.MustBeOfAn(), + ErrorDetails{"x": KEY_MIN_PROPERTIES, "y": TYPE_INTEGER}, + )) + } + if *minPropertiesIntegerValue < 0 { + return errors.New(formatErrorDescription( + Locale.MustBeGTEZero(), + ErrorDetails{"key": KEY_MIN_PROPERTIES}, + )) + } + currentSchema.minProperties = minPropertiesIntegerValue + } + + if existsMapKey(m, KEY_MAX_PROPERTIES) { + maxPropertiesIntegerValue := mustBeInteger(m[KEY_MAX_PROPERTIES]) + if maxPropertiesIntegerValue == nil { + return errors.New(formatErrorDescription( + Locale.MustBeOfAn(), + ErrorDetails{"x": KEY_MAX_PROPERTIES, "y": TYPE_INTEGER}, + )) + } + if *maxPropertiesIntegerValue < 0 { + return errors.New(formatErrorDescription( + Locale.MustBeGTEZero(), + ErrorDetails{"key": KEY_MAX_PROPERTIES}, + )) + } + currentSchema.maxProperties = maxPropertiesIntegerValue + } + + if currentSchema.minProperties != nil && currentSchema.maxProperties != nil { + if *currentSchema.minProperties > *currentSchema.maxProperties { + return errors.New(formatErrorDescription( + Locale.KeyCannotBeGreaterThan(), + ErrorDetails{"key": KEY_MIN_PROPERTIES, "y": KEY_MAX_PROPERTIES}, + )) + } + } + + if existsMapKey(m, KEY_REQUIRED) { + if isKind(m[KEY_REQUIRED], reflect.Slice) { + requiredValues := m[KEY_REQUIRED].([]interface{}) + for _, requiredValue := range requiredValues { + if isKind(requiredValue, reflect.String) { + err := currentSchema.AddRequired(requiredValue.(string)) + if err != nil { + return err + } + } else { + return errors.New(formatErrorDescription( + Locale.KeyItemsMustBeOfType(), + ErrorDetails{"key": KEY_REQUIRED, "type": TYPE_STRING}, + )) + } + } + } else { + return errors.New(formatErrorDescription( + Locale.MustBeOfAn(), + ErrorDetails{"x": KEY_REQUIRED, "y": TYPE_ARRAY}, + )) + } + } + + // validation : array + + if existsMapKey(m, KEY_MIN_ITEMS) { + minItemsIntegerValue := mustBeInteger(m[KEY_MIN_ITEMS]) + if minItemsIntegerValue == nil { + return errors.New(formatErrorDescription( + Locale.MustBeOfAn(), + ErrorDetails{"x": KEY_MIN_ITEMS, "y": TYPE_INTEGER}, + )) + } + if *minItemsIntegerValue < 0 { + return errors.New(formatErrorDescription( + Locale.MustBeGTEZero(), + ErrorDetails{"key": KEY_MIN_ITEMS}, + )) + } + currentSchema.minItems = minItemsIntegerValue + } + + if existsMapKey(m, KEY_MAX_ITEMS) { + maxItemsIntegerValue := mustBeInteger(m[KEY_MAX_ITEMS]) + if maxItemsIntegerValue == nil { + return errors.New(formatErrorDescription( + Locale.MustBeOfAn(), + ErrorDetails{"x": KEY_MAX_ITEMS, "y": TYPE_INTEGER}, + )) + } + if *maxItemsIntegerValue < 0 { + return errors.New(formatErrorDescription( + Locale.MustBeGTEZero(), + ErrorDetails{"key": KEY_MAX_ITEMS}, + )) + } + currentSchema.maxItems = maxItemsIntegerValue + } + + if existsMapKey(m, KEY_UNIQUE_ITEMS) { + if isKind(m[KEY_UNIQUE_ITEMS], reflect.Bool) { + currentSchema.uniqueItems = m[KEY_UNIQUE_ITEMS].(bool) + } else { + return errors.New(formatErrorDescription( + Locale.MustBeOfA(), + ErrorDetails{"x": KEY_UNIQUE_ITEMS, "y": TYPE_BOOLEAN}, + )) + } + } + + if existsMapKey(m, KEY_CONTAINS) { + newSchema := &subSchema{property: KEY_CONTAINS, parent: currentSchema, ref: currentSchema.ref} + currentSchema.contains = newSchema + err := d.parseSchema(m[KEY_CONTAINS], newSchema) + if err != nil { + return err + } + } + + // validation : all + + if existsMapKey(m, KEY_CONST) { + err := currentSchema.AddConst(m[KEY_CONST]) + if err != nil { + return err + } + } + + if existsMapKey(m, KEY_ENUM) { + if isKind(m[KEY_ENUM], reflect.Slice) { + for _, v := range m[KEY_ENUM].([]interface{}) { + err := currentSchema.AddEnum(v) + if err != nil { + return err + } + } + } else { + return errors.New(formatErrorDescription( + Locale.MustBeOfAn(), + ErrorDetails{"x": KEY_ENUM, "y": TYPE_ARRAY}, + )) + } + } + + // validation : subSchema + + if existsMapKey(m, KEY_ONE_OF) { + if isKind(m[KEY_ONE_OF], reflect.Slice) { + for _, v := range m[KEY_ONE_OF].([]interface{}) { + newSchema := &subSchema{property: KEY_ONE_OF, parent: currentSchema, ref: currentSchema.ref} + currentSchema.AddOneOf(newSchema) + err := d.parseSchema(v, newSchema) + if err != nil { + return err + } + } + } else { + return errors.New(formatErrorDescription( + Locale.MustBeOfAn(), + ErrorDetails{"x": KEY_ONE_OF, "y": TYPE_ARRAY}, + )) + } + } + + if existsMapKey(m, KEY_ANY_OF) { + if isKind(m[KEY_ANY_OF], reflect.Slice) { + for _, v := range m[KEY_ANY_OF].([]interface{}) { + newSchema := &subSchema{property: KEY_ANY_OF, parent: currentSchema, ref: currentSchema.ref} + currentSchema.AddAnyOf(newSchema) + err := d.parseSchema(v, newSchema) + if err != nil { + return err + } + } + } else { + return errors.New(formatErrorDescription( + Locale.MustBeOfAn(), + ErrorDetails{"x": KEY_ANY_OF, "y": TYPE_ARRAY}, + )) + } + } + + if existsMapKey(m, KEY_ALL_OF) { + if isKind(m[KEY_ALL_OF], reflect.Slice) { + for _, v := range m[KEY_ALL_OF].([]interface{}) { + newSchema := &subSchema{property: KEY_ALL_OF, parent: currentSchema, ref: currentSchema.ref} + currentSchema.AddAllOf(newSchema) + err := d.parseSchema(v, newSchema) + if err != nil { + return err + } + } + } else { + return errors.New(formatErrorDescription( + Locale.MustBeOfAn(), + ErrorDetails{"x": KEY_ANY_OF, "y": TYPE_ARRAY}, + )) + } + } + + if existsMapKey(m, KEY_NOT) { + if isKind(m[KEY_NOT], reflect.Map, reflect.Bool) { + newSchema := &subSchema{property: KEY_NOT, parent: currentSchema, ref: currentSchema.ref} + currentSchema.SetNot(newSchema) + err := d.parseSchema(m[KEY_NOT], newSchema) + if err != nil { + return err + } + } else { + return errors.New(formatErrorDescription( + Locale.MustBeOfAn(), + ErrorDetails{"x": KEY_NOT, "y": TYPE_OBJECT}, + )) + } + } + + if existsMapKey(m, KEY_IF) { + if isKind(m[KEY_IF], reflect.Map, reflect.Bool) { + newSchema := &subSchema{property: KEY_IF, parent: currentSchema, ref: currentSchema.ref} + currentSchema.SetIf(newSchema) + err := d.parseSchema(m[KEY_IF], newSchema) + if err != nil { + return err + } + } else { + return errors.New(formatErrorDescription( + Locale.MustBeOfAn(), + ErrorDetails{"x": KEY_IF, "y": TYPE_OBJECT}, + )) + } + } + + if existsMapKey(m, KEY_THEN) { + if isKind(m[KEY_THEN], reflect.Map, reflect.Bool) { + newSchema := &subSchema{property: KEY_THEN, parent: currentSchema, ref: currentSchema.ref} + currentSchema.SetThen(newSchema) + err := d.parseSchema(m[KEY_THEN], newSchema) + if err != nil { + return err + } + } else { + return errors.New(formatErrorDescription( + Locale.MustBeOfAn(), + ErrorDetails{"x": KEY_THEN, "y": TYPE_OBJECT}, + )) + } + } + + if existsMapKey(m, KEY_ELSE) { + if isKind(m[KEY_ELSE], reflect.Map, reflect.Bool) { + newSchema := &subSchema{property: KEY_ELSE, parent: currentSchema, ref: currentSchema.ref} + currentSchema.SetElse(newSchema) + err := d.parseSchema(m[KEY_ELSE], newSchema) + if err != nil { + return err + } + } else { + return errors.New(formatErrorDescription( + Locale.MustBeOfAn(), + ErrorDetails{"x": KEY_ELSE, "y": TYPE_OBJECT}, + )) + } + } + + return nil +} + +func (d *Schema) parseReference(documentNode interface{}, currentSchema *subSchema) error { + var ( + refdDocumentNode interface{} + dsp *schemaPoolDocument + err error + ) + + newSchema := &subSchema{property: KEY_REF, parent: currentSchema, ref: currentSchema.ref} + + d.referencePool.Add(currentSchema.ref.String(), newSchema) + + dsp, err = d.pool.GetDocument(*currentSchema.ref) + if err != nil { + return err + } + newSchema.id = currentSchema.ref + + refdDocumentNode = dsp.Document + + if err != nil { + return err + } + + if !isKind(refdDocumentNode, reflect.Map, reflect.Bool) { + return errors.New(formatErrorDescription( + Locale.MustBeOfType(), + ErrorDetails{"key": STRING_SCHEMA, "type": TYPE_OBJECT}, + )) + } + + err = d.parseSchema(refdDocumentNode, newSchema) + if err != nil { + return err + } + + currentSchema.refSchema = newSchema + + return nil + +} + +func (d *Schema) parseProperties(documentNode interface{}, currentSchema *subSchema) error { + + if !isKind(documentNode, reflect.Map) { + return errors.New(formatErrorDescription( + Locale.MustBeOfType(), + ErrorDetails{"key": STRING_PROPERTIES, "type": TYPE_OBJECT}, + )) + } + + m := documentNode.(map[string]interface{}) + for k := range m { + schemaProperty := k + newSchema := &subSchema{property: schemaProperty, parent: currentSchema, ref: currentSchema.ref} + currentSchema.AddPropertiesChild(newSchema) + err := d.parseSchema(m[k], newSchema) + if err != nil { + return err + } + } + + return nil +} + +func (d *Schema) parseDependencies(documentNode interface{}, currentSchema *subSchema) error { + + if !isKind(documentNode, reflect.Map) { + return errors.New(formatErrorDescription( + Locale.MustBeOfType(), + ErrorDetails{"key": KEY_DEPENDENCIES, "type": TYPE_OBJECT}, + )) + } + + m := documentNode.(map[string]interface{}) + currentSchema.dependencies = make(map[string]interface{}) + + for k := range m { + switch reflect.ValueOf(m[k]).Kind() { + + case reflect.Slice: + values := m[k].([]interface{}) + var valuesToRegister []string + + for _, value := range values { + if !isKind(value, reflect.String) { + return errors.New(formatErrorDescription( + Locale.MustBeOfType(), + ErrorDetails{ + "key": STRING_DEPENDENCY, + "type": STRING_SCHEMA_OR_ARRAY_OF_STRINGS, + }, + )) + } else { + valuesToRegister = append(valuesToRegister, value.(string)) + } + currentSchema.dependencies[k] = valuesToRegister + } + + case reflect.Map, reflect.Bool: + depSchema := &subSchema{property: k, parent: currentSchema, ref: currentSchema.ref} + err := d.parseSchema(m[k], depSchema) + if err != nil { + return err + } + currentSchema.dependencies[k] = depSchema + + default: + return errors.New(formatErrorDescription( + Locale.MustBeOfType(), + ErrorDetails{ + "key": STRING_DEPENDENCY, + "type": STRING_SCHEMA_OR_ARRAY_OF_STRINGS, + }, + )) + } + + } + + return nil +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/schemaPool.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/schemaPool.go new file mode 100644 index 0000000000..65c91e457d --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/schemaPool.go @@ -0,0 +1,192 @@ +// Copyright 2015 xeipuuv ( https://github.com/xeipuuv ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// author xeipuuv +// author-github https://github.com/xeipuuv +// author-mail xeipuuv@gmail.com +// +// repository-name gojsonschema +// repository-desc An implementation of JSON Schema, based on IETF's draft v4 - Go language. +// +// description Defines resources pooling. +// Eases referencing and avoids downloading the same resource twice. +// +// created 26-02-2013 + +package gojsonschema + +import ( + "errors" + "reflect" + + "github.com/xeipuuv/gojsonreference" +) + +type schemaPoolDocument struct { + Document interface{} +} + +type schemaPool struct { + schemaPoolDocuments map[string]*schemaPoolDocument + jsonLoaderFactory JSONLoaderFactory +} + +func newSchemaPool(f JSONLoaderFactory) *schemaPool { + + p := &schemaPool{} + p.schemaPoolDocuments = make(map[string]*schemaPoolDocument) + p.jsonLoaderFactory = f + + return p +} + +func (p *schemaPool) ParseReferences(document interface{}, ref gojsonreference.JsonReference) { + // Only the root document should be added to the schema pool + p.schemaPoolDocuments[ref.String()] = &schemaPoolDocument{Document: document} + p.parseReferencesRecursive(document, ref) +} + +func (p *schemaPool) parseReferencesRecursive(document interface{}, ref gojsonreference.JsonReference) { + // parseReferencesRecursive parses a JSON document and resolves all $id and $ref references. + // For $ref references it takes into account the $id scope it is in and replaces + // the reference by the absolute resolved reference + + // When encountering errors it fails silently. Error handling is done when the schema + // is syntactically parsed and any error encountered here should also come up there. + switch m := document.(type) { + case []interface{}: + for _, v := range m { + p.parseReferencesRecursive(v, ref) + } + case map[string]interface{}: + localRef := &ref + + keyID := KEY_ID_NEW + if existsMapKey(m, KEY_ID) { + keyID = KEY_ID + } + if existsMapKey(m, keyID) && isKind(m[keyID], reflect.String) { + jsonReference, err := gojsonreference.NewJsonReference(m[keyID].(string)) + if err == nil { + localRef, err = ref.Inherits(jsonReference) + if err == nil { + p.schemaPoolDocuments[localRef.String()] = &schemaPoolDocument{Document: document} + } + } + } + + if existsMapKey(m, KEY_REF) && isKind(m[KEY_REF], reflect.String) { + jsonReference, err := gojsonreference.NewJsonReference(m[KEY_REF].(string)) + if err == nil { + absoluteRef, err := localRef.Inherits(jsonReference) + if err == nil { + m[KEY_REF] = absoluteRef.String() + } + } + } + + for k, v := range m { + // const and enums should be interpreted literally, so ignore them + if k == KEY_CONST || k == KEY_ENUM { + continue + } + // Something like a property or a dependency is not a valid schema, as it might describe properties named "$ref", "$id" or "const", etc + // Therefore don't treat it like a schema. + if k == KEY_PROPERTIES || k == KEY_DEPENDENCIES || k == KEY_PATTERN_PROPERTIES { + if child, ok := v.(map[string]interface{}); ok { + for _, v := range child { + p.parseReferencesRecursive(v, *localRef) + } + } + } else { + p.parseReferencesRecursive(v, *localRef) + } + } + } +} + +func (p *schemaPool) GetDocument(reference gojsonreference.JsonReference) (*schemaPoolDocument, error) { + + var ( + spd *schemaPoolDocument + ok bool + err error + ) + + if internalLogEnabled { + internalLog("Get Document ( %s )", reference.String()) + } + + // Create a deep copy, so we can remove the fragment part later on without altering the original + refToUrl, _ := gojsonreference.NewJsonReference(reference.String()) + + // First check if the given fragment is a location independent identifier + // http://json-schema.org/latest/json-schema-core.html#rfc.section.8.2.3 + + if spd, ok = p.schemaPoolDocuments[refToUrl.String()]; ok { + if internalLogEnabled { + internalLog(" From pool") + } + return spd, nil + } + + // If the given reference is not a location independent identifier, + // strip the fragment and look for a document with it's base URI + + refToUrl.GetUrl().Fragment = "" + + if cachedSpd, ok := p.schemaPoolDocuments[refToUrl.String()]; ok { + document, _, err := reference.GetPointer().Get(cachedSpd.Document) + + if err != nil { + return nil, err + } + + if internalLogEnabled { + internalLog(" From pool") + } + + spd = &schemaPoolDocument{Document: document} + p.schemaPoolDocuments[reference.String()] = spd + + return spd, nil + } + + // It is not possible to load anything remotely that is not canonical... + if !reference.IsCanonical() { + return nil, errors.New(formatErrorDescription( + Locale.ReferenceMustBeCanonical(), + ErrorDetails{"reference": reference.String()}, + )) + } + + jsonReferenceLoader := p.jsonLoaderFactory.New(reference.String()) + document, err := jsonReferenceLoader.LoadJSON() + + if err != nil { + return nil, err + } + + // add the whole document to the pool for potential re-use + p.ParseReferences(document, refToUrl) + + // resolve the potential fragment and also cache it + document, _, err = reference.GetPointer().Get(document) + + if err != nil { + return nil, err + } + + return &schemaPoolDocument{Document: document}, nil +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/schemaReferencePool.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/schemaReferencePool.go new file mode 100644 index 0000000000..6e5e1b5cdb --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/schemaReferencePool.go @@ -0,0 +1,68 @@ +// Copyright 2015 xeipuuv ( https://github.com/xeipuuv ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// author xeipuuv +// author-github https://github.com/xeipuuv +// author-mail xeipuuv@gmail.com +// +// repository-name gojsonschema +// repository-desc An implementation of JSON Schema, based on IETF's draft v4 - Go language. +// +// description Pool of referenced schemas. +// +// created 25-06-2013 + +package gojsonschema + +import ( + "fmt" +) + +type schemaReferencePool struct { + documents map[string]*subSchema +} + +func newSchemaReferencePool() *schemaReferencePool { + + p := &schemaReferencePool{} + p.documents = make(map[string]*subSchema) + + return p +} + +func (p *schemaReferencePool) Get(ref string) (r *subSchema, o bool) { + + if internalLogEnabled { + internalLog(fmt.Sprintf("Schema Reference ( %s )", ref)) + } + + if sch, ok := p.documents[ref]; ok { + if internalLogEnabled { + internalLog(fmt.Sprintf(" From pool")) + } + return sch, true + } + + return nil, false +} + +func (p *schemaReferencePool) Add(ref string, sch *subSchema) { + + if internalLogEnabled { + internalLog(fmt.Sprintf("Add Schema Reference %s to pool", ref)) + } + if _, ok := p.documents[ref]; !ok { + p.documents[ref] = sch + } +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/schemaType.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/schemaType.go new file mode 100644 index 0000000000..36b447a291 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/schemaType.go @@ -0,0 +1,83 @@ +// Copyright 2015 xeipuuv ( https://github.com/xeipuuv ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// author xeipuuv +// author-github https://github.com/xeipuuv +// author-mail xeipuuv@gmail.com +// +// repository-name gojsonschema +// repository-desc An implementation of JSON Schema, based on IETF's draft v4 - Go language. +// +// description Helper structure to handle schema types, and the combination of them. +// +// created 28-02-2013 + +package gojsonschema + +import ( + "errors" + "fmt" + "strings" +) + +type jsonSchemaType struct { + types []string +} + +// Is the schema typed ? that is containing at least one type +// When not typed, the schema does not need any type validation +func (t *jsonSchemaType) IsTyped() bool { + return len(t.types) > 0 +} + +func (t *jsonSchemaType) Add(etype string) error { + + if !isStringInSlice(JSON_TYPES, etype) { + return errors.New(formatErrorDescription(Locale.NotAValidType(), ErrorDetails{"given": "/" + etype + "/", "expected": JSON_TYPES})) + } + + if t.Contains(etype) { + return errors.New(formatErrorDescription(Locale.Duplicated(), ErrorDetails{"type": etype})) + } + + t.types = append(t.types, etype) + + return nil +} + +func (t *jsonSchemaType) Contains(etype string) bool { + + for _, v := range t.types { + if v == etype { + return true + } + } + + return false +} + +func (t *jsonSchemaType) String() string { + + if len(t.types) == 0 { + return STRING_UNDEFINED // should never happen + } + + // Displayed as a list [type1,type2,...] + if len(t.types) > 1 { + return fmt.Sprintf("[%s]", strings.Join(t.types, ",")) + } + + // Only one type: name only + return t.types[0] +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/subSchema.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/subSchema.go new file mode 100644 index 0000000000..ea792a111a --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/subSchema.go @@ -0,0 +1,255 @@ +// Copyright 2015 xeipuuv ( https://github.com/xeipuuv ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// author xeipuuv +// author-github https://github.com/xeipuuv +// author-mail xeipuuv@gmail.com +// +// repository-name gojsonschema +// repository-desc An implementation of JSON Schema, based on IETF's draft v4 - Go language. +// +// description Defines the structure of a sub-subSchema. +// A sub-subSchema can contain other sub-schemas. +// +// created 27-02-2013 + +package gojsonschema + +import ( + "errors" + "math/big" + "regexp" + "strings" + + "github.com/xeipuuv/gojsonreference" +) + +const ( + KEY_SCHEMA = "$schema" + KEY_ID = "id" + KEY_ID_NEW = "$id" + KEY_REF = "$ref" + KEY_TITLE = "title" + KEY_DESCRIPTION = "description" + KEY_TYPE = "type" + KEY_ITEMS = "items" + KEY_ADDITIONAL_ITEMS = "additionalItems" + KEY_PROPERTIES = "properties" + KEY_PATTERN_PROPERTIES = "patternProperties" + KEY_ADDITIONAL_PROPERTIES = "additionalProperties" + KEY_PROPERTY_NAMES = "propertyNames" + KEY_DEFINITIONS = "definitions" + KEY_MULTIPLE_OF = "multipleOf" + KEY_MINIMUM = "minimum" + KEY_MAXIMUM = "maximum" + KEY_EXCLUSIVE_MINIMUM = "exclusiveMinimum" + KEY_EXCLUSIVE_MAXIMUM = "exclusiveMaximum" + KEY_MIN_LENGTH = "minLength" + KEY_MAX_LENGTH = "maxLength" + KEY_PATTERN = "pattern" + KEY_FORMAT = "format" + KEY_MIN_PROPERTIES = "minProperties" + KEY_MAX_PROPERTIES = "maxProperties" + KEY_DEPENDENCIES = "dependencies" + KEY_REQUIRED = "required" + KEY_MIN_ITEMS = "minItems" + KEY_MAX_ITEMS = "maxItems" + KEY_UNIQUE_ITEMS = "uniqueItems" + KEY_CONTAINS = "contains" + KEY_CONST = "const" + KEY_ENUM = "enum" + KEY_ONE_OF = "oneOf" + KEY_ANY_OF = "anyOf" + KEY_ALL_OF = "allOf" + KEY_NOT = "not" + KEY_IF = "if" + KEY_THEN = "then" + KEY_ELSE = "else" +) + +type subSchema struct { + + // basic subSchema meta properties + id *gojsonreference.JsonReference + title *string + description *string + + property string + + // Types associated with the subSchema + types jsonSchemaType + + // Reference url + ref *gojsonreference.JsonReference + // Schema referenced + refSchema *subSchema + + // hierarchy + parent *subSchema + itemsChildren []*subSchema + itemsChildrenIsSingleSchema bool + propertiesChildren []*subSchema + + // validation : number / integer + multipleOf *big.Float + maximum *big.Float + exclusiveMaximum bool + minimum *big.Float + exclusiveMinimum bool + + // validation : string + minLength *int + maxLength *int + pattern *regexp.Regexp + format string + + // validation : object + minProperties *int + maxProperties *int + required []string + + dependencies map[string]interface{} + additionalProperties interface{} + patternProperties map[string]*subSchema + propertyNames *subSchema + + // validation : array + minItems *int + maxItems *int + uniqueItems bool + contains *subSchema + + additionalItems interface{} + + // validation : all + _const *string //const is a golang keyword + enum []string + + // validation : subSchema + oneOf []*subSchema + anyOf []*subSchema + allOf []*subSchema + not *subSchema + _if *subSchema // if/else are golang keywords + _then *subSchema + _else *subSchema +} + +func (s *subSchema) AddConst(i interface{}) error { + + is, err := marshalWithoutNumber(i) + if err != nil { + return err + } + s._const = is + return nil +} + +func (s *subSchema) AddEnum(i interface{}) error { + + is, err := marshalWithoutNumber(i) + if err != nil { + return err + } + + if isStringInSlice(s.enum, *is) { + return errors.New(formatErrorDescription( + Locale.KeyItemsMustBeUnique(), + ErrorDetails{"key": KEY_ENUM}, + )) + } + + s.enum = append(s.enum, *is) + + return nil +} + +func (s *subSchema) ContainsEnum(i interface{}) (bool, error) { + + is, err := marshalWithoutNumber(i) + if err != nil { + return false, err + } + + return isStringInSlice(s.enum, *is), nil +} + +func (s *subSchema) AddOneOf(subSchema *subSchema) { + s.oneOf = append(s.oneOf, subSchema) +} + +func (s *subSchema) AddAllOf(subSchema *subSchema) { + s.allOf = append(s.allOf, subSchema) +} + +func (s *subSchema) AddAnyOf(subSchema *subSchema) { + s.anyOf = append(s.anyOf, subSchema) +} + +func (s *subSchema) SetNot(subSchema *subSchema) { + s.not = subSchema +} + +func (s *subSchema) SetIf(subSchema *subSchema) { + s._if = subSchema +} + +func (s *subSchema) SetThen(subSchema *subSchema) { + s._then = subSchema +} + +func (s *subSchema) SetElse(subSchema *subSchema) { + s._else = subSchema +} + +func (s *subSchema) AddRequired(value string) error { + + if isStringInSlice(s.required, value) { + return errors.New(formatErrorDescription( + Locale.KeyItemsMustBeUnique(), + ErrorDetails{"key": KEY_REQUIRED}, + )) + } + + s.required = append(s.required, value) + + return nil +} + +func (s *subSchema) AddItemsChild(child *subSchema) { + s.itemsChildren = append(s.itemsChildren, child) +} + +func (s *subSchema) AddPropertiesChild(child *subSchema) { + s.propertiesChildren = append(s.propertiesChildren, child) +} + +func (s *subSchema) PatternPropertiesString() string { + + if s.patternProperties == nil || len(s.patternProperties) == 0 { + return STRING_UNDEFINED // should never happen + } + + patternPropertiesKeySlice := []string{} + for pk := range s.patternProperties { + patternPropertiesKeySlice = append(patternPropertiesKeySlice, `"`+pk+`"`) + } + + if len(patternPropertiesKeySlice) == 1 { + return patternPropertiesKeySlice[0] + } + + return "[" + strings.Join(patternPropertiesKeySlice, ",") + "]" + +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/types.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/types.go new file mode 100644 index 0000000000..952d22ef65 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/types.go @@ -0,0 +1,58 @@ +// Copyright 2015 xeipuuv ( https://github.com/xeipuuv ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// author xeipuuv +// author-github https://github.com/xeipuuv +// author-mail xeipuuv@gmail.com +// +// repository-name gojsonschema +// repository-desc An implementation of JSON Schema, based on IETF's draft v4 - Go language. +// +// description Contains const types for schema and JSON. +// +// created 28-02-2013 + +package gojsonschema + +const ( + TYPE_ARRAY = `array` + TYPE_BOOLEAN = `boolean` + TYPE_INTEGER = `integer` + TYPE_NUMBER = `number` + TYPE_NULL = `null` + TYPE_OBJECT = `object` + TYPE_STRING = `string` +) + +var JSON_TYPES []string +var SCHEMA_TYPES []string + +func init() { + JSON_TYPES = []string{ + TYPE_ARRAY, + TYPE_BOOLEAN, + TYPE_INTEGER, + TYPE_NUMBER, + TYPE_NULL, + TYPE_OBJECT, + TYPE_STRING} + + SCHEMA_TYPES = []string{ + TYPE_ARRAY, + TYPE_BOOLEAN, + TYPE_INTEGER, + TYPE_NUMBER, + TYPE_OBJECT, + TYPE_STRING} +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/utils.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/utils.go new file mode 100644 index 0000000000..cc3100a78d --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/utils.go @@ -0,0 +1,226 @@ +// Copyright 2015 xeipuuv ( https://github.com/xeipuuv ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// author xeipuuv +// author-github https://github.com/xeipuuv +// author-mail xeipuuv@gmail.com +// +// repository-name gojsonschema +// repository-desc An implementation of JSON Schema, based on IETF's draft v4 - Go language. +// +// description Various utility functions. +// +// created 26-02-2013 + +package gojsonschema + +import ( + "encoding/json" + "fmt" + "math" + "math/big" + "reflect" +) + +func isKind(what interface{}, kinds ...reflect.Kind) bool { + target := what + if isJsonNumber(what) { + // JSON Numbers are strings! + target = *mustBeNumber(what) + } + targetKind := reflect.ValueOf(target).Kind() + for _, kind := range kinds { + if targetKind == kind { + return true + } + } + return false +} + +func existsMapKey(m map[string]interface{}, k string) bool { + _, ok := m[k] + return ok +} + +func isStringInSlice(s []string, what string) bool { + for i := range s { + if s[i] == what { + return true + } + } + return false +} + +func marshalToJsonString(value interface{}) (*string, error) { + + mBytes, err := json.Marshal(value) + if err != nil { + return nil, err + } + + sBytes := string(mBytes) + return &sBytes, nil +} + +func marshalWithoutNumber(value interface{}) (*string, error) { + + // The JSON is decoded using https://golang.org/pkg/encoding/json/#Decoder.UseNumber + // This means the numbers are internally still represented as strings and therefore 1.00 is unequal to 1 + // One way to eliminate these differences is to decode and encode the JSON one more time without Decoder.UseNumber + // so that these differences in representation are removed + + jsonString, err := marshalToJsonString(value) + if err != nil { + return nil, err + } + + var document interface{} + + err = json.Unmarshal([]byte(*jsonString), &document) + if err != nil { + return nil, err + } + + return marshalToJsonString(document) +} + +func isJsonNumber(what interface{}) bool { + + switch what.(type) { + + case json.Number: + return true + } + + return false +} + +func checkJsonInteger(what interface{}) (isInt bool) { + + jsonNumber := what.(json.Number) + + bigFloat, isValidNumber := new(big.Float).SetString(string(jsonNumber)) + + return isValidNumber && bigFloat.IsInt() + +} + +// same as ECMA Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER +const ( + max_json_float = float64(1<<53 - 1) // 9007199254740991.0 2^53 - 1 + min_json_float = -float64(1<<53 - 1) //-9007199254740991.0 -2^53 - 1 +) + +func isFloat64AnInteger(f float64) bool { + + if math.IsNaN(f) || math.IsInf(f, 0) || f < min_json_float || f > max_json_float { + return false + } + + return f == float64(int64(f)) || f == float64(uint64(f)) +} + +func mustBeInteger(what interface{}) *int { + + if isJsonNumber(what) { + + number := what.(json.Number) + + isInt := checkJsonInteger(number) + + if isInt { + + int64Value, err := number.Int64() + if err != nil { + return nil + } + + int32Value := int(int64Value) + return &int32Value + + } else { + return nil + } + + } + + return nil +} + +func mustBeNumber(what interface{}) *big.Float { + + if isJsonNumber(what) { + number := what.(json.Number) + float64Value, success := new(big.Float).SetString(string(number)) + if success { + return float64Value + } else { + return nil + } + + } + + return nil + +} + +// formats a number so that it is displayed as the smallest string possible +func resultErrorFormatJsonNumber(n json.Number) string { + + if int64Value, err := n.Int64(); err == nil { + return fmt.Sprintf("%d", int64Value) + } + + float64Value, _ := n.Float64() + + return fmt.Sprintf("%g", float64Value) +} + +// formats a number so that it is displayed as the smallest string possible +func resultErrorFormatNumber(n float64) string { + + if isFloat64AnInteger(n) { + return fmt.Sprintf("%d", int64(n)) + } + + return fmt.Sprintf("%g", n) +} + +func convertDocumentNode(val interface{}) interface{} { + + if lval, ok := val.([]interface{}); ok { + + res := []interface{}{} + for _, v := range lval { + res = append(res, convertDocumentNode(v)) + } + + return res + + } + + if mval, ok := val.(map[interface{}]interface{}); ok { + + res := map[string]interface{}{} + + for k, v := range mval { + res[k.(string)] = convertDocumentNode(v) + } + + return res + + } + + return val +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/validation.go b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/validation.go new file mode 100644 index 0000000000..63786d5f1e --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/github.com/xeipuuv/gojsonschema/validation.go @@ -0,0 +1,930 @@ +// Copyright 2015 xeipuuv ( https://github.com/xeipuuv ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// author xeipuuv +// author-github https://github.com/xeipuuv +// author-mail xeipuuv@gmail.com +// +// repository-name gojsonschema +// repository-desc An implementation of JSON Schema, based on IETF's draft v4 - Go language. +// +// description Extends Schema and subSchema, implements the validation phase. +// +// created 28-02-2013 + +package gojsonschema + +import ( + "encoding/json" + "math/big" + "reflect" + "regexp" + "strconv" + "strings" + "unicode/utf8" +) + +func Validate(ls JSONLoader, ld JSONLoader) (*Result, error) { + + var err error + + // load schema + + schema, err := NewSchema(ls) + if err != nil { + return nil, err + } + + // begine validation + + return schema.Validate(ld) + +} + +func (v *Schema) Validate(l JSONLoader) (*Result, error) { + + // load document + + root, err := l.LoadJSON() + if err != nil { + return nil, err + } + + return v.validateDocument(root), nil +} + +func (v *Schema) validateDocument(root interface{}) *Result { + // begin validation + + result := &Result{} + context := NewJsonContext(STRING_CONTEXT_ROOT, nil) + v.rootSchema.validateRecursive(v.rootSchema, root, result, context) + + return result +} + +func (v *subSchema) subValidateWithContext(document interface{}, context *JsonContext) *Result { + result := &Result{} + v.validateRecursive(v, document, result, context) + return result +} + +// Walker function to validate the json recursively against the subSchema +func (v *subSchema) validateRecursive(currentSubSchema *subSchema, currentNode interface{}, result *Result, context *JsonContext) { + + if internalLogEnabled { + internalLog("validateRecursive %s", context.String()) + internalLog(" %v", currentNode) + } + + // Handle referenced schemas, returns directly when a $ref is found + if currentSubSchema.refSchema != nil { + v.validateRecursive(currentSubSchema.refSchema, currentNode, result, context) + return + } + + // Check for null value + if currentNode == nil { + if currentSubSchema.types.IsTyped() && !currentSubSchema.types.Contains(TYPE_NULL) { + result.addInternalError( + new(InvalidTypeError), + context, + currentNode, + ErrorDetails{ + "expected": currentSubSchema.types.String(), + "given": TYPE_NULL, + }, + ) + return + } + + currentSubSchema.validateSchema(currentSubSchema, currentNode, result, context) + v.validateCommon(currentSubSchema, currentNode, result, context) + + } else { // Not a null value + + if isJsonNumber(currentNode) { + + value := currentNode.(json.Number) + + isInt := checkJsonInteger(value) + + validType := currentSubSchema.types.Contains(TYPE_NUMBER) || (isInt && currentSubSchema.types.Contains(TYPE_INTEGER)) + + if currentSubSchema.types.IsTyped() && !validType { + + givenType := TYPE_INTEGER + if !isInt { + givenType = TYPE_NUMBER + } + + result.addInternalError( + new(InvalidTypeError), + context, + currentNode, + ErrorDetails{ + "expected": currentSubSchema.types.String(), + "given": givenType, + }, + ) + return + } + + currentSubSchema.validateSchema(currentSubSchema, value, result, context) + v.validateNumber(currentSubSchema, value, result, context) + v.validateCommon(currentSubSchema, value, result, context) + v.validateString(currentSubSchema, value, result, context) + + } else { + + rValue := reflect.ValueOf(currentNode) + rKind := rValue.Kind() + + switch rKind { + + // Slice => JSON array + + case reflect.Slice: + + if currentSubSchema.types.IsTyped() && !currentSubSchema.types.Contains(TYPE_ARRAY) { + result.addInternalError( + new(InvalidTypeError), + context, + currentNode, + ErrorDetails{ + "expected": currentSubSchema.types.String(), + "given": TYPE_ARRAY, + }, + ) + return + } + + castCurrentNode := currentNode.([]interface{}) + + currentSubSchema.validateSchema(currentSubSchema, castCurrentNode, result, context) + + v.validateArray(currentSubSchema, castCurrentNode, result, context) + v.validateCommon(currentSubSchema, castCurrentNode, result, context) + + // Map => JSON object + + case reflect.Map: + if currentSubSchema.types.IsTyped() && !currentSubSchema.types.Contains(TYPE_OBJECT) { + result.addInternalError( + new(InvalidTypeError), + context, + currentNode, + ErrorDetails{ + "expected": currentSubSchema.types.String(), + "given": TYPE_OBJECT, + }, + ) + return + } + + castCurrentNode, ok := currentNode.(map[string]interface{}) + if !ok { + castCurrentNode = convertDocumentNode(currentNode).(map[string]interface{}) + } + + currentSubSchema.validateSchema(currentSubSchema, castCurrentNode, result, context) + + v.validateObject(currentSubSchema, castCurrentNode, result, context) + v.validateCommon(currentSubSchema, castCurrentNode, result, context) + + for _, pSchema := range currentSubSchema.propertiesChildren { + nextNode, ok := castCurrentNode[pSchema.property] + if ok { + subContext := NewJsonContext(pSchema.property, context) + v.validateRecursive(pSchema, nextNode, result, subContext) + } + } + + // Simple JSON values : string, number, boolean + + case reflect.Bool: + + if currentSubSchema.types.IsTyped() && !currentSubSchema.types.Contains(TYPE_BOOLEAN) { + result.addInternalError( + new(InvalidTypeError), + context, + currentNode, + ErrorDetails{ + "expected": currentSubSchema.types.String(), + "given": TYPE_BOOLEAN, + }, + ) + return + } + + value := currentNode.(bool) + + currentSubSchema.validateSchema(currentSubSchema, value, result, context) + v.validateNumber(currentSubSchema, value, result, context) + v.validateCommon(currentSubSchema, value, result, context) + v.validateString(currentSubSchema, value, result, context) + + case reflect.String: + + if currentSubSchema.types.IsTyped() && !currentSubSchema.types.Contains(TYPE_STRING) { + result.addInternalError( + new(InvalidTypeError), + context, + currentNode, + ErrorDetails{ + "expected": currentSubSchema.types.String(), + "given": TYPE_STRING, + }, + ) + return + } + + value := currentNode.(string) + + currentSubSchema.validateSchema(currentSubSchema, value, result, context) + v.validateNumber(currentSubSchema, value, result, context) + v.validateCommon(currentSubSchema, value, result, context) + v.validateString(currentSubSchema, value, result, context) + + } + + } + + } + + result.incrementScore() +} + +// Different kinds of validation there, subSchema / common / array / object / string... +func (v *subSchema) validateSchema(currentSubSchema *subSchema, currentNode interface{}, result *Result, context *JsonContext) { + + if internalLogEnabled { + internalLog("validateSchema %s", context.String()) + internalLog(" %v", currentNode) + } + + if len(currentSubSchema.anyOf) > 0 { + + validatedAnyOf := false + var bestValidationResult *Result + + for _, anyOfSchema := range currentSubSchema.anyOf { + if !validatedAnyOf { + validationResult := anyOfSchema.subValidateWithContext(currentNode, context) + validatedAnyOf = validationResult.Valid() + + if !validatedAnyOf && (bestValidationResult == nil || validationResult.score > bestValidationResult.score) { + bestValidationResult = validationResult + } + } + } + if !validatedAnyOf { + + result.addInternalError(new(NumberAnyOfError), context, currentNode, ErrorDetails{}) + + if bestValidationResult != nil { + // add error messages of closest matching subSchema as + // that's probably the one the user was trying to match + result.mergeErrors(bestValidationResult) + } + } + } + + if len(currentSubSchema.oneOf) > 0 { + + nbValidated := 0 + var bestValidationResult *Result + + for _, oneOfSchema := range currentSubSchema.oneOf { + validationResult := oneOfSchema.subValidateWithContext(currentNode, context) + if validationResult.Valid() { + nbValidated++ + } else if nbValidated == 0 && (bestValidationResult == nil || validationResult.score > bestValidationResult.score) { + bestValidationResult = validationResult + } + } + + if nbValidated != 1 { + + result.addInternalError(new(NumberOneOfError), context, currentNode, ErrorDetails{}) + + if nbValidated == 0 { + // add error messages of closest matching subSchema as + // that's probably the one the user was trying to match + result.mergeErrors(bestValidationResult) + } + } + + } + + if len(currentSubSchema.allOf) > 0 { + nbValidated := 0 + + for _, allOfSchema := range currentSubSchema.allOf { + validationResult := allOfSchema.subValidateWithContext(currentNode, context) + if validationResult.Valid() { + nbValidated++ + } + result.mergeErrors(validationResult) + } + + if nbValidated != len(currentSubSchema.allOf) { + result.addInternalError(new(NumberAllOfError), context, currentNode, ErrorDetails{}) + } + } + + if currentSubSchema.not != nil { + validationResult := currentSubSchema.not.subValidateWithContext(currentNode, context) + if validationResult.Valid() { + result.addInternalError(new(NumberNotError), context, currentNode, ErrorDetails{}) + } + } + + if currentSubSchema.dependencies != nil && len(currentSubSchema.dependencies) > 0 { + if isKind(currentNode, reflect.Map) { + for elementKey := range currentNode.(map[string]interface{}) { + if dependency, ok := currentSubSchema.dependencies[elementKey]; ok { + switch dependency := dependency.(type) { + + case []string: + for _, dependOnKey := range dependency { + if _, dependencyResolved := currentNode.(map[string]interface{})[dependOnKey]; !dependencyResolved { + result.addInternalError( + new(MissingDependencyError), + context, + currentNode, + ErrorDetails{"dependency": dependOnKey}, + ) + } + } + + case *subSchema: + dependency.validateRecursive(dependency, currentNode, result, context) + } + } + } + } + } + + if currentSubSchema._if != nil { + validationResultIf := currentSubSchema._if.subValidateWithContext(currentNode, context) + if currentSubSchema._then != nil && validationResultIf.Valid() { + validationResultThen := currentSubSchema._then.subValidateWithContext(currentNode, context) + if !validationResultThen.Valid() { + result.addInternalError(new(ConditionThenError), context, currentNode, ErrorDetails{}) + result.mergeErrors(validationResultThen) + } + } + if currentSubSchema._else != nil && !validationResultIf.Valid() { + validationResultElse := currentSubSchema._else.subValidateWithContext(currentNode, context) + if !validationResultElse.Valid() { + result.addInternalError(new(ConditionElseError), context, currentNode, ErrorDetails{}) + result.mergeErrors(validationResultElse) + } + } + } + + result.incrementScore() +} + +func (v *subSchema) validateCommon(currentSubSchema *subSchema, value interface{}, result *Result, context *JsonContext) { + + if internalLogEnabled { + internalLog("validateCommon %s", context.String()) + internalLog(" %v", value) + } + + // const: + if currentSubSchema._const != nil { + vString, err := marshalWithoutNumber(value) + if err != nil { + result.addInternalError(new(InternalError), context, value, ErrorDetails{"error": err}) + } + if *vString != *currentSubSchema._const { + result.addInternalError(new(ConstError), + context, + value, + ErrorDetails{ + "allowed": *currentSubSchema._const, + }, + ) + } + } + + // enum: + if len(currentSubSchema.enum) > 0 { + has, err := currentSubSchema.ContainsEnum(value) + if err != nil { + result.addInternalError(new(InternalError), context, value, ErrorDetails{"error": err}) + } + if !has { + result.addInternalError( + new(EnumError), + context, + value, + ErrorDetails{ + "allowed": strings.Join(currentSubSchema.enum, ", "), + }, + ) + } + } + + result.incrementScore() +} + +func (v *subSchema) validateArray(currentSubSchema *subSchema, value []interface{}, result *Result, context *JsonContext) { + + if internalLogEnabled { + internalLog("validateArray %s", context.String()) + internalLog(" %v", value) + } + + nbValues := len(value) + + // TODO explain + if currentSubSchema.itemsChildrenIsSingleSchema { + for i := range value { + subContext := NewJsonContext(strconv.Itoa(i), context) + validationResult := currentSubSchema.itemsChildren[0].subValidateWithContext(value[i], subContext) + result.mergeErrors(validationResult) + } + } else { + if currentSubSchema.itemsChildren != nil && len(currentSubSchema.itemsChildren) > 0 { + + nbItems := len(currentSubSchema.itemsChildren) + + // while we have both schemas and values, check them against each other + for i := 0; i != nbItems && i != nbValues; i++ { + subContext := NewJsonContext(strconv.Itoa(i), context) + validationResult := currentSubSchema.itemsChildren[i].subValidateWithContext(value[i], subContext) + result.mergeErrors(validationResult) + } + + if nbItems < nbValues { + // we have less schemas than elements in the instance array, + // but that might be ok if "additionalItems" is specified. + + switch currentSubSchema.additionalItems.(type) { + case bool: + if !currentSubSchema.additionalItems.(bool) { + result.addInternalError(new(ArrayNoAdditionalItemsError), context, value, ErrorDetails{}) + } + case *subSchema: + additionalItemSchema := currentSubSchema.additionalItems.(*subSchema) + for i := nbItems; i != nbValues; i++ { + subContext := NewJsonContext(strconv.Itoa(i), context) + validationResult := additionalItemSchema.subValidateWithContext(value[i], subContext) + result.mergeErrors(validationResult) + } + } + } + } + } + + // minItems & maxItems + if currentSubSchema.minItems != nil { + if nbValues < int(*currentSubSchema.minItems) { + result.addInternalError( + new(ArrayMinItemsError), + context, + value, + ErrorDetails{"min": *currentSubSchema.minItems}, + ) + } + } + if currentSubSchema.maxItems != nil { + if nbValues > int(*currentSubSchema.maxItems) { + result.addInternalError( + new(ArrayMaxItemsError), + context, + value, + ErrorDetails{"max": *currentSubSchema.maxItems}, + ) + } + } + + // uniqueItems: + if currentSubSchema.uniqueItems { + var stringifiedItems []string + for _, v := range value { + vString, err := marshalWithoutNumber(v) + if err != nil { + result.addInternalError(new(InternalError), context, value, ErrorDetails{"err": err}) + } + if isStringInSlice(stringifiedItems, *vString) { + result.addInternalError( + new(ItemsMustBeUniqueError), + context, + value, + ErrorDetails{"type": TYPE_ARRAY}, + ) + } + stringifiedItems = append(stringifiedItems, *vString) + } + } + + // contains: + + if currentSubSchema.contains != nil { + validatedOne := false + var bestValidationResult *Result + + for i, v := range value { + subContext := NewJsonContext(strconv.Itoa(i), context) + + validationResult := currentSubSchema.contains.subValidateWithContext(v, subContext) + if validationResult.Valid() { + validatedOne = true + break + } else { + if bestValidationResult == nil || validationResult.score > bestValidationResult.score { + bestValidationResult = validationResult + } + } + } + if !validatedOne { + result.addInternalError( + new(ArrayContainsError), + context, + value, + ErrorDetails{}, + ) + if bestValidationResult != nil { + result.mergeErrors(bestValidationResult) + } + } + } + + result.incrementScore() +} + +func (v *subSchema) validateObject(currentSubSchema *subSchema, value map[string]interface{}, result *Result, context *JsonContext) { + + if internalLogEnabled { + internalLog("validateObject %s", context.String()) + internalLog(" %v", value) + } + + // minProperties & maxProperties: + if currentSubSchema.minProperties != nil { + if len(value) < int(*currentSubSchema.minProperties) { + result.addInternalError( + new(ArrayMinPropertiesError), + context, + value, + ErrorDetails{"min": *currentSubSchema.minProperties}, + ) + } + } + if currentSubSchema.maxProperties != nil { + if len(value) > int(*currentSubSchema.maxProperties) { + result.addInternalError( + new(ArrayMaxPropertiesError), + context, + value, + ErrorDetails{"max": *currentSubSchema.maxProperties}, + ) + } + } + + // required: + for _, requiredProperty := range currentSubSchema.required { + _, ok := value[requiredProperty] + if ok { + result.incrementScore() + } else { + result.addInternalError( + new(RequiredError), + context, + value, + ErrorDetails{"property": requiredProperty}, + ) + } + } + + // additionalProperty & patternProperty: + if currentSubSchema.additionalProperties != nil { + + switch currentSubSchema.additionalProperties.(type) { + case bool: + + if !currentSubSchema.additionalProperties.(bool) { + + for pk := range value { + + found := false + for _, spValue := range currentSubSchema.propertiesChildren { + if pk == spValue.property { + found = true + } + } + + pp_has, pp_match := v.validatePatternProperty(currentSubSchema, pk, value[pk], result, context) + + if found { + + if pp_has && !pp_match { + result.addInternalError( + new(AdditionalPropertyNotAllowedError), + context, + value[pk], + ErrorDetails{"property": pk}, + ) + } + + } else { + + if !pp_has || !pp_match { + result.addInternalError( + new(AdditionalPropertyNotAllowedError), + context, + value[pk], + ErrorDetails{"property": pk}, + ) + } + + } + } + } + + case *subSchema: + + additionalPropertiesSchema := currentSubSchema.additionalProperties.(*subSchema) + for pk := range value { + + found := false + for _, spValue := range currentSubSchema.propertiesChildren { + if pk == spValue.property { + found = true + } + } + + pp_has, pp_match := v.validatePatternProperty(currentSubSchema, pk, value[pk], result, context) + + if found { + + if pp_has && !pp_match { + validationResult := additionalPropertiesSchema.subValidateWithContext(value[pk], context) + result.mergeErrors(validationResult) + } + + } else { + + if !pp_has || !pp_match { + validationResult := additionalPropertiesSchema.subValidateWithContext(value[pk], context) + result.mergeErrors(validationResult) + } + + } + + } + } + } else { + + for pk := range value { + + pp_has, pp_match := v.validatePatternProperty(currentSubSchema, pk, value[pk], result, context) + + if pp_has && !pp_match { + + result.addInternalError( + new(InvalidPropertyPatternError), + context, + value[pk], + ErrorDetails{ + "property": pk, + "pattern": currentSubSchema.PatternPropertiesString(), + }, + ) + } + + } + } + + // propertyNames: + if currentSubSchema.propertyNames != nil { + for pk := range value { + validationResult := currentSubSchema.propertyNames.subValidateWithContext(pk, context) + if !validationResult.Valid() { + result.addInternalError(new(InvalidPropertyNameError), + context, + value, ErrorDetails{ + "property": pk, + }) + result.mergeErrors(validationResult) + } + } + } + + result.incrementScore() +} + +func (v *subSchema) validatePatternProperty(currentSubSchema *subSchema, key string, value interface{}, result *Result, context *JsonContext) (has bool, matched bool) { + + if internalLogEnabled { + internalLog("validatePatternProperty %s", context.String()) + internalLog(" %s %v", key, value) + } + + has = false + + validatedkey := false + + for pk, pv := range currentSubSchema.patternProperties { + if matches, _ := regexp.MatchString(pk, key); matches { + has = true + subContext := NewJsonContext(key, context) + validationResult := pv.subValidateWithContext(value, subContext) + result.mergeErrors(validationResult) + if validationResult.Valid() { + validatedkey = true + } + } + } + + if !validatedkey { + return has, false + } + + result.incrementScore() + + return has, true +} + +func (v *subSchema) validateString(currentSubSchema *subSchema, value interface{}, result *Result, context *JsonContext) { + + // Ignore JSON numbers + if isJsonNumber(value) { + return + } + + // Ignore non strings + if !isKind(value, reflect.String) { + return + } + + if internalLogEnabled { + internalLog("validateString %s", context.String()) + internalLog(" %v", value) + } + + stringValue := value.(string) + + // minLength & maxLength: + if currentSubSchema.minLength != nil { + if utf8.RuneCount([]byte(stringValue)) < int(*currentSubSchema.minLength) { + result.addInternalError( + new(StringLengthGTEError), + context, + value, + ErrorDetails{"min": *currentSubSchema.minLength}, + ) + } + } + if currentSubSchema.maxLength != nil { + if utf8.RuneCount([]byte(stringValue)) > int(*currentSubSchema.maxLength) { + result.addInternalError( + new(StringLengthLTEError), + context, + value, + ErrorDetails{"max": *currentSubSchema.maxLength}, + ) + } + } + + // pattern: + if currentSubSchema.pattern != nil { + if !currentSubSchema.pattern.MatchString(stringValue) { + result.addInternalError( + new(DoesNotMatchPatternError), + context, + value, + ErrorDetails{"pattern": currentSubSchema.pattern}, + ) + + } + } + + // format + if currentSubSchema.format != "" { + if !FormatCheckers.IsFormat(currentSubSchema.format, stringValue) { + result.addInternalError( + new(DoesNotMatchFormatError), + context, + value, + ErrorDetails{"format": currentSubSchema.format}, + ) + } + } + + result.incrementScore() +} + +func (v *subSchema) validateNumber(currentSubSchema *subSchema, value interface{}, result *Result, context *JsonContext) { + + // Ignore non numbers + if !isJsonNumber(value) { + return + } + + if internalLogEnabled { + internalLog("validateNumber %s", context.String()) + internalLog(" %v", value) + } + + number := value.(json.Number) + float64Value, _ := new(big.Float).SetString(string(number)) + + // multipleOf: + if currentSubSchema.multipleOf != nil { + + if q := new(big.Float).Quo(float64Value, currentSubSchema.multipleOf); !q.IsInt() { + result.addInternalError( + new(MultipleOfError), + context, + resultErrorFormatJsonNumber(number), + ErrorDetails{"multiple": currentSubSchema.multipleOf}, + ) + } + } + + //maximum & exclusiveMaximum: + if currentSubSchema.maximum != nil { + if currentSubSchema.exclusiveMaximum { + if float64Value.Cmp(currentSubSchema.maximum) >= 0 { + result.addInternalError( + new(NumberLTError), + context, + resultErrorFormatJsonNumber(number), + ErrorDetails{ + "max": currentSubSchema.maximum, + }, + ) + } + } else { + if float64Value.Cmp(currentSubSchema.maximum) == 1 { + result.addInternalError( + new(NumberLTEError), + context, + resultErrorFormatJsonNumber(number), + ErrorDetails{ + "max": currentSubSchema.maximum, + }, + ) + } + } + } + + //minimum & exclusiveMinimum: + if currentSubSchema.minimum != nil { + if currentSubSchema.exclusiveMinimum { + if float64Value.Cmp(currentSubSchema.minimum) <= 0 { + // if float64Value <= *currentSubSchema.minimum { + result.addInternalError( + new(NumberGTError), + context, + resultErrorFormatJsonNumber(number), + ErrorDetails{ + "min": currentSubSchema.minimum, + }, + ) + } + } else { + if float64Value.Cmp(currentSubSchema.minimum) == -1 { + result.addInternalError( + new(NumberGTEError), + context, + resultErrorFormatJsonNumber(number), + ErrorDetails{ + "min": currentSubSchema.minimum, + }, + ) + } + } + } + + // format + if currentSubSchema.format != "" { + if !FormatCheckers.IsFormat(currentSubSchema.format, float64Value) { + result.addInternalError( + new(DoesNotMatchFormatError), + context, + value, + ErrorDetails{"format": currentSubSchema.format}, + ) + } + } + + result.incrementScore() +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/LICENSE b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/LICENSE new file mode 100644 index 0000000000..6a66aea5ea --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/PATENTS b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/PATENTS new file mode 100644 index 0000000000..733099041f --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/PATENTS @@ -0,0 +1,22 @@ +Additional IP Rights Grant (Patents) + +"This implementation" means the copyrightable works distributed by +Google as part of the Go project. + +Google 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, +transfer and otherwise run, modify and propagate the contents of this +implementation of Go, where such license applies only to those patent +claims, both currently owned or controlled by Google and acquired in +the future, licensable by Google that are necessarily infringed by this +implementation of Go. This grant does not include claims that would be +infringed only as a consequence of further modification of this +implementation. If you or your agent or exclusive licensee institute or +order or agree to the institution of patent litigation against any +entity (including a cross-claim or counterclaim in a lawsuit) alleging +that this implementation of Go or any code incorporated within this +implementation of Go constitutes direct or contributory patent +infringement, or inducement of patent infringement, then any patent +rights granted to you under this License for this implementation of Go +shall terminate as of the date such litigation is filed. diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/README.md b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/README.md new file mode 100644 index 0000000000..c9d6fecd1e --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/README.md @@ -0,0 +1,21 @@ +# Go Cryptography + +This repository holds supplementary Go cryptography libraries. + +## Download/Install + +The easiest way to install is to run `go get -u golang.org/x/crypto/...`. You +can also manually git clone the repository to `$GOPATH/src/golang.org/x/crypto`. + +## Report Issues / Send Patches + +This repository uses Gerrit for code changes. To learn how to submit changes to +this repository, see https://golang.org/doc/contribute.html. + +The main issue tracker for the crypto repository is located at +https://github.com/golang/go/issues. Prefix your issue with "x/crypto:" in the +subject line, so it is easy to find. + +Note that contributions to the cryptography package receive additional scrutiny +due to their sensitive nature. Patches may take longer than normal to receive +feedback. diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/curve25519/const_amd64.h b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/curve25519/const_amd64.h new file mode 100644 index 0000000000..b3f74162f6 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/curve25519/const_amd64.h @@ -0,0 +1,8 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This code was translated into a form compatible with 6a from the public +// domain sources in SUPERCOP: https://bench.cr.yp.to/supercop.html + +#define REDMASK51 0x0007FFFFFFFFFFFF diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/curve25519/const_amd64.s b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/curve25519/const_amd64.s new file mode 100644 index 0000000000..ee7b4bd5f8 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/curve25519/const_amd64.s @@ -0,0 +1,20 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This code was translated into a form compatible with 6a from the public +// domain sources in SUPERCOP: https://bench.cr.yp.to/supercop.html + +// +build amd64,!gccgo,!appengine + +// These constants cannot be encoded in non-MOVQ immediates. +// We access them directly from memory instead. + +DATA ·_121666_213(SB)/8, $996687872 +GLOBL ·_121666_213(SB), 8, $8 + +DATA ·_2P0(SB)/8, $0xFFFFFFFFFFFDA +GLOBL ·_2P0(SB), 8, $8 + +DATA ·_2P1234(SB)/8, $0xFFFFFFFFFFFFE +GLOBL ·_2P1234(SB), 8, $8 diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/curve25519/cswap_amd64.s b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/curve25519/cswap_amd64.s new file mode 100644 index 0000000000..cd793a5b5f --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/curve25519/cswap_amd64.s @@ -0,0 +1,65 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build amd64,!gccgo,!appengine + +// func cswap(inout *[4][5]uint64, v uint64) +TEXT ·cswap(SB),7,$0 + MOVQ inout+0(FP),DI + MOVQ v+8(FP),SI + + SUBQ $1, SI + NOTQ SI + MOVQ SI, X15 + PSHUFD $0x44, X15, X15 + + MOVOU 0(DI), X0 + MOVOU 16(DI), X2 + MOVOU 32(DI), X4 + MOVOU 48(DI), X6 + MOVOU 64(DI), X8 + MOVOU 80(DI), X1 + MOVOU 96(DI), X3 + MOVOU 112(DI), X5 + MOVOU 128(DI), X7 + MOVOU 144(DI), X9 + + MOVO X1, X10 + MOVO X3, X11 + MOVO X5, X12 + MOVO X7, X13 + MOVO X9, X14 + + PXOR X0, X10 + PXOR X2, X11 + PXOR X4, X12 + PXOR X6, X13 + PXOR X8, X14 + PAND X15, X10 + PAND X15, X11 + PAND X15, X12 + PAND X15, X13 + PAND X15, X14 + PXOR X10, X0 + PXOR X10, X1 + PXOR X11, X2 + PXOR X11, X3 + PXOR X12, X4 + PXOR X12, X5 + PXOR X13, X6 + PXOR X13, X7 + PXOR X14, X8 + PXOR X14, X9 + + MOVOU X0, 0(DI) + MOVOU X2, 16(DI) + MOVOU X4, 32(DI) + MOVOU X6, 48(DI) + MOVOU X8, 64(DI) + MOVOU X1, 80(DI) + MOVOU X3, 96(DI) + MOVOU X5, 112(DI) + MOVOU X7, 128(DI) + MOVOU X9, 144(DI) + RET diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/curve25519/curve25519.go b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/curve25519/curve25519.go new file mode 100644 index 0000000000..cb8fbc57b9 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/curve25519/curve25519.go @@ -0,0 +1,834 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// We have an implementation in amd64 assembly so this code is only run on +// non-amd64 platforms. The amd64 assembly does not support gccgo. +// +build !amd64 gccgo appengine + +package curve25519 + +import ( + "encoding/binary" +) + +// This code is a port of the public domain, "ref10" implementation of +// curve25519 from SUPERCOP 20130419 by D. J. Bernstein. + +// fieldElement represents an element of the field GF(2^255 - 19). An element +// t, entries t[0]...t[9], represents the integer t[0]+2^26 t[1]+2^51 t[2]+2^77 +// t[3]+2^102 t[4]+...+2^230 t[9]. Bounds on each t[i] vary depending on +// context. +type fieldElement [10]int32 + +func feZero(fe *fieldElement) { + for i := range fe { + fe[i] = 0 + } +} + +func feOne(fe *fieldElement) { + feZero(fe) + fe[0] = 1 +} + +func feAdd(dst, a, b *fieldElement) { + for i := range dst { + dst[i] = a[i] + b[i] + } +} + +func feSub(dst, a, b *fieldElement) { + for i := range dst { + dst[i] = a[i] - b[i] + } +} + +func feCopy(dst, src *fieldElement) { + for i := range dst { + dst[i] = src[i] + } +} + +// feCSwap replaces (f,g) with (g,f) if b == 1; replaces (f,g) with (f,g) if b == 0. +// +// Preconditions: b in {0,1}. +func feCSwap(f, g *fieldElement, b int32) { + b = -b + for i := range f { + t := b & (f[i] ^ g[i]) + f[i] ^= t + g[i] ^= t + } +} + +// load3 reads a 24-bit, little-endian value from in. +func load3(in []byte) int64 { + var r int64 + r = int64(in[0]) + r |= int64(in[1]) << 8 + r |= int64(in[2]) << 16 + return r +} + +// load4 reads a 32-bit, little-endian value from in. +func load4(in []byte) int64 { + return int64(binary.LittleEndian.Uint32(in)) +} + +func feFromBytes(dst *fieldElement, src *[32]byte) { + h0 := load4(src[:]) + h1 := load3(src[4:]) << 6 + h2 := load3(src[7:]) << 5 + h3 := load3(src[10:]) << 3 + h4 := load3(src[13:]) << 2 + h5 := load4(src[16:]) + h6 := load3(src[20:]) << 7 + h7 := load3(src[23:]) << 5 + h8 := load3(src[26:]) << 4 + h9 := load3(src[29:]) << 2 + + var carry [10]int64 + carry[9] = (h9 + 1<<24) >> 25 + h0 += carry[9] * 19 + h9 -= carry[9] << 25 + carry[1] = (h1 + 1<<24) >> 25 + h2 += carry[1] + h1 -= carry[1] << 25 + carry[3] = (h3 + 1<<24) >> 25 + h4 += carry[3] + h3 -= carry[3] << 25 + carry[5] = (h5 + 1<<24) >> 25 + h6 += carry[5] + h5 -= carry[5] << 25 + carry[7] = (h7 + 1<<24) >> 25 + h8 += carry[7] + h7 -= carry[7] << 25 + + carry[0] = (h0 + 1<<25) >> 26 + h1 += carry[0] + h0 -= carry[0] << 26 + carry[2] = (h2 + 1<<25) >> 26 + h3 += carry[2] + h2 -= carry[2] << 26 + carry[4] = (h4 + 1<<25) >> 26 + h5 += carry[4] + h4 -= carry[4] << 26 + carry[6] = (h6 + 1<<25) >> 26 + h7 += carry[6] + h6 -= carry[6] << 26 + carry[8] = (h8 + 1<<25) >> 26 + h9 += carry[8] + h8 -= carry[8] << 26 + + dst[0] = int32(h0) + dst[1] = int32(h1) + dst[2] = int32(h2) + dst[3] = int32(h3) + dst[4] = int32(h4) + dst[5] = int32(h5) + dst[6] = int32(h6) + dst[7] = int32(h7) + dst[8] = int32(h8) + dst[9] = int32(h9) +} + +// feToBytes marshals h to s. +// Preconditions: +// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. +// +// Write p=2^255-19; q=floor(h/p). +// Basic claim: q = floor(2^(-255)(h + 19 2^(-25)h9 + 2^(-1))). +// +// Proof: +// Have |h|<=p so |q|<=1 so |19^2 2^(-255) q|<1/4. +// Also have |h-2^230 h9|<2^230 so |19 2^(-255)(h-2^230 h9)|<1/4. +// +// Write y=2^(-1)-19^2 2^(-255)q-19 2^(-255)(h-2^230 h9). +// Then 0> 25 + q = (h[0] + q) >> 26 + q = (h[1] + q) >> 25 + q = (h[2] + q) >> 26 + q = (h[3] + q) >> 25 + q = (h[4] + q) >> 26 + q = (h[5] + q) >> 25 + q = (h[6] + q) >> 26 + q = (h[7] + q) >> 25 + q = (h[8] + q) >> 26 + q = (h[9] + q) >> 25 + + // Goal: Output h-(2^255-19)q, which is between 0 and 2^255-20. + h[0] += 19 * q + // Goal: Output h-2^255 q, which is between 0 and 2^255-20. + + carry[0] = h[0] >> 26 + h[1] += carry[0] + h[0] -= carry[0] << 26 + carry[1] = h[1] >> 25 + h[2] += carry[1] + h[1] -= carry[1] << 25 + carry[2] = h[2] >> 26 + h[3] += carry[2] + h[2] -= carry[2] << 26 + carry[3] = h[3] >> 25 + h[4] += carry[3] + h[3] -= carry[3] << 25 + carry[4] = h[4] >> 26 + h[5] += carry[4] + h[4] -= carry[4] << 26 + carry[5] = h[5] >> 25 + h[6] += carry[5] + h[5] -= carry[5] << 25 + carry[6] = h[6] >> 26 + h[7] += carry[6] + h[6] -= carry[6] << 26 + carry[7] = h[7] >> 25 + h[8] += carry[7] + h[7] -= carry[7] << 25 + carry[8] = h[8] >> 26 + h[9] += carry[8] + h[8] -= carry[8] << 26 + carry[9] = h[9] >> 25 + h[9] -= carry[9] << 25 + // h10 = carry9 + + // Goal: Output h[0]+...+2^255 h10-2^255 q, which is between 0 and 2^255-20. + // Have h[0]+...+2^230 h[9] between 0 and 2^255-1; + // evidently 2^255 h10-2^255 q = 0. + // Goal: Output h[0]+...+2^230 h[9]. + + s[0] = byte(h[0] >> 0) + s[1] = byte(h[0] >> 8) + s[2] = byte(h[0] >> 16) + s[3] = byte((h[0] >> 24) | (h[1] << 2)) + s[4] = byte(h[1] >> 6) + s[5] = byte(h[1] >> 14) + s[6] = byte((h[1] >> 22) | (h[2] << 3)) + s[7] = byte(h[2] >> 5) + s[8] = byte(h[2] >> 13) + s[9] = byte((h[2] >> 21) | (h[3] << 5)) + s[10] = byte(h[3] >> 3) + s[11] = byte(h[3] >> 11) + s[12] = byte((h[3] >> 19) | (h[4] << 6)) + s[13] = byte(h[4] >> 2) + s[14] = byte(h[4] >> 10) + s[15] = byte(h[4] >> 18) + s[16] = byte(h[5] >> 0) + s[17] = byte(h[5] >> 8) + s[18] = byte(h[5] >> 16) + s[19] = byte((h[5] >> 24) | (h[6] << 1)) + s[20] = byte(h[6] >> 7) + s[21] = byte(h[6] >> 15) + s[22] = byte((h[6] >> 23) | (h[7] << 3)) + s[23] = byte(h[7] >> 5) + s[24] = byte(h[7] >> 13) + s[25] = byte((h[7] >> 21) | (h[8] << 4)) + s[26] = byte(h[8] >> 4) + s[27] = byte(h[8] >> 12) + s[28] = byte((h[8] >> 20) | (h[9] << 6)) + s[29] = byte(h[9] >> 2) + s[30] = byte(h[9] >> 10) + s[31] = byte(h[9] >> 18) +} + +// feMul calculates h = f * g +// Can overlap h with f or g. +// +// Preconditions: +// |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. +// |g| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. +// +// Postconditions: +// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. +// +// Notes on implementation strategy: +// +// Using schoolbook multiplication. +// Karatsuba would save a little in some cost models. +// +// Most multiplications by 2 and 19 are 32-bit precomputations; +// cheaper than 64-bit postcomputations. +// +// There is one remaining multiplication by 19 in the carry chain; +// one *19 precomputation can be merged into this, +// but the resulting data flow is considerably less clean. +// +// There are 12 carries below. +// 10 of them are 2-way parallelizable and vectorizable. +// Can get away with 11 carries, but then data flow is much deeper. +// +// With tighter constraints on inputs can squeeze carries into int32. +func feMul(h, f, g *fieldElement) { + f0 := f[0] + f1 := f[1] + f2 := f[2] + f3 := f[3] + f4 := f[4] + f5 := f[5] + f6 := f[6] + f7 := f[7] + f8 := f[8] + f9 := f[9] + g0 := g[0] + g1 := g[1] + g2 := g[2] + g3 := g[3] + g4 := g[4] + g5 := g[5] + g6 := g[6] + g7 := g[7] + g8 := g[8] + g9 := g[9] + g1_19 := 19 * g1 // 1.4*2^29 + g2_19 := 19 * g2 // 1.4*2^30; still ok + g3_19 := 19 * g3 + g4_19 := 19 * g4 + g5_19 := 19 * g5 + g6_19 := 19 * g6 + g7_19 := 19 * g7 + g8_19 := 19 * g8 + g9_19 := 19 * g9 + f1_2 := 2 * f1 + f3_2 := 2 * f3 + f5_2 := 2 * f5 + f7_2 := 2 * f7 + f9_2 := 2 * f9 + f0g0 := int64(f0) * int64(g0) + f0g1 := int64(f0) * int64(g1) + f0g2 := int64(f0) * int64(g2) + f0g3 := int64(f0) * int64(g3) + f0g4 := int64(f0) * int64(g4) + f0g5 := int64(f0) * int64(g5) + f0g6 := int64(f0) * int64(g6) + f0g7 := int64(f0) * int64(g7) + f0g8 := int64(f0) * int64(g8) + f0g9 := int64(f0) * int64(g9) + f1g0 := int64(f1) * int64(g0) + f1g1_2 := int64(f1_2) * int64(g1) + f1g2 := int64(f1) * int64(g2) + f1g3_2 := int64(f1_2) * int64(g3) + f1g4 := int64(f1) * int64(g4) + f1g5_2 := int64(f1_2) * int64(g5) + f1g6 := int64(f1) * int64(g6) + f1g7_2 := int64(f1_2) * int64(g7) + f1g8 := int64(f1) * int64(g8) + f1g9_38 := int64(f1_2) * int64(g9_19) + f2g0 := int64(f2) * int64(g0) + f2g1 := int64(f2) * int64(g1) + f2g2 := int64(f2) * int64(g2) + f2g3 := int64(f2) * int64(g3) + f2g4 := int64(f2) * int64(g4) + f2g5 := int64(f2) * int64(g5) + f2g6 := int64(f2) * int64(g6) + f2g7 := int64(f2) * int64(g7) + f2g8_19 := int64(f2) * int64(g8_19) + f2g9_19 := int64(f2) * int64(g9_19) + f3g0 := int64(f3) * int64(g0) + f3g1_2 := int64(f3_2) * int64(g1) + f3g2 := int64(f3) * int64(g2) + f3g3_2 := int64(f3_2) * int64(g3) + f3g4 := int64(f3) * int64(g4) + f3g5_2 := int64(f3_2) * int64(g5) + f3g6 := int64(f3) * int64(g6) + f3g7_38 := int64(f3_2) * int64(g7_19) + f3g8_19 := int64(f3) * int64(g8_19) + f3g9_38 := int64(f3_2) * int64(g9_19) + f4g0 := int64(f4) * int64(g0) + f4g1 := int64(f4) * int64(g1) + f4g2 := int64(f4) * int64(g2) + f4g3 := int64(f4) * int64(g3) + f4g4 := int64(f4) * int64(g4) + f4g5 := int64(f4) * int64(g5) + f4g6_19 := int64(f4) * int64(g6_19) + f4g7_19 := int64(f4) * int64(g7_19) + f4g8_19 := int64(f4) * int64(g8_19) + f4g9_19 := int64(f4) * int64(g9_19) + f5g0 := int64(f5) * int64(g0) + f5g1_2 := int64(f5_2) * int64(g1) + f5g2 := int64(f5) * int64(g2) + f5g3_2 := int64(f5_2) * int64(g3) + f5g4 := int64(f5) * int64(g4) + f5g5_38 := int64(f5_2) * int64(g5_19) + f5g6_19 := int64(f5) * int64(g6_19) + f5g7_38 := int64(f5_2) * int64(g7_19) + f5g8_19 := int64(f5) * int64(g8_19) + f5g9_38 := int64(f5_2) * int64(g9_19) + f6g0 := int64(f6) * int64(g0) + f6g1 := int64(f6) * int64(g1) + f6g2 := int64(f6) * int64(g2) + f6g3 := int64(f6) * int64(g3) + f6g4_19 := int64(f6) * int64(g4_19) + f6g5_19 := int64(f6) * int64(g5_19) + f6g6_19 := int64(f6) * int64(g6_19) + f6g7_19 := int64(f6) * int64(g7_19) + f6g8_19 := int64(f6) * int64(g8_19) + f6g9_19 := int64(f6) * int64(g9_19) + f7g0 := int64(f7) * int64(g0) + f7g1_2 := int64(f7_2) * int64(g1) + f7g2 := int64(f7) * int64(g2) + f7g3_38 := int64(f7_2) * int64(g3_19) + f7g4_19 := int64(f7) * int64(g4_19) + f7g5_38 := int64(f7_2) * int64(g5_19) + f7g6_19 := int64(f7) * int64(g6_19) + f7g7_38 := int64(f7_2) * int64(g7_19) + f7g8_19 := int64(f7) * int64(g8_19) + f7g9_38 := int64(f7_2) * int64(g9_19) + f8g0 := int64(f8) * int64(g0) + f8g1 := int64(f8) * int64(g1) + f8g2_19 := int64(f8) * int64(g2_19) + f8g3_19 := int64(f8) * int64(g3_19) + f8g4_19 := int64(f8) * int64(g4_19) + f8g5_19 := int64(f8) * int64(g5_19) + f8g6_19 := int64(f8) * int64(g6_19) + f8g7_19 := int64(f8) * int64(g7_19) + f8g8_19 := int64(f8) * int64(g8_19) + f8g9_19 := int64(f8) * int64(g9_19) + f9g0 := int64(f9) * int64(g0) + f9g1_38 := int64(f9_2) * int64(g1_19) + f9g2_19 := int64(f9) * int64(g2_19) + f9g3_38 := int64(f9_2) * int64(g3_19) + f9g4_19 := int64(f9) * int64(g4_19) + f9g5_38 := int64(f9_2) * int64(g5_19) + f9g6_19 := int64(f9) * int64(g6_19) + f9g7_38 := int64(f9_2) * int64(g7_19) + f9g8_19 := int64(f9) * int64(g8_19) + f9g9_38 := int64(f9_2) * int64(g9_19) + h0 := f0g0 + f1g9_38 + f2g8_19 + f3g7_38 + f4g6_19 + f5g5_38 + f6g4_19 + f7g3_38 + f8g2_19 + f9g1_38 + h1 := f0g1 + f1g0 + f2g9_19 + f3g8_19 + f4g7_19 + f5g6_19 + f6g5_19 + f7g4_19 + f8g3_19 + f9g2_19 + h2 := f0g2 + f1g1_2 + f2g0 + f3g9_38 + f4g8_19 + f5g7_38 + f6g6_19 + f7g5_38 + f8g4_19 + f9g3_38 + h3 := f0g3 + f1g2 + f2g1 + f3g0 + f4g9_19 + f5g8_19 + f6g7_19 + f7g6_19 + f8g5_19 + f9g4_19 + h4 := f0g4 + f1g3_2 + f2g2 + f3g1_2 + f4g0 + f5g9_38 + f6g8_19 + f7g7_38 + f8g6_19 + f9g5_38 + h5 := f0g5 + f1g4 + f2g3 + f3g2 + f4g1 + f5g0 + f6g9_19 + f7g8_19 + f8g7_19 + f9g6_19 + h6 := f0g6 + f1g5_2 + f2g4 + f3g3_2 + f4g2 + f5g1_2 + f6g0 + f7g9_38 + f8g8_19 + f9g7_38 + h7 := f0g7 + f1g6 + f2g5 + f3g4 + f4g3 + f5g2 + f6g1 + f7g0 + f8g9_19 + f9g8_19 + h8 := f0g8 + f1g7_2 + f2g6 + f3g5_2 + f4g4 + f5g3_2 + f6g2 + f7g1_2 + f8g0 + f9g9_38 + h9 := f0g9 + f1g8 + f2g7 + f3g6 + f4g5 + f5g4 + f6g3 + f7g2 + f8g1 + f9g0 + var carry [10]int64 + + // |h0| <= (1.1*1.1*2^52*(1+19+19+19+19)+1.1*1.1*2^50*(38+38+38+38+38)) + // i.e. |h0| <= 1.2*2^59; narrower ranges for h2, h4, h6, h8 + // |h1| <= (1.1*1.1*2^51*(1+1+19+19+19+19+19+19+19+19)) + // i.e. |h1| <= 1.5*2^58; narrower ranges for h3, h5, h7, h9 + + carry[0] = (h0 + (1 << 25)) >> 26 + h1 += carry[0] + h0 -= carry[0] << 26 + carry[4] = (h4 + (1 << 25)) >> 26 + h5 += carry[4] + h4 -= carry[4] << 26 + // |h0| <= 2^25 + // |h4| <= 2^25 + // |h1| <= 1.51*2^58 + // |h5| <= 1.51*2^58 + + carry[1] = (h1 + (1 << 24)) >> 25 + h2 += carry[1] + h1 -= carry[1] << 25 + carry[5] = (h5 + (1 << 24)) >> 25 + h6 += carry[5] + h5 -= carry[5] << 25 + // |h1| <= 2^24; from now on fits into int32 + // |h5| <= 2^24; from now on fits into int32 + // |h2| <= 1.21*2^59 + // |h6| <= 1.21*2^59 + + carry[2] = (h2 + (1 << 25)) >> 26 + h3 += carry[2] + h2 -= carry[2] << 26 + carry[6] = (h6 + (1 << 25)) >> 26 + h7 += carry[6] + h6 -= carry[6] << 26 + // |h2| <= 2^25; from now on fits into int32 unchanged + // |h6| <= 2^25; from now on fits into int32 unchanged + // |h3| <= 1.51*2^58 + // |h7| <= 1.51*2^58 + + carry[3] = (h3 + (1 << 24)) >> 25 + h4 += carry[3] + h3 -= carry[3] << 25 + carry[7] = (h7 + (1 << 24)) >> 25 + h8 += carry[7] + h7 -= carry[7] << 25 + // |h3| <= 2^24; from now on fits into int32 unchanged + // |h7| <= 2^24; from now on fits into int32 unchanged + // |h4| <= 1.52*2^33 + // |h8| <= 1.52*2^33 + + carry[4] = (h4 + (1 << 25)) >> 26 + h5 += carry[4] + h4 -= carry[4] << 26 + carry[8] = (h8 + (1 << 25)) >> 26 + h9 += carry[8] + h8 -= carry[8] << 26 + // |h4| <= 2^25; from now on fits into int32 unchanged + // |h8| <= 2^25; from now on fits into int32 unchanged + // |h5| <= 1.01*2^24 + // |h9| <= 1.51*2^58 + + carry[9] = (h9 + (1 << 24)) >> 25 + h0 += carry[9] * 19 + h9 -= carry[9] << 25 + // |h9| <= 2^24; from now on fits into int32 unchanged + // |h0| <= 1.8*2^37 + + carry[0] = (h0 + (1 << 25)) >> 26 + h1 += carry[0] + h0 -= carry[0] << 26 + // |h0| <= 2^25; from now on fits into int32 unchanged + // |h1| <= 1.01*2^24 + + h[0] = int32(h0) + h[1] = int32(h1) + h[2] = int32(h2) + h[3] = int32(h3) + h[4] = int32(h4) + h[5] = int32(h5) + h[6] = int32(h6) + h[7] = int32(h7) + h[8] = int32(h8) + h[9] = int32(h9) +} + +// feSquare calculates h = f*f. Can overlap h with f. +// +// Preconditions: +// |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. +// +// Postconditions: +// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. +func feSquare(h, f *fieldElement) { + f0 := f[0] + f1 := f[1] + f2 := f[2] + f3 := f[3] + f4 := f[4] + f5 := f[5] + f6 := f[6] + f7 := f[7] + f8 := f[8] + f9 := f[9] + f0_2 := 2 * f0 + f1_2 := 2 * f1 + f2_2 := 2 * f2 + f3_2 := 2 * f3 + f4_2 := 2 * f4 + f5_2 := 2 * f5 + f6_2 := 2 * f6 + f7_2 := 2 * f7 + f5_38 := 38 * f5 // 1.31*2^30 + f6_19 := 19 * f6 // 1.31*2^30 + f7_38 := 38 * f7 // 1.31*2^30 + f8_19 := 19 * f8 // 1.31*2^30 + f9_38 := 38 * f9 // 1.31*2^30 + f0f0 := int64(f0) * int64(f0) + f0f1_2 := int64(f0_2) * int64(f1) + f0f2_2 := int64(f0_2) * int64(f2) + f0f3_2 := int64(f0_2) * int64(f3) + f0f4_2 := int64(f0_2) * int64(f4) + f0f5_2 := int64(f0_2) * int64(f5) + f0f6_2 := int64(f0_2) * int64(f6) + f0f7_2 := int64(f0_2) * int64(f7) + f0f8_2 := int64(f0_2) * int64(f8) + f0f9_2 := int64(f0_2) * int64(f9) + f1f1_2 := int64(f1_2) * int64(f1) + f1f2_2 := int64(f1_2) * int64(f2) + f1f3_4 := int64(f1_2) * int64(f3_2) + f1f4_2 := int64(f1_2) * int64(f4) + f1f5_4 := int64(f1_2) * int64(f5_2) + f1f6_2 := int64(f1_2) * int64(f6) + f1f7_4 := int64(f1_2) * int64(f7_2) + f1f8_2 := int64(f1_2) * int64(f8) + f1f9_76 := int64(f1_2) * int64(f9_38) + f2f2 := int64(f2) * int64(f2) + f2f3_2 := int64(f2_2) * int64(f3) + f2f4_2 := int64(f2_2) * int64(f4) + f2f5_2 := int64(f2_2) * int64(f5) + f2f6_2 := int64(f2_2) * int64(f6) + f2f7_2 := int64(f2_2) * int64(f7) + f2f8_38 := int64(f2_2) * int64(f8_19) + f2f9_38 := int64(f2) * int64(f9_38) + f3f3_2 := int64(f3_2) * int64(f3) + f3f4_2 := int64(f3_2) * int64(f4) + f3f5_4 := int64(f3_2) * int64(f5_2) + f3f6_2 := int64(f3_2) * int64(f6) + f3f7_76 := int64(f3_2) * int64(f7_38) + f3f8_38 := int64(f3_2) * int64(f8_19) + f3f9_76 := int64(f3_2) * int64(f9_38) + f4f4 := int64(f4) * int64(f4) + f4f5_2 := int64(f4_2) * int64(f5) + f4f6_38 := int64(f4_2) * int64(f6_19) + f4f7_38 := int64(f4) * int64(f7_38) + f4f8_38 := int64(f4_2) * int64(f8_19) + f4f9_38 := int64(f4) * int64(f9_38) + f5f5_38 := int64(f5) * int64(f5_38) + f5f6_38 := int64(f5_2) * int64(f6_19) + f5f7_76 := int64(f5_2) * int64(f7_38) + f5f8_38 := int64(f5_2) * int64(f8_19) + f5f9_76 := int64(f5_2) * int64(f9_38) + f6f6_19 := int64(f6) * int64(f6_19) + f6f7_38 := int64(f6) * int64(f7_38) + f6f8_38 := int64(f6_2) * int64(f8_19) + f6f9_38 := int64(f6) * int64(f9_38) + f7f7_38 := int64(f7) * int64(f7_38) + f7f8_38 := int64(f7_2) * int64(f8_19) + f7f9_76 := int64(f7_2) * int64(f9_38) + f8f8_19 := int64(f8) * int64(f8_19) + f8f9_38 := int64(f8) * int64(f9_38) + f9f9_38 := int64(f9) * int64(f9_38) + h0 := f0f0 + f1f9_76 + f2f8_38 + f3f7_76 + f4f6_38 + f5f5_38 + h1 := f0f1_2 + f2f9_38 + f3f8_38 + f4f7_38 + f5f6_38 + h2 := f0f2_2 + f1f1_2 + f3f9_76 + f4f8_38 + f5f7_76 + f6f6_19 + h3 := f0f3_2 + f1f2_2 + f4f9_38 + f5f8_38 + f6f7_38 + h4 := f0f4_2 + f1f3_4 + f2f2 + f5f9_76 + f6f8_38 + f7f7_38 + h5 := f0f5_2 + f1f4_2 + f2f3_2 + f6f9_38 + f7f8_38 + h6 := f0f6_2 + f1f5_4 + f2f4_2 + f3f3_2 + f7f9_76 + f8f8_19 + h7 := f0f7_2 + f1f6_2 + f2f5_2 + f3f4_2 + f8f9_38 + h8 := f0f8_2 + f1f7_4 + f2f6_2 + f3f5_4 + f4f4 + f9f9_38 + h9 := f0f9_2 + f1f8_2 + f2f7_2 + f3f6_2 + f4f5_2 + var carry [10]int64 + + carry[0] = (h0 + (1 << 25)) >> 26 + h1 += carry[0] + h0 -= carry[0] << 26 + carry[4] = (h4 + (1 << 25)) >> 26 + h5 += carry[4] + h4 -= carry[4] << 26 + + carry[1] = (h1 + (1 << 24)) >> 25 + h2 += carry[1] + h1 -= carry[1] << 25 + carry[5] = (h5 + (1 << 24)) >> 25 + h6 += carry[5] + h5 -= carry[5] << 25 + + carry[2] = (h2 + (1 << 25)) >> 26 + h3 += carry[2] + h2 -= carry[2] << 26 + carry[6] = (h6 + (1 << 25)) >> 26 + h7 += carry[6] + h6 -= carry[6] << 26 + + carry[3] = (h3 + (1 << 24)) >> 25 + h4 += carry[3] + h3 -= carry[3] << 25 + carry[7] = (h7 + (1 << 24)) >> 25 + h8 += carry[7] + h7 -= carry[7] << 25 + + carry[4] = (h4 + (1 << 25)) >> 26 + h5 += carry[4] + h4 -= carry[4] << 26 + carry[8] = (h8 + (1 << 25)) >> 26 + h9 += carry[8] + h8 -= carry[8] << 26 + + carry[9] = (h9 + (1 << 24)) >> 25 + h0 += carry[9] * 19 + h9 -= carry[9] << 25 + + carry[0] = (h0 + (1 << 25)) >> 26 + h1 += carry[0] + h0 -= carry[0] << 26 + + h[0] = int32(h0) + h[1] = int32(h1) + h[2] = int32(h2) + h[3] = int32(h3) + h[4] = int32(h4) + h[5] = int32(h5) + h[6] = int32(h6) + h[7] = int32(h7) + h[8] = int32(h8) + h[9] = int32(h9) +} + +// feMul121666 calculates h = f * 121666. Can overlap h with f. +// +// Preconditions: +// |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. +// +// Postconditions: +// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. +func feMul121666(h, f *fieldElement) { + h0 := int64(f[0]) * 121666 + h1 := int64(f[1]) * 121666 + h2 := int64(f[2]) * 121666 + h3 := int64(f[3]) * 121666 + h4 := int64(f[4]) * 121666 + h5 := int64(f[5]) * 121666 + h6 := int64(f[6]) * 121666 + h7 := int64(f[7]) * 121666 + h8 := int64(f[8]) * 121666 + h9 := int64(f[9]) * 121666 + var carry [10]int64 + + carry[9] = (h9 + (1 << 24)) >> 25 + h0 += carry[9] * 19 + h9 -= carry[9] << 25 + carry[1] = (h1 + (1 << 24)) >> 25 + h2 += carry[1] + h1 -= carry[1] << 25 + carry[3] = (h3 + (1 << 24)) >> 25 + h4 += carry[3] + h3 -= carry[3] << 25 + carry[5] = (h5 + (1 << 24)) >> 25 + h6 += carry[5] + h5 -= carry[5] << 25 + carry[7] = (h7 + (1 << 24)) >> 25 + h8 += carry[7] + h7 -= carry[7] << 25 + + carry[0] = (h0 + (1 << 25)) >> 26 + h1 += carry[0] + h0 -= carry[0] << 26 + carry[2] = (h2 + (1 << 25)) >> 26 + h3 += carry[2] + h2 -= carry[2] << 26 + carry[4] = (h4 + (1 << 25)) >> 26 + h5 += carry[4] + h4 -= carry[4] << 26 + carry[6] = (h6 + (1 << 25)) >> 26 + h7 += carry[6] + h6 -= carry[6] << 26 + carry[8] = (h8 + (1 << 25)) >> 26 + h9 += carry[8] + h8 -= carry[8] << 26 + + h[0] = int32(h0) + h[1] = int32(h1) + h[2] = int32(h2) + h[3] = int32(h3) + h[4] = int32(h4) + h[5] = int32(h5) + h[6] = int32(h6) + h[7] = int32(h7) + h[8] = int32(h8) + h[9] = int32(h9) +} + +// feInvert sets out = z^-1. +func feInvert(out, z *fieldElement) { + var t0, t1, t2, t3 fieldElement + var i int + + feSquare(&t0, z) + for i = 1; i < 1; i++ { + feSquare(&t0, &t0) + } + feSquare(&t1, &t0) + for i = 1; i < 2; i++ { + feSquare(&t1, &t1) + } + feMul(&t1, z, &t1) + feMul(&t0, &t0, &t1) + feSquare(&t2, &t0) + for i = 1; i < 1; i++ { + feSquare(&t2, &t2) + } + feMul(&t1, &t1, &t2) + feSquare(&t2, &t1) + for i = 1; i < 5; i++ { + feSquare(&t2, &t2) + } + feMul(&t1, &t2, &t1) + feSquare(&t2, &t1) + for i = 1; i < 10; i++ { + feSquare(&t2, &t2) + } + feMul(&t2, &t2, &t1) + feSquare(&t3, &t2) + for i = 1; i < 20; i++ { + feSquare(&t3, &t3) + } + feMul(&t2, &t3, &t2) + feSquare(&t2, &t2) + for i = 1; i < 10; i++ { + feSquare(&t2, &t2) + } + feMul(&t1, &t2, &t1) + feSquare(&t2, &t1) + for i = 1; i < 50; i++ { + feSquare(&t2, &t2) + } + feMul(&t2, &t2, &t1) + feSquare(&t3, &t2) + for i = 1; i < 100; i++ { + feSquare(&t3, &t3) + } + feMul(&t2, &t3, &t2) + feSquare(&t2, &t2) + for i = 1; i < 50; i++ { + feSquare(&t2, &t2) + } + feMul(&t1, &t2, &t1) + feSquare(&t1, &t1) + for i = 1; i < 5; i++ { + feSquare(&t1, &t1) + } + feMul(out, &t1, &t0) +} + +func scalarMult(out, in, base *[32]byte) { + var e [32]byte + + copy(e[:], in[:]) + e[0] &= 248 + e[31] &= 127 + e[31] |= 64 + + var x1, x2, z2, x3, z3, tmp0, tmp1 fieldElement + feFromBytes(&x1, base) + feOne(&x2) + feCopy(&x3, &x1) + feOne(&z3) + + swap := int32(0) + for pos := 254; pos >= 0; pos-- { + b := e[pos/8] >> uint(pos&7) + b &= 1 + swap ^= int32(b) + feCSwap(&x2, &x3, swap) + feCSwap(&z2, &z3, swap) + swap = int32(b) + + feSub(&tmp0, &x3, &z3) + feSub(&tmp1, &x2, &z2) + feAdd(&x2, &x2, &z2) + feAdd(&z2, &x3, &z3) + feMul(&z3, &tmp0, &x2) + feMul(&z2, &z2, &tmp1) + feSquare(&tmp0, &tmp1) + feSquare(&tmp1, &x2) + feAdd(&x3, &z3, &z2) + feSub(&z2, &z3, &z2) + feMul(&x2, &tmp1, &tmp0) + feSub(&tmp1, &tmp1, &tmp0) + feSquare(&z2, &z2) + feMul121666(&z3, &tmp1) + feSquare(&x3, &x3) + feAdd(&tmp0, &tmp0, &z3) + feMul(&z3, &x1, &z2) + feMul(&z2, &tmp1, &tmp0) + } + + feCSwap(&x2, &x3, swap) + feCSwap(&z2, &z3, swap) + + feInvert(&z2, &z2) + feMul(&x2, &x2, &z2) + feToBytes(out, &x2) +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/curve25519/doc.go b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/curve25519/doc.go new file mode 100644 index 0000000000..da9b10d9c1 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/curve25519/doc.go @@ -0,0 +1,23 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package curve25519 provides an implementation of scalar multiplication on +// the elliptic curve known as curve25519. See https://cr.yp.to/ecdh.html +package curve25519 // import "golang.org/x/crypto/curve25519" + +// basePoint is the x coordinate of the generator of the curve. +var basePoint = [32]byte{9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + +// ScalarMult sets dst to the product in*base where dst and base are the x +// coordinates of group points and all values are in little-endian form. +func ScalarMult(dst, in, base *[32]byte) { + scalarMult(dst, in, base) +} + +// ScalarBaseMult sets dst to the product in*base where dst and base are the x +// coordinates of group points, base is the standard generator and all values +// are in little-endian form. +func ScalarBaseMult(dst, in *[32]byte) { + ScalarMult(dst, in, &basePoint) +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/curve25519/freeze_amd64.s b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/curve25519/freeze_amd64.s new file mode 100644 index 0000000000..390816106e --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/curve25519/freeze_amd64.s @@ -0,0 +1,73 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This code was translated into a form compatible with 6a from the public +// domain sources in SUPERCOP: https://bench.cr.yp.to/supercop.html + +// +build amd64,!gccgo,!appengine + +#include "const_amd64.h" + +// func freeze(inout *[5]uint64) +TEXT ·freeze(SB),7,$0-8 + MOVQ inout+0(FP), DI + + MOVQ 0(DI),SI + MOVQ 8(DI),DX + MOVQ 16(DI),CX + MOVQ 24(DI),R8 + MOVQ 32(DI),R9 + MOVQ $REDMASK51,AX + MOVQ AX,R10 + SUBQ $18,R10 + MOVQ $3,R11 +REDUCELOOP: + MOVQ SI,R12 + SHRQ $51,R12 + ANDQ AX,SI + ADDQ R12,DX + MOVQ DX,R12 + SHRQ $51,R12 + ANDQ AX,DX + ADDQ R12,CX + MOVQ CX,R12 + SHRQ $51,R12 + ANDQ AX,CX + ADDQ R12,R8 + MOVQ R8,R12 + SHRQ $51,R12 + ANDQ AX,R8 + ADDQ R12,R9 + MOVQ R9,R12 + SHRQ $51,R12 + ANDQ AX,R9 + IMUL3Q $19,R12,R12 + ADDQ R12,SI + SUBQ $1,R11 + JA REDUCELOOP + MOVQ $1,R12 + CMPQ R10,SI + CMOVQLT R11,R12 + CMPQ AX,DX + CMOVQNE R11,R12 + CMPQ AX,CX + CMOVQNE R11,R12 + CMPQ AX,R8 + CMOVQNE R11,R12 + CMPQ AX,R9 + CMOVQNE R11,R12 + NEGQ R12 + ANDQ R12,AX + ANDQ R12,R10 + SUBQ R10,SI + SUBQ AX,DX + SUBQ AX,CX + SUBQ AX,R8 + SUBQ AX,R9 + MOVQ SI,0(DI) + MOVQ DX,8(DI) + MOVQ CX,16(DI) + MOVQ R8,24(DI) + MOVQ R9,32(DI) + RET diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/curve25519/ladderstep_amd64.s b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/curve25519/ladderstep_amd64.s new file mode 100644 index 0000000000..9e9040b250 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/curve25519/ladderstep_amd64.s @@ -0,0 +1,1377 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This code was translated into a form compatible with 6a from the public +// domain sources in SUPERCOP: https://bench.cr.yp.to/supercop.html + +// +build amd64,!gccgo,!appengine + +#include "const_amd64.h" + +// func ladderstep(inout *[5][5]uint64) +TEXT ·ladderstep(SB),0,$296-8 + MOVQ inout+0(FP),DI + + MOVQ 40(DI),SI + MOVQ 48(DI),DX + MOVQ 56(DI),CX + MOVQ 64(DI),R8 + MOVQ 72(DI),R9 + MOVQ SI,AX + MOVQ DX,R10 + MOVQ CX,R11 + MOVQ R8,R12 + MOVQ R9,R13 + ADDQ ·_2P0(SB),AX + ADDQ ·_2P1234(SB),R10 + ADDQ ·_2P1234(SB),R11 + ADDQ ·_2P1234(SB),R12 + ADDQ ·_2P1234(SB),R13 + ADDQ 80(DI),SI + ADDQ 88(DI),DX + ADDQ 96(DI),CX + ADDQ 104(DI),R8 + ADDQ 112(DI),R9 + SUBQ 80(DI),AX + SUBQ 88(DI),R10 + SUBQ 96(DI),R11 + SUBQ 104(DI),R12 + SUBQ 112(DI),R13 + MOVQ SI,0(SP) + MOVQ DX,8(SP) + MOVQ CX,16(SP) + MOVQ R8,24(SP) + MOVQ R9,32(SP) + MOVQ AX,40(SP) + MOVQ R10,48(SP) + MOVQ R11,56(SP) + MOVQ R12,64(SP) + MOVQ R13,72(SP) + MOVQ 40(SP),AX + MULQ 40(SP) + MOVQ AX,SI + MOVQ DX,CX + MOVQ 40(SP),AX + SHLQ $1,AX + MULQ 48(SP) + MOVQ AX,R8 + MOVQ DX,R9 + MOVQ 40(SP),AX + SHLQ $1,AX + MULQ 56(SP) + MOVQ AX,R10 + MOVQ DX,R11 + MOVQ 40(SP),AX + SHLQ $1,AX + MULQ 64(SP) + MOVQ AX,R12 + MOVQ DX,R13 + MOVQ 40(SP),AX + SHLQ $1,AX + MULQ 72(SP) + MOVQ AX,R14 + MOVQ DX,R15 + MOVQ 48(SP),AX + MULQ 48(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 48(SP),AX + SHLQ $1,AX + MULQ 56(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 48(SP),AX + SHLQ $1,AX + MULQ 64(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 48(SP),DX + IMUL3Q $38,DX,AX + MULQ 72(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 56(SP),AX + MULQ 56(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 56(SP),DX + IMUL3Q $38,DX,AX + MULQ 64(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 56(SP),DX + IMUL3Q $38,DX,AX + MULQ 72(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 64(SP),DX + IMUL3Q $19,DX,AX + MULQ 64(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 64(SP),DX + IMUL3Q $38,DX,AX + MULQ 72(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 72(SP),DX + IMUL3Q $19,DX,AX + MULQ 72(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ $REDMASK51,DX + SHLQ $13,CX:SI + ANDQ DX,SI + SHLQ $13,R9:R8 + ANDQ DX,R8 + ADDQ CX,R8 + SHLQ $13,R11:R10 + ANDQ DX,R10 + ADDQ R9,R10 + SHLQ $13,R13:R12 + ANDQ DX,R12 + ADDQ R11,R12 + SHLQ $13,R15:R14 + ANDQ DX,R14 + ADDQ R13,R14 + IMUL3Q $19,R15,CX + ADDQ CX,SI + MOVQ SI,CX + SHRQ $51,CX + ADDQ R8,CX + ANDQ DX,SI + MOVQ CX,R8 + SHRQ $51,CX + ADDQ R10,CX + ANDQ DX,R8 + MOVQ CX,R9 + SHRQ $51,CX + ADDQ R12,CX + ANDQ DX,R9 + MOVQ CX,AX + SHRQ $51,CX + ADDQ R14,CX + ANDQ DX,AX + MOVQ CX,R10 + SHRQ $51,CX + IMUL3Q $19,CX,CX + ADDQ CX,SI + ANDQ DX,R10 + MOVQ SI,80(SP) + MOVQ R8,88(SP) + MOVQ R9,96(SP) + MOVQ AX,104(SP) + MOVQ R10,112(SP) + MOVQ 0(SP),AX + MULQ 0(SP) + MOVQ AX,SI + MOVQ DX,CX + MOVQ 0(SP),AX + SHLQ $1,AX + MULQ 8(SP) + MOVQ AX,R8 + MOVQ DX,R9 + MOVQ 0(SP),AX + SHLQ $1,AX + MULQ 16(SP) + MOVQ AX,R10 + MOVQ DX,R11 + MOVQ 0(SP),AX + SHLQ $1,AX + MULQ 24(SP) + MOVQ AX,R12 + MOVQ DX,R13 + MOVQ 0(SP),AX + SHLQ $1,AX + MULQ 32(SP) + MOVQ AX,R14 + MOVQ DX,R15 + MOVQ 8(SP),AX + MULQ 8(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 8(SP),AX + SHLQ $1,AX + MULQ 16(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 8(SP),AX + SHLQ $1,AX + MULQ 24(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 8(SP),DX + IMUL3Q $38,DX,AX + MULQ 32(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 16(SP),AX + MULQ 16(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 16(SP),DX + IMUL3Q $38,DX,AX + MULQ 24(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 16(SP),DX + IMUL3Q $38,DX,AX + MULQ 32(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 24(SP),DX + IMUL3Q $19,DX,AX + MULQ 24(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 24(SP),DX + IMUL3Q $38,DX,AX + MULQ 32(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 32(SP),DX + IMUL3Q $19,DX,AX + MULQ 32(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ $REDMASK51,DX + SHLQ $13,CX:SI + ANDQ DX,SI + SHLQ $13,R9:R8 + ANDQ DX,R8 + ADDQ CX,R8 + SHLQ $13,R11:R10 + ANDQ DX,R10 + ADDQ R9,R10 + SHLQ $13,R13:R12 + ANDQ DX,R12 + ADDQ R11,R12 + SHLQ $13,R15:R14 + ANDQ DX,R14 + ADDQ R13,R14 + IMUL3Q $19,R15,CX + ADDQ CX,SI + MOVQ SI,CX + SHRQ $51,CX + ADDQ R8,CX + ANDQ DX,SI + MOVQ CX,R8 + SHRQ $51,CX + ADDQ R10,CX + ANDQ DX,R8 + MOVQ CX,R9 + SHRQ $51,CX + ADDQ R12,CX + ANDQ DX,R9 + MOVQ CX,AX + SHRQ $51,CX + ADDQ R14,CX + ANDQ DX,AX + MOVQ CX,R10 + SHRQ $51,CX + IMUL3Q $19,CX,CX + ADDQ CX,SI + ANDQ DX,R10 + MOVQ SI,120(SP) + MOVQ R8,128(SP) + MOVQ R9,136(SP) + MOVQ AX,144(SP) + MOVQ R10,152(SP) + MOVQ SI,SI + MOVQ R8,DX + MOVQ R9,CX + MOVQ AX,R8 + MOVQ R10,R9 + ADDQ ·_2P0(SB),SI + ADDQ ·_2P1234(SB),DX + ADDQ ·_2P1234(SB),CX + ADDQ ·_2P1234(SB),R8 + ADDQ ·_2P1234(SB),R9 + SUBQ 80(SP),SI + SUBQ 88(SP),DX + SUBQ 96(SP),CX + SUBQ 104(SP),R8 + SUBQ 112(SP),R9 + MOVQ SI,160(SP) + MOVQ DX,168(SP) + MOVQ CX,176(SP) + MOVQ R8,184(SP) + MOVQ R9,192(SP) + MOVQ 120(DI),SI + MOVQ 128(DI),DX + MOVQ 136(DI),CX + MOVQ 144(DI),R8 + MOVQ 152(DI),R9 + MOVQ SI,AX + MOVQ DX,R10 + MOVQ CX,R11 + MOVQ R8,R12 + MOVQ R9,R13 + ADDQ ·_2P0(SB),AX + ADDQ ·_2P1234(SB),R10 + ADDQ ·_2P1234(SB),R11 + ADDQ ·_2P1234(SB),R12 + ADDQ ·_2P1234(SB),R13 + ADDQ 160(DI),SI + ADDQ 168(DI),DX + ADDQ 176(DI),CX + ADDQ 184(DI),R8 + ADDQ 192(DI),R9 + SUBQ 160(DI),AX + SUBQ 168(DI),R10 + SUBQ 176(DI),R11 + SUBQ 184(DI),R12 + SUBQ 192(DI),R13 + MOVQ SI,200(SP) + MOVQ DX,208(SP) + MOVQ CX,216(SP) + MOVQ R8,224(SP) + MOVQ R9,232(SP) + MOVQ AX,240(SP) + MOVQ R10,248(SP) + MOVQ R11,256(SP) + MOVQ R12,264(SP) + MOVQ R13,272(SP) + MOVQ 224(SP),SI + IMUL3Q $19,SI,AX + MOVQ AX,280(SP) + MULQ 56(SP) + MOVQ AX,SI + MOVQ DX,CX + MOVQ 232(SP),DX + IMUL3Q $19,DX,AX + MOVQ AX,288(SP) + MULQ 48(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 200(SP),AX + MULQ 40(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 200(SP),AX + MULQ 48(SP) + MOVQ AX,R8 + MOVQ DX,R9 + MOVQ 200(SP),AX + MULQ 56(SP) + MOVQ AX,R10 + MOVQ DX,R11 + MOVQ 200(SP),AX + MULQ 64(SP) + MOVQ AX,R12 + MOVQ DX,R13 + MOVQ 200(SP),AX + MULQ 72(SP) + MOVQ AX,R14 + MOVQ DX,R15 + MOVQ 208(SP),AX + MULQ 40(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 208(SP),AX + MULQ 48(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 208(SP),AX + MULQ 56(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 208(SP),AX + MULQ 64(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 208(SP),DX + IMUL3Q $19,DX,AX + MULQ 72(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 216(SP),AX + MULQ 40(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 216(SP),AX + MULQ 48(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 216(SP),AX + MULQ 56(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 216(SP),DX + IMUL3Q $19,DX,AX + MULQ 64(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 216(SP),DX + IMUL3Q $19,DX,AX + MULQ 72(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 224(SP),AX + MULQ 40(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 224(SP),AX + MULQ 48(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 280(SP),AX + MULQ 64(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 280(SP),AX + MULQ 72(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 232(SP),AX + MULQ 40(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 288(SP),AX + MULQ 56(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 288(SP),AX + MULQ 64(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 288(SP),AX + MULQ 72(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ $REDMASK51,DX + SHLQ $13,CX:SI + ANDQ DX,SI + SHLQ $13,R9:R8 + ANDQ DX,R8 + ADDQ CX,R8 + SHLQ $13,R11:R10 + ANDQ DX,R10 + ADDQ R9,R10 + SHLQ $13,R13:R12 + ANDQ DX,R12 + ADDQ R11,R12 + SHLQ $13,R15:R14 + ANDQ DX,R14 + ADDQ R13,R14 + IMUL3Q $19,R15,CX + ADDQ CX,SI + MOVQ SI,CX + SHRQ $51,CX + ADDQ R8,CX + MOVQ CX,R8 + SHRQ $51,CX + ANDQ DX,SI + ADDQ R10,CX + MOVQ CX,R9 + SHRQ $51,CX + ANDQ DX,R8 + ADDQ R12,CX + MOVQ CX,AX + SHRQ $51,CX + ANDQ DX,R9 + ADDQ R14,CX + MOVQ CX,R10 + SHRQ $51,CX + ANDQ DX,AX + IMUL3Q $19,CX,CX + ADDQ CX,SI + ANDQ DX,R10 + MOVQ SI,40(SP) + MOVQ R8,48(SP) + MOVQ R9,56(SP) + MOVQ AX,64(SP) + MOVQ R10,72(SP) + MOVQ 264(SP),SI + IMUL3Q $19,SI,AX + MOVQ AX,200(SP) + MULQ 16(SP) + MOVQ AX,SI + MOVQ DX,CX + MOVQ 272(SP),DX + IMUL3Q $19,DX,AX + MOVQ AX,208(SP) + MULQ 8(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 240(SP),AX + MULQ 0(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 240(SP),AX + MULQ 8(SP) + MOVQ AX,R8 + MOVQ DX,R9 + MOVQ 240(SP),AX + MULQ 16(SP) + MOVQ AX,R10 + MOVQ DX,R11 + MOVQ 240(SP),AX + MULQ 24(SP) + MOVQ AX,R12 + MOVQ DX,R13 + MOVQ 240(SP),AX + MULQ 32(SP) + MOVQ AX,R14 + MOVQ DX,R15 + MOVQ 248(SP),AX + MULQ 0(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 248(SP),AX + MULQ 8(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 248(SP),AX + MULQ 16(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 248(SP),AX + MULQ 24(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 248(SP),DX + IMUL3Q $19,DX,AX + MULQ 32(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 256(SP),AX + MULQ 0(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 256(SP),AX + MULQ 8(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 256(SP),AX + MULQ 16(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 256(SP),DX + IMUL3Q $19,DX,AX + MULQ 24(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 256(SP),DX + IMUL3Q $19,DX,AX + MULQ 32(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 264(SP),AX + MULQ 0(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 264(SP),AX + MULQ 8(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 200(SP),AX + MULQ 24(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 200(SP),AX + MULQ 32(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 272(SP),AX + MULQ 0(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 208(SP),AX + MULQ 16(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 208(SP),AX + MULQ 24(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 208(SP),AX + MULQ 32(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ $REDMASK51,DX + SHLQ $13,CX:SI + ANDQ DX,SI + SHLQ $13,R9:R8 + ANDQ DX,R8 + ADDQ CX,R8 + SHLQ $13,R11:R10 + ANDQ DX,R10 + ADDQ R9,R10 + SHLQ $13,R13:R12 + ANDQ DX,R12 + ADDQ R11,R12 + SHLQ $13,R15:R14 + ANDQ DX,R14 + ADDQ R13,R14 + IMUL3Q $19,R15,CX + ADDQ CX,SI + MOVQ SI,CX + SHRQ $51,CX + ADDQ R8,CX + MOVQ CX,R8 + SHRQ $51,CX + ANDQ DX,SI + ADDQ R10,CX + MOVQ CX,R9 + SHRQ $51,CX + ANDQ DX,R8 + ADDQ R12,CX + MOVQ CX,AX + SHRQ $51,CX + ANDQ DX,R9 + ADDQ R14,CX + MOVQ CX,R10 + SHRQ $51,CX + ANDQ DX,AX + IMUL3Q $19,CX,CX + ADDQ CX,SI + ANDQ DX,R10 + MOVQ SI,DX + MOVQ R8,CX + MOVQ R9,R11 + MOVQ AX,R12 + MOVQ R10,R13 + ADDQ ·_2P0(SB),DX + ADDQ ·_2P1234(SB),CX + ADDQ ·_2P1234(SB),R11 + ADDQ ·_2P1234(SB),R12 + ADDQ ·_2P1234(SB),R13 + ADDQ 40(SP),SI + ADDQ 48(SP),R8 + ADDQ 56(SP),R9 + ADDQ 64(SP),AX + ADDQ 72(SP),R10 + SUBQ 40(SP),DX + SUBQ 48(SP),CX + SUBQ 56(SP),R11 + SUBQ 64(SP),R12 + SUBQ 72(SP),R13 + MOVQ SI,120(DI) + MOVQ R8,128(DI) + MOVQ R9,136(DI) + MOVQ AX,144(DI) + MOVQ R10,152(DI) + MOVQ DX,160(DI) + MOVQ CX,168(DI) + MOVQ R11,176(DI) + MOVQ R12,184(DI) + MOVQ R13,192(DI) + MOVQ 120(DI),AX + MULQ 120(DI) + MOVQ AX,SI + MOVQ DX,CX + MOVQ 120(DI),AX + SHLQ $1,AX + MULQ 128(DI) + MOVQ AX,R8 + MOVQ DX,R9 + MOVQ 120(DI),AX + SHLQ $1,AX + MULQ 136(DI) + MOVQ AX,R10 + MOVQ DX,R11 + MOVQ 120(DI),AX + SHLQ $1,AX + MULQ 144(DI) + MOVQ AX,R12 + MOVQ DX,R13 + MOVQ 120(DI),AX + SHLQ $1,AX + MULQ 152(DI) + MOVQ AX,R14 + MOVQ DX,R15 + MOVQ 128(DI),AX + MULQ 128(DI) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 128(DI),AX + SHLQ $1,AX + MULQ 136(DI) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 128(DI),AX + SHLQ $1,AX + MULQ 144(DI) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 128(DI),DX + IMUL3Q $38,DX,AX + MULQ 152(DI) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 136(DI),AX + MULQ 136(DI) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 136(DI),DX + IMUL3Q $38,DX,AX + MULQ 144(DI) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 136(DI),DX + IMUL3Q $38,DX,AX + MULQ 152(DI) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 144(DI),DX + IMUL3Q $19,DX,AX + MULQ 144(DI) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 144(DI),DX + IMUL3Q $38,DX,AX + MULQ 152(DI) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 152(DI),DX + IMUL3Q $19,DX,AX + MULQ 152(DI) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ $REDMASK51,DX + SHLQ $13,CX:SI + ANDQ DX,SI + SHLQ $13,R9:R8 + ANDQ DX,R8 + ADDQ CX,R8 + SHLQ $13,R11:R10 + ANDQ DX,R10 + ADDQ R9,R10 + SHLQ $13,R13:R12 + ANDQ DX,R12 + ADDQ R11,R12 + SHLQ $13,R15:R14 + ANDQ DX,R14 + ADDQ R13,R14 + IMUL3Q $19,R15,CX + ADDQ CX,SI + MOVQ SI,CX + SHRQ $51,CX + ADDQ R8,CX + ANDQ DX,SI + MOVQ CX,R8 + SHRQ $51,CX + ADDQ R10,CX + ANDQ DX,R8 + MOVQ CX,R9 + SHRQ $51,CX + ADDQ R12,CX + ANDQ DX,R9 + MOVQ CX,AX + SHRQ $51,CX + ADDQ R14,CX + ANDQ DX,AX + MOVQ CX,R10 + SHRQ $51,CX + IMUL3Q $19,CX,CX + ADDQ CX,SI + ANDQ DX,R10 + MOVQ SI,120(DI) + MOVQ R8,128(DI) + MOVQ R9,136(DI) + MOVQ AX,144(DI) + MOVQ R10,152(DI) + MOVQ 160(DI),AX + MULQ 160(DI) + MOVQ AX,SI + MOVQ DX,CX + MOVQ 160(DI),AX + SHLQ $1,AX + MULQ 168(DI) + MOVQ AX,R8 + MOVQ DX,R9 + MOVQ 160(DI),AX + SHLQ $1,AX + MULQ 176(DI) + MOVQ AX,R10 + MOVQ DX,R11 + MOVQ 160(DI),AX + SHLQ $1,AX + MULQ 184(DI) + MOVQ AX,R12 + MOVQ DX,R13 + MOVQ 160(DI),AX + SHLQ $1,AX + MULQ 192(DI) + MOVQ AX,R14 + MOVQ DX,R15 + MOVQ 168(DI),AX + MULQ 168(DI) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 168(DI),AX + SHLQ $1,AX + MULQ 176(DI) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 168(DI),AX + SHLQ $1,AX + MULQ 184(DI) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 168(DI),DX + IMUL3Q $38,DX,AX + MULQ 192(DI) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 176(DI),AX + MULQ 176(DI) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 176(DI),DX + IMUL3Q $38,DX,AX + MULQ 184(DI) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 176(DI),DX + IMUL3Q $38,DX,AX + MULQ 192(DI) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 184(DI),DX + IMUL3Q $19,DX,AX + MULQ 184(DI) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 184(DI),DX + IMUL3Q $38,DX,AX + MULQ 192(DI) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 192(DI),DX + IMUL3Q $19,DX,AX + MULQ 192(DI) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ $REDMASK51,DX + SHLQ $13,CX:SI + ANDQ DX,SI + SHLQ $13,R9:R8 + ANDQ DX,R8 + ADDQ CX,R8 + SHLQ $13,R11:R10 + ANDQ DX,R10 + ADDQ R9,R10 + SHLQ $13,R13:R12 + ANDQ DX,R12 + ADDQ R11,R12 + SHLQ $13,R15:R14 + ANDQ DX,R14 + ADDQ R13,R14 + IMUL3Q $19,R15,CX + ADDQ CX,SI + MOVQ SI,CX + SHRQ $51,CX + ADDQ R8,CX + ANDQ DX,SI + MOVQ CX,R8 + SHRQ $51,CX + ADDQ R10,CX + ANDQ DX,R8 + MOVQ CX,R9 + SHRQ $51,CX + ADDQ R12,CX + ANDQ DX,R9 + MOVQ CX,AX + SHRQ $51,CX + ADDQ R14,CX + ANDQ DX,AX + MOVQ CX,R10 + SHRQ $51,CX + IMUL3Q $19,CX,CX + ADDQ CX,SI + ANDQ DX,R10 + MOVQ SI,160(DI) + MOVQ R8,168(DI) + MOVQ R9,176(DI) + MOVQ AX,184(DI) + MOVQ R10,192(DI) + MOVQ 184(DI),SI + IMUL3Q $19,SI,AX + MOVQ AX,0(SP) + MULQ 16(DI) + MOVQ AX,SI + MOVQ DX,CX + MOVQ 192(DI),DX + IMUL3Q $19,DX,AX + MOVQ AX,8(SP) + MULQ 8(DI) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 160(DI),AX + MULQ 0(DI) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 160(DI),AX + MULQ 8(DI) + MOVQ AX,R8 + MOVQ DX,R9 + MOVQ 160(DI),AX + MULQ 16(DI) + MOVQ AX,R10 + MOVQ DX,R11 + MOVQ 160(DI),AX + MULQ 24(DI) + MOVQ AX,R12 + MOVQ DX,R13 + MOVQ 160(DI),AX + MULQ 32(DI) + MOVQ AX,R14 + MOVQ DX,R15 + MOVQ 168(DI),AX + MULQ 0(DI) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 168(DI),AX + MULQ 8(DI) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 168(DI),AX + MULQ 16(DI) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 168(DI),AX + MULQ 24(DI) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 168(DI),DX + IMUL3Q $19,DX,AX + MULQ 32(DI) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 176(DI),AX + MULQ 0(DI) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 176(DI),AX + MULQ 8(DI) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 176(DI),AX + MULQ 16(DI) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 176(DI),DX + IMUL3Q $19,DX,AX + MULQ 24(DI) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 176(DI),DX + IMUL3Q $19,DX,AX + MULQ 32(DI) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 184(DI),AX + MULQ 0(DI) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 184(DI),AX + MULQ 8(DI) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 0(SP),AX + MULQ 24(DI) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 0(SP),AX + MULQ 32(DI) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 192(DI),AX + MULQ 0(DI) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 8(SP),AX + MULQ 16(DI) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 8(SP),AX + MULQ 24(DI) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 8(SP),AX + MULQ 32(DI) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ $REDMASK51,DX + SHLQ $13,CX:SI + ANDQ DX,SI + SHLQ $13,R9:R8 + ANDQ DX,R8 + ADDQ CX,R8 + SHLQ $13,R11:R10 + ANDQ DX,R10 + ADDQ R9,R10 + SHLQ $13,R13:R12 + ANDQ DX,R12 + ADDQ R11,R12 + SHLQ $13,R15:R14 + ANDQ DX,R14 + ADDQ R13,R14 + IMUL3Q $19,R15,CX + ADDQ CX,SI + MOVQ SI,CX + SHRQ $51,CX + ADDQ R8,CX + MOVQ CX,R8 + SHRQ $51,CX + ANDQ DX,SI + ADDQ R10,CX + MOVQ CX,R9 + SHRQ $51,CX + ANDQ DX,R8 + ADDQ R12,CX + MOVQ CX,AX + SHRQ $51,CX + ANDQ DX,R9 + ADDQ R14,CX + MOVQ CX,R10 + SHRQ $51,CX + ANDQ DX,AX + IMUL3Q $19,CX,CX + ADDQ CX,SI + ANDQ DX,R10 + MOVQ SI,160(DI) + MOVQ R8,168(DI) + MOVQ R9,176(DI) + MOVQ AX,184(DI) + MOVQ R10,192(DI) + MOVQ 144(SP),SI + IMUL3Q $19,SI,AX + MOVQ AX,0(SP) + MULQ 96(SP) + MOVQ AX,SI + MOVQ DX,CX + MOVQ 152(SP),DX + IMUL3Q $19,DX,AX + MOVQ AX,8(SP) + MULQ 88(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 120(SP),AX + MULQ 80(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 120(SP),AX + MULQ 88(SP) + MOVQ AX,R8 + MOVQ DX,R9 + MOVQ 120(SP),AX + MULQ 96(SP) + MOVQ AX,R10 + MOVQ DX,R11 + MOVQ 120(SP),AX + MULQ 104(SP) + MOVQ AX,R12 + MOVQ DX,R13 + MOVQ 120(SP),AX + MULQ 112(SP) + MOVQ AX,R14 + MOVQ DX,R15 + MOVQ 128(SP),AX + MULQ 80(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 128(SP),AX + MULQ 88(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 128(SP),AX + MULQ 96(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 128(SP),AX + MULQ 104(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 128(SP),DX + IMUL3Q $19,DX,AX + MULQ 112(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 136(SP),AX + MULQ 80(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 136(SP),AX + MULQ 88(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 136(SP),AX + MULQ 96(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 136(SP),DX + IMUL3Q $19,DX,AX + MULQ 104(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 136(SP),DX + IMUL3Q $19,DX,AX + MULQ 112(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 144(SP),AX + MULQ 80(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 144(SP),AX + MULQ 88(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 0(SP),AX + MULQ 104(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 0(SP),AX + MULQ 112(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 152(SP),AX + MULQ 80(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 8(SP),AX + MULQ 96(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 8(SP),AX + MULQ 104(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 8(SP),AX + MULQ 112(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ $REDMASK51,DX + SHLQ $13,CX:SI + ANDQ DX,SI + SHLQ $13,R9:R8 + ANDQ DX,R8 + ADDQ CX,R8 + SHLQ $13,R11:R10 + ANDQ DX,R10 + ADDQ R9,R10 + SHLQ $13,R13:R12 + ANDQ DX,R12 + ADDQ R11,R12 + SHLQ $13,R15:R14 + ANDQ DX,R14 + ADDQ R13,R14 + IMUL3Q $19,R15,CX + ADDQ CX,SI + MOVQ SI,CX + SHRQ $51,CX + ADDQ R8,CX + MOVQ CX,R8 + SHRQ $51,CX + ANDQ DX,SI + ADDQ R10,CX + MOVQ CX,R9 + SHRQ $51,CX + ANDQ DX,R8 + ADDQ R12,CX + MOVQ CX,AX + SHRQ $51,CX + ANDQ DX,R9 + ADDQ R14,CX + MOVQ CX,R10 + SHRQ $51,CX + ANDQ DX,AX + IMUL3Q $19,CX,CX + ADDQ CX,SI + ANDQ DX,R10 + MOVQ SI,40(DI) + MOVQ R8,48(DI) + MOVQ R9,56(DI) + MOVQ AX,64(DI) + MOVQ R10,72(DI) + MOVQ 160(SP),AX + MULQ ·_121666_213(SB) + SHRQ $13,AX + MOVQ AX,SI + MOVQ DX,CX + MOVQ 168(SP),AX + MULQ ·_121666_213(SB) + SHRQ $13,AX + ADDQ AX,CX + MOVQ DX,R8 + MOVQ 176(SP),AX + MULQ ·_121666_213(SB) + SHRQ $13,AX + ADDQ AX,R8 + MOVQ DX,R9 + MOVQ 184(SP),AX + MULQ ·_121666_213(SB) + SHRQ $13,AX + ADDQ AX,R9 + MOVQ DX,R10 + MOVQ 192(SP),AX + MULQ ·_121666_213(SB) + SHRQ $13,AX + ADDQ AX,R10 + IMUL3Q $19,DX,DX + ADDQ DX,SI + ADDQ 80(SP),SI + ADDQ 88(SP),CX + ADDQ 96(SP),R8 + ADDQ 104(SP),R9 + ADDQ 112(SP),R10 + MOVQ SI,80(DI) + MOVQ CX,88(DI) + MOVQ R8,96(DI) + MOVQ R9,104(DI) + MOVQ R10,112(DI) + MOVQ 104(DI),SI + IMUL3Q $19,SI,AX + MOVQ AX,0(SP) + MULQ 176(SP) + MOVQ AX,SI + MOVQ DX,CX + MOVQ 112(DI),DX + IMUL3Q $19,DX,AX + MOVQ AX,8(SP) + MULQ 168(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 80(DI),AX + MULQ 160(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 80(DI),AX + MULQ 168(SP) + MOVQ AX,R8 + MOVQ DX,R9 + MOVQ 80(DI),AX + MULQ 176(SP) + MOVQ AX,R10 + MOVQ DX,R11 + MOVQ 80(DI),AX + MULQ 184(SP) + MOVQ AX,R12 + MOVQ DX,R13 + MOVQ 80(DI),AX + MULQ 192(SP) + MOVQ AX,R14 + MOVQ DX,R15 + MOVQ 88(DI),AX + MULQ 160(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 88(DI),AX + MULQ 168(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 88(DI),AX + MULQ 176(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 88(DI),AX + MULQ 184(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 88(DI),DX + IMUL3Q $19,DX,AX + MULQ 192(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 96(DI),AX + MULQ 160(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 96(DI),AX + MULQ 168(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 96(DI),AX + MULQ 176(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 96(DI),DX + IMUL3Q $19,DX,AX + MULQ 184(SP) + ADDQ AX,SI + ADCQ DX,CX + MOVQ 96(DI),DX + IMUL3Q $19,DX,AX + MULQ 192(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 104(DI),AX + MULQ 160(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 104(DI),AX + MULQ 168(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 0(SP),AX + MULQ 184(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 0(SP),AX + MULQ 192(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 112(DI),AX + MULQ 160(SP) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 8(SP),AX + MULQ 176(SP) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 8(SP),AX + MULQ 184(SP) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 8(SP),AX + MULQ 192(SP) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ $REDMASK51,DX + SHLQ $13,CX:SI + ANDQ DX,SI + SHLQ $13,R9:R8 + ANDQ DX,R8 + ADDQ CX,R8 + SHLQ $13,R11:R10 + ANDQ DX,R10 + ADDQ R9,R10 + SHLQ $13,R13:R12 + ANDQ DX,R12 + ADDQ R11,R12 + SHLQ $13,R15:R14 + ANDQ DX,R14 + ADDQ R13,R14 + IMUL3Q $19,R15,CX + ADDQ CX,SI + MOVQ SI,CX + SHRQ $51,CX + ADDQ R8,CX + MOVQ CX,R8 + SHRQ $51,CX + ANDQ DX,SI + ADDQ R10,CX + MOVQ CX,R9 + SHRQ $51,CX + ANDQ DX,R8 + ADDQ R12,CX + MOVQ CX,AX + SHRQ $51,CX + ANDQ DX,R9 + ADDQ R14,CX + MOVQ CX,R10 + SHRQ $51,CX + ANDQ DX,AX + IMUL3Q $19,CX,CX + ADDQ CX,SI + ANDQ DX,R10 + MOVQ SI,80(DI) + MOVQ R8,88(DI) + MOVQ R9,96(DI) + MOVQ AX,104(DI) + MOVQ R10,112(DI) + RET diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/curve25519/mont25519_amd64.go b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/curve25519/mont25519_amd64.go new file mode 100644 index 0000000000..5822bd5338 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/curve25519/mont25519_amd64.go @@ -0,0 +1,240 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build amd64,!gccgo,!appengine + +package curve25519 + +// These functions are implemented in the .s files. The names of the functions +// in the rest of the file are also taken from the SUPERCOP sources to help +// people following along. + +//go:noescape + +func cswap(inout *[5]uint64, v uint64) + +//go:noescape + +func ladderstep(inout *[5][5]uint64) + +//go:noescape + +func freeze(inout *[5]uint64) + +//go:noescape + +func mul(dest, a, b *[5]uint64) + +//go:noescape + +func square(out, in *[5]uint64) + +// mladder uses a Montgomery ladder to calculate (xr/zr) *= s. +func mladder(xr, zr *[5]uint64, s *[32]byte) { + var work [5][5]uint64 + + work[0] = *xr + setint(&work[1], 1) + setint(&work[2], 0) + work[3] = *xr + setint(&work[4], 1) + + j := uint(6) + var prevbit byte + + for i := 31; i >= 0; i-- { + for j < 8 { + bit := ((*s)[i] >> j) & 1 + swap := bit ^ prevbit + prevbit = bit + cswap(&work[1], uint64(swap)) + ladderstep(&work) + j-- + } + j = 7 + } + + *xr = work[1] + *zr = work[2] +} + +func scalarMult(out, in, base *[32]byte) { + var e [32]byte + copy(e[:], (*in)[:]) + e[0] &= 248 + e[31] &= 127 + e[31] |= 64 + + var t, z [5]uint64 + unpack(&t, base) + mladder(&t, &z, &e) + invert(&z, &z) + mul(&t, &t, &z) + pack(out, &t) +} + +func setint(r *[5]uint64, v uint64) { + r[0] = v + r[1] = 0 + r[2] = 0 + r[3] = 0 + r[4] = 0 +} + +// unpack sets r = x where r consists of 5, 51-bit limbs in little-endian +// order. +func unpack(r *[5]uint64, x *[32]byte) { + r[0] = uint64(x[0]) | + uint64(x[1])<<8 | + uint64(x[2])<<16 | + uint64(x[3])<<24 | + uint64(x[4])<<32 | + uint64(x[5])<<40 | + uint64(x[6]&7)<<48 + + r[1] = uint64(x[6])>>3 | + uint64(x[7])<<5 | + uint64(x[8])<<13 | + uint64(x[9])<<21 | + uint64(x[10])<<29 | + uint64(x[11])<<37 | + uint64(x[12]&63)<<45 + + r[2] = uint64(x[12])>>6 | + uint64(x[13])<<2 | + uint64(x[14])<<10 | + uint64(x[15])<<18 | + uint64(x[16])<<26 | + uint64(x[17])<<34 | + uint64(x[18])<<42 | + uint64(x[19]&1)<<50 + + r[3] = uint64(x[19])>>1 | + uint64(x[20])<<7 | + uint64(x[21])<<15 | + uint64(x[22])<<23 | + uint64(x[23])<<31 | + uint64(x[24])<<39 | + uint64(x[25]&15)<<47 + + r[4] = uint64(x[25])>>4 | + uint64(x[26])<<4 | + uint64(x[27])<<12 | + uint64(x[28])<<20 | + uint64(x[29])<<28 | + uint64(x[30])<<36 | + uint64(x[31]&127)<<44 +} + +// pack sets out = x where out is the usual, little-endian form of the 5, +// 51-bit limbs in x. +func pack(out *[32]byte, x *[5]uint64) { + t := *x + freeze(&t) + + out[0] = byte(t[0]) + out[1] = byte(t[0] >> 8) + out[2] = byte(t[0] >> 16) + out[3] = byte(t[0] >> 24) + out[4] = byte(t[0] >> 32) + out[5] = byte(t[0] >> 40) + out[6] = byte(t[0] >> 48) + + out[6] ^= byte(t[1]<<3) & 0xf8 + out[7] = byte(t[1] >> 5) + out[8] = byte(t[1] >> 13) + out[9] = byte(t[1] >> 21) + out[10] = byte(t[1] >> 29) + out[11] = byte(t[1] >> 37) + out[12] = byte(t[1] >> 45) + + out[12] ^= byte(t[2]<<6) & 0xc0 + out[13] = byte(t[2] >> 2) + out[14] = byte(t[2] >> 10) + out[15] = byte(t[2] >> 18) + out[16] = byte(t[2] >> 26) + out[17] = byte(t[2] >> 34) + out[18] = byte(t[2] >> 42) + out[19] = byte(t[2] >> 50) + + out[19] ^= byte(t[3]<<1) & 0xfe + out[20] = byte(t[3] >> 7) + out[21] = byte(t[3] >> 15) + out[22] = byte(t[3] >> 23) + out[23] = byte(t[3] >> 31) + out[24] = byte(t[3] >> 39) + out[25] = byte(t[3] >> 47) + + out[25] ^= byte(t[4]<<4) & 0xf0 + out[26] = byte(t[4] >> 4) + out[27] = byte(t[4] >> 12) + out[28] = byte(t[4] >> 20) + out[29] = byte(t[4] >> 28) + out[30] = byte(t[4] >> 36) + out[31] = byte(t[4] >> 44) +} + +// invert calculates r = x^-1 mod p using Fermat's little theorem. +func invert(r *[5]uint64, x *[5]uint64) { + var z2, z9, z11, z2_5_0, z2_10_0, z2_20_0, z2_50_0, z2_100_0, t [5]uint64 + + square(&z2, x) /* 2 */ + square(&t, &z2) /* 4 */ + square(&t, &t) /* 8 */ + mul(&z9, &t, x) /* 9 */ + mul(&z11, &z9, &z2) /* 11 */ + square(&t, &z11) /* 22 */ + mul(&z2_5_0, &t, &z9) /* 2^5 - 2^0 = 31 */ + + square(&t, &z2_5_0) /* 2^6 - 2^1 */ + for i := 1; i < 5; i++ { /* 2^20 - 2^10 */ + square(&t, &t) + } + mul(&z2_10_0, &t, &z2_5_0) /* 2^10 - 2^0 */ + + square(&t, &z2_10_0) /* 2^11 - 2^1 */ + for i := 1; i < 10; i++ { /* 2^20 - 2^10 */ + square(&t, &t) + } + mul(&z2_20_0, &t, &z2_10_0) /* 2^20 - 2^0 */ + + square(&t, &z2_20_0) /* 2^21 - 2^1 */ + for i := 1; i < 20; i++ { /* 2^40 - 2^20 */ + square(&t, &t) + } + mul(&t, &t, &z2_20_0) /* 2^40 - 2^0 */ + + square(&t, &t) /* 2^41 - 2^1 */ + for i := 1; i < 10; i++ { /* 2^50 - 2^10 */ + square(&t, &t) + } + mul(&z2_50_0, &t, &z2_10_0) /* 2^50 - 2^0 */ + + square(&t, &z2_50_0) /* 2^51 - 2^1 */ + for i := 1; i < 50; i++ { /* 2^100 - 2^50 */ + square(&t, &t) + } + mul(&z2_100_0, &t, &z2_50_0) /* 2^100 - 2^0 */ + + square(&t, &z2_100_0) /* 2^101 - 2^1 */ + for i := 1; i < 100; i++ { /* 2^200 - 2^100 */ + square(&t, &t) + } + mul(&t, &t, &z2_100_0) /* 2^200 - 2^0 */ + + square(&t, &t) /* 2^201 - 2^1 */ + for i := 1; i < 50; i++ { /* 2^250 - 2^50 */ + square(&t, &t) + } + mul(&t, &t, &z2_50_0) /* 2^250 - 2^0 */ + + square(&t, &t) /* 2^251 - 2^1 */ + square(&t, &t) /* 2^252 - 2^2 */ + square(&t, &t) /* 2^253 - 2^3 */ + + square(&t, &t) /* 2^254 - 2^4 */ + + square(&t, &t) /* 2^255 - 2^5 */ + mul(r, &t, &z11) /* 2^255 - 21 */ +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/curve25519/mul_amd64.s b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/curve25519/mul_amd64.s new file mode 100644 index 0000000000..5ce80a2e56 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/curve25519/mul_amd64.s @@ -0,0 +1,169 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This code was translated into a form compatible with 6a from the public +// domain sources in SUPERCOP: https://bench.cr.yp.to/supercop.html + +// +build amd64,!gccgo,!appengine + +#include "const_amd64.h" + +// func mul(dest, a, b *[5]uint64) +TEXT ·mul(SB),0,$16-24 + MOVQ dest+0(FP), DI + MOVQ a+8(FP), SI + MOVQ b+16(FP), DX + + MOVQ DX,CX + MOVQ 24(SI),DX + IMUL3Q $19,DX,AX + MOVQ AX,0(SP) + MULQ 16(CX) + MOVQ AX,R8 + MOVQ DX,R9 + MOVQ 32(SI),DX + IMUL3Q $19,DX,AX + MOVQ AX,8(SP) + MULQ 8(CX) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 0(SI),AX + MULQ 0(CX) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 0(SI),AX + MULQ 8(CX) + MOVQ AX,R10 + MOVQ DX,R11 + MOVQ 0(SI),AX + MULQ 16(CX) + MOVQ AX,R12 + MOVQ DX,R13 + MOVQ 0(SI),AX + MULQ 24(CX) + MOVQ AX,R14 + MOVQ DX,R15 + MOVQ 0(SI),AX + MULQ 32(CX) + MOVQ AX,BX + MOVQ DX,BP + MOVQ 8(SI),AX + MULQ 0(CX) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 8(SI),AX + MULQ 8(CX) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 8(SI),AX + MULQ 16(CX) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 8(SI),AX + MULQ 24(CX) + ADDQ AX,BX + ADCQ DX,BP + MOVQ 8(SI),DX + IMUL3Q $19,DX,AX + MULQ 32(CX) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 16(SI),AX + MULQ 0(CX) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 16(SI),AX + MULQ 8(CX) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 16(SI),AX + MULQ 16(CX) + ADDQ AX,BX + ADCQ DX,BP + MOVQ 16(SI),DX + IMUL3Q $19,DX,AX + MULQ 24(CX) + ADDQ AX,R8 + ADCQ DX,R9 + MOVQ 16(SI),DX + IMUL3Q $19,DX,AX + MULQ 32(CX) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 24(SI),AX + MULQ 0(CX) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ 24(SI),AX + MULQ 8(CX) + ADDQ AX,BX + ADCQ DX,BP + MOVQ 0(SP),AX + MULQ 24(CX) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 0(SP),AX + MULQ 32(CX) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 32(SI),AX + MULQ 0(CX) + ADDQ AX,BX + ADCQ DX,BP + MOVQ 8(SP),AX + MULQ 16(CX) + ADDQ AX,R10 + ADCQ DX,R11 + MOVQ 8(SP),AX + MULQ 24(CX) + ADDQ AX,R12 + ADCQ DX,R13 + MOVQ 8(SP),AX + MULQ 32(CX) + ADDQ AX,R14 + ADCQ DX,R15 + MOVQ $REDMASK51,SI + SHLQ $13,R9:R8 + ANDQ SI,R8 + SHLQ $13,R11:R10 + ANDQ SI,R10 + ADDQ R9,R10 + SHLQ $13,R13:R12 + ANDQ SI,R12 + ADDQ R11,R12 + SHLQ $13,R15:R14 + ANDQ SI,R14 + ADDQ R13,R14 + SHLQ $13,BP:BX + ANDQ SI,BX + ADDQ R15,BX + IMUL3Q $19,BP,DX + ADDQ DX,R8 + MOVQ R8,DX + SHRQ $51,DX + ADDQ R10,DX + MOVQ DX,CX + SHRQ $51,DX + ANDQ SI,R8 + ADDQ R12,DX + MOVQ DX,R9 + SHRQ $51,DX + ANDQ SI,CX + ADDQ R14,DX + MOVQ DX,AX + SHRQ $51,DX + ANDQ SI,R9 + ADDQ BX,DX + MOVQ DX,R10 + SHRQ $51,DX + ANDQ SI,AX + IMUL3Q $19,DX,DX + ADDQ DX,R8 + ANDQ SI,R10 + MOVQ R8,0(DI) + MOVQ CX,8(DI) + MOVQ R9,16(DI) + MOVQ AX,24(DI) + MOVQ R10,32(DI) + RET diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/curve25519/square_amd64.s b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/curve25519/square_amd64.s new file mode 100644 index 0000000000..12f73734ff --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/curve25519/square_amd64.s @@ -0,0 +1,132 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This code was translated into a form compatible with 6a from the public +// domain sources in SUPERCOP: https://bench.cr.yp.to/supercop.html + +// +build amd64,!gccgo,!appengine + +#include "const_amd64.h" + +// func square(out, in *[5]uint64) +TEXT ·square(SB),7,$0-16 + MOVQ out+0(FP), DI + MOVQ in+8(FP), SI + + MOVQ 0(SI),AX + MULQ 0(SI) + MOVQ AX,CX + MOVQ DX,R8 + MOVQ 0(SI),AX + SHLQ $1,AX + MULQ 8(SI) + MOVQ AX,R9 + MOVQ DX,R10 + MOVQ 0(SI),AX + SHLQ $1,AX + MULQ 16(SI) + MOVQ AX,R11 + MOVQ DX,R12 + MOVQ 0(SI),AX + SHLQ $1,AX + MULQ 24(SI) + MOVQ AX,R13 + MOVQ DX,R14 + MOVQ 0(SI),AX + SHLQ $1,AX + MULQ 32(SI) + MOVQ AX,R15 + MOVQ DX,BX + MOVQ 8(SI),AX + MULQ 8(SI) + ADDQ AX,R11 + ADCQ DX,R12 + MOVQ 8(SI),AX + SHLQ $1,AX + MULQ 16(SI) + ADDQ AX,R13 + ADCQ DX,R14 + MOVQ 8(SI),AX + SHLQ $1,AX + MULQ 24(SI) + ADDQ AX,R15 + ADCQ DX,BX + MOVQ 8(SI),DX + IMUL3Q $38,DX,AX + MULQ 32(SI) + ADDQ AX,CX + ADCQ DX,R8 + MOVQ 16(SI),AX + MULQ 16(SI) + ADDQ AX,R15 + ADCQ DX,BX + MOVQ 16(SI),DX + IMUL3Q $38,DX,AX + MULQ 24(SI) + ADDQ AX,CX + ADCQ DX,R8 + MOVQ 16(SI),DX + IMUL3Q $38,DX,AX + MULQ 32(SI) + ADDQ AX,R9 + ADCQ DX,R10 + MOVQ 24(SI),DX + IMUL3Q $19,DX,AX + MULQ 24(SI) + ADDQ AX,R9 + ADCQ DX,R10 + MOVQ 24(SI),DX + IMUL3Q $38,DX,AX + MULQ 32(SI) + ADDQ AX,R11 + ADCQ DX,R12 + MOVQ 32(SI),DX + IMUL3Q $19,DX,AX + MULQ 32(SI) + ADDQ AX,R13 + ADCQ DX,R14 + MOVQ $REDMASK51,SI + SHLQ $13,R8:CX + ANDQ SI,CX + SHLQ $13,R10:R9 + ANDQ SI,R9 + ADDQ R8,R9 + SHLQ $13,R12:R11 + ANDQ SI,R11 + ADDQ R10,R11 + SHLQ $13,R14:R13 + ANDQ SI,R13 + ADDQ R12,R13 + SHLQ $13,BX:R15 + ANDQ SI,R15 + ADDQ R14,R15 + IMUL3Q $19,BX,DX + ADDQ DX,CX + MOVQ CX,DX + SHRQ $51,DX + ADDQ R9,DX + ANDQ SI,CX + MOVQ DX,R8 + SHRQ $51,DX + ADDQ R11,DX + ANDQ SI,R8 + MOVQ DX,R9 + SHRQ $51,DX + ADDQ R13,DX + ANDQ SI,R9 + MOVQ DX,AX + SHRQ $51,DX + ADDQ R15,DX + ANDQ SI,AX + MOVQ DX,R10 + SHRQ $51,DX + IMUL3Q $19,DX,DX + ADDQ DX,CX + ANDQ SI,R10 + MOVQ CX,0(DI) + MOVQ R8,8(DI) + MOVQ R9,16(DI) + MOVQ AX,24(DI) + MOVQ R10,32(DI) + RET diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/otr/libotr_test_helper.c b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/otr/libotr_test_helper.c new file mode 100644 index 0000000000..b3ca072d48 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/otr/libotr_test_helper.c @@ -0,0 +1,197 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This code can be compiled and used to test the otr package against libotr. +// See otr_test.go. + +// +build ignore + +#include +#include +#include + +#include +#include +#include + +static int g_session_established = 0; + +OtrlPolicy policy(void *opdata, ConnContext *context) { + return OTRL_POLICY_ALWAYS; +} + +int is_logged_in(void *opdata, const char *accountname, const char *protocol, + const char *recipient) { + return 1; +} + +void inject_message(void *opdata, const char *accountname, const char *protocol, + const char *recipient, const char *message) { + printf("%s\n", message); + fflush(stdout); + fprintf(stderr, "libotr helper sent: %s\n", message); +} + +void update_context_list(void *opdata) {} + +void new_fingerprint(void *opdata, OtrlUserState us, const char *accountname, + const char *protocol, const char *username, + unsigned char fingerprint[20]) { + fprintf(stderr, "NEW FINGERPRINT\n"); + g_session_established = 1; +} + +void write_fingerprints(void *opdata) {} + +void gone_secure(void *opdata, ConnContext *context) {} + +void gone_insecure(void *opdata, ConnContext *context) {} + +void still_secure(void *opdata, ConnContext *context, int is_reply) {} + +int max_message_size(void *opdata, ConnContext *context) { return 99999; } + +const char *account_name(void *opdata, const char *account, + const char *protocol) { + return "ACCOUNT"; +} + +void account_name_free(void *opdata, const char *account_name) {} + +const char *error_message(void *opdata, ConnContext *context, + OtrlErrorCode err_code) { + return "ERR"; +} + +void error_message_free(void *opdata, const char *msg) {} + +void resent_msg_prefix_free(void *opdata, const char *prefix) {} + +void handle_smp_event(void *opdata, OtrlSMPEvent smp_event, + ConnContext *context, unsigned short progress_event, + char *question) {} + +void handle_msg_event(void *opdata, OtrlMessageEvent msg_event, + ConnContext *context, const char *message, + gcry_error_t err) { + fprintf(stderr, "msg event: %d %s\n", msg_event, message); +} + +OtrlMessageAppOps uiops = { + policy, + NULL, + is_logged_in, + inject_message, + update_context_list, + new_fingerprint, + write_fingerprints, + gone_secure, + gone_insecure, + still_secure, + max_message_size, + account_name, + account_name_free, + NULL, /* received_symkey */ + error_message, + error_message_free, + NULL, /* resent_msg_prefix */ + resent_msg_prefix_free, + handle_smp_event, + handle_msg_event, + NULL /* create_instag */, + NULL /* convert_msg */, + NULL /* convert_free */, + NULL /* timer_control */, +}; + +static const char kPrivateKeyData[] = + "(privkeys (account (name \"account\") (protocol proto) (private-key (dsa " + "(p " + "#00FC07ABCF0DC916AFF6E9AE47BEF60C7AB9B4D6B2469E436630E36F8A489BE812486A09F" + "30B71224508654940A835301ACC525A4FF133FC152CC53DCC59D65C30A54F1993FE13FE63E" + "5823D4C746DB21B90F9B9C00B49EC7404AB1D929BA7FBA12F2E45C6E0A651689750E8528AB" + "8C031D3561FECEE72EBB4A090D450A9B7A857#) (q " + "#00997BD266EF7B1F60A5C23F3A741F2AEFD07A2081#) (g " + "#535E360E8A95EBA46A4F7DE50AD6E9B2A6DB785A66B64EB9F20338D2A3E8FB0E94725848F" + "1AA6CC567CB83A1CC517EC806F2E92EAE71457E80B2210A189B91250779434B41FC8A8873F" + "6DB94BEA7D177F5D59E7E114EE10A49CFD9CEF88AE43387023B672927BA74B04EB6BBB5E57" + "597766A2F9CE3857D7ACE3E1E3BC1FC6F26#) (y " + "#0AC8670AD767D7A8D9D14CC1AC6744CD7D76F993B77FFD9E39DF01E5A6536EF65E775FCEF" + "2A983E2A19BD6415500F6979715D9FD1257E1FE2B6F5E1E74B333079E7C880D39868462A93" + "454B41877BE62E5EF0A041C2EE9C9E76BD1E12AE25D9628DECB097025DD625EF49C3258A1A" + "3C0FF501E3DC673B76D7BABF349009B6ECF#) (x " + "#14D0345A3562C480A039E3C72764F72D79043216#)))))\n"; + +int main() { + OTRL_INIT; + + // We have to write the private key information to a file because the libotr + // API demands a filename to read from. + const char *tmpdir = "/tmp"; + if (getenv("TMP")) { + tmpdir = getenv("TMP"); + } + + char private_key_file[256]; + snprintf(private_key_file, sizeof(private_key_file), + "%s/libotr_test_helper_privatekeys-XXXXXX", tmpdir); + int fd = mkstemp(private_key_file); + if (fd == -1) { + perror("creating temp file"); + } + write(fd, kPrivateKeyData, sizeof(kPrivateKeyData) - 1); + close(fd); + + OtrlUserState userstate = otrl_userstate_create(); + otrl_privkey_read(userstate, private_key_file); + unlink(private_key_file); + + fprintf(stderr, "libotr helper started\n"); + + char buf[4096]; + + for (;;) { + char *message = fgets(buf, sizeof(buf), stdin); + if (strlen(message) == 0) { + break; + } + message[strlen(message) - 1] = 0; + fprintf(stderr, "libotr helper got: %s\n", message); + + char *newmessage = NULL; + OtrlTLV *tlvs; + int ignore_message = otrl_message_receiving( + userstate, &uiops, NULL, "account", "proto", "peer", message, + &newmessage, &tlvs, NULL, NULL, NULL); + if (tlvs) { + otrl_tlv_free(tlvs); + } + + if (newmessage != NULL) { + fprintf(stderr, "libotr got: %s\n", newmessage); + otrl_message_free(newmessage); + + gcry_error_t err; + char *newmessage = NULL; + + err = otrl_message_sending(userstate, &uiops, NULL, "account", "proto", + "peer", 0, "test message", NULL, &newmessage, + OTRL_FRAGMENT_SEND_SKIP, NULL, NULL, NULL); + if (newmessage == NULL) { + fprintf(stderr, "libotr didn't encrypt message\n"); + return 1; + } + write(1, newmessage, strlen(newmessage)); + write(1, "\n", 1); + fprintf(stderr, "libotr sent: %s\n", newmessage); + otrl_message_free(newmessage); + + g_session_established = 0; + write(1, "?OTRv2?\n", 8); + fprintf(stderr, "libotr sent: ?OTRv2\n"); + } + } + + return 0; +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/otr/otr.go b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/otr/otr.go new file mode 100644 index 0000000000..173b753dbd --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/otr/otr.go @@ -0,0 +1,1415 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package otr implements the Off The Record protocol as specified in +// http://www.cypherpunks.ca/otr/Protocol-v2-3.1.0.html +package otr // import "golang.org/x/crypto/otr" + +import ( + "bytes" + "crypto/aes" + "crypto/cipher" + "crypto/dsa" + "crypto/hmac" + "crypto/rand" + "crypto/sha1" + "crypto/sha256" + "crypto/subtle" + "encoding/base64" + "encoding/hex" + "errors" + "hash" + "io" + "math/big" + "strconv" +) + +// SecurityChange describes a change in the security state of a Conversation. +type SecurityChange int + +const ( + NoChange SecurityChange = iota + // NewKeys indicates that a key exchange has completed. This occurs + // when a conversation first becomes encrypted, and when the keys are + // renegotiated within an encrypted conversation. + NewKeys + // SMPSecretNeeded indicates that the peer has started an + // authentication and that we need to supply a secret. Call SMPQuestion + // to get the optional, human readable challenge and then Authenticate + // to supply the matching secret. + SMPSecretNeeded + // SMPComplete indicates that an authentication completed. The identity + // of the peer has now been confirmed. + SMPComplete + // SMPFailed indicates that an authentication failed. + SMPFailed + // ConversationEnded indicates that the peer ended the secure + // conversation. + ConversationEnded +) + +// QueryMessage can be sent to a peer to start an OTR conversation. +var QueryMessage = "?OTRv2?" + +// ErrorPrefix can be used to make an OTR error by appending an error message +// to it. +var ErrorPrefix = "?OTR Error:" + +var ( + fragmentPartSeparator = []byte(",") + fragmentPrefix = []byte("?OTR,") + msgPrefix = []byte("?OTR:") + queryMarker = []byte("?OTR") +) + +// isQuery attempts to parse an OTR query from msg and returns the greatest +// common version, or 0 if msg is not an OTR query. +func isQuery(msg []byte) (greatestCommonVersion int) { + pos := bytes.Index(msg, queryMarker) + if pos == -1 { + return 0 + } + for i, c := range msg[pos+len(queryMarker):] { + if i == 0 { + if c == '?' { + // Indicates support for version 1, but we don't + // implement that. + continue + } + + if c != 'v' { + // Invalid message + return 0 + } + + continue + } + + if c == '?' { + // End of message + return + } + + if c == ' ' || c == '\t' { + // Probably an invalid message + return 0 + } + + if c == '2' { + greatestCommonVersion = 2 + } + } + + return 0 +} + +const ( + statePlaintext = iota + stateEncrypted + stateFinished +) + +const ( + authStateNone = iota + authStateAwaitingDHKey + authStateAwaitingRevealSig + authStateAwaitingSig +) + +const ( + msgTypeDHCommit = 2 + msgTypeData = 3 + msgTypeDHKey = 10 + msgTypeRevealSig = 17 + msgTypeSig = 18 +) + +const ( + // If the requested fragment size is less than this, it will be ignored. + minFragmentSize = 18 + // Messages are padded to a multiple of this number of bytes. + paddingGranularity = 256 + // The number of bytes in a Diffie-Hellman private value (320-bits). + dhPrivateBytes = 40 + // The number of bytes needed to represent an element of the DSA + // subgroup (160-bits). + dsaSubgroupBytes = 20 + // The number of bytes of the MAC that are sent on the wire (160-bits). + macPrefixBytes = 20 +) + +// These are the global, common group parameters for OTR. +var ( + p *big.Int // group prime + g *big.Int // group generator + q *big.Int // group order + pMinus2 *big.Int +) + +func init() { + p, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF", 16) + q, _ = new(big.Int).SetString("7FFFFFFFFFFFFFFFE487ED5110B4611A62633145C06E0E68948127044533E63A0105DF531D89CD9128A5043CC71A026EF7CA8CD9E69D218D98158536F92F8A1BA7F09AB6B6A8E122F242DABB312F3F637A262174D31BF6B585FFAE5B7A035BF6F71C35FDAD44CFD2D74F9208BE258FF324943328F6722D9EE1003E5C50B1DF82CC6D241B0E2AE9CD348B1FD47E9267AFC1B2AE91EE51D6CB0E3179AB1042A95DCF6A9483B84B4B36B3861AA7255E4C0278BA36046511B993FFFFFFFFFFFFFFFF", 16) + g = new(big.Int).SetInt64(2) + pMinus2 = new(big.Int).Sub(p, g) +} + +// Conversation represents a relation with a peer. The zero value is a valid +// Conversation, although PrivateKey must be set. +// +// When communicating with a peer, all inbound messages should be passed to +// Conversation.Receive and all outbound messages to Conversation.Send. The +// Conversation will take care of maintaining the encryption state and +// negotiating encryption as needed. +type Conversation struct { + // PrivateKey contains the private key to use to sign key exchanges. + PrivateKey *PrivateKey + + // Rand can be set to override the entropy source. Otherwise, + // crypto/rand will be used. + Rand io.Reader + // If FragmentSize is set, all messages produced by Receive and Send + // will be fragmented into messages of, at most, this number of bytes. + FragmentSize int + + // Once Receive has returned NewKeys once, the following fields are + // valid. + SSID [8]byte + TheirPublicKey PublicKey + + state, authState int + + r [16]byte + x, y *big.Int + gx, gy *big.Int + gxBytes []byte + digest [sha256.Size]byte + + revealKeys, sigKeys akeKeys + + myKeyId uint32 + myCurrentDHPub *big.Int + myCurrentDHPriv *big.Int + myLastDHPub *big.Int + myLastDHPriv *big.Int + + theirKeyId uint32 + theirCurrentDHPub *big.Int + theirLastDHPub *big.Int + + keySlots [4]keySlot + + myCounter [8]byte + theirLastCtr [8]byte + oldMACs []byte + + k, n int // fragment state + frag []byte + + smp smpState +} + +// A keySlot contains key material for a specific (their keyid, my keyid) pair. +type keySlot struct { + // used is true if this slot is valid. If false, it's free for reuse. + used bool + theirKeyId uint32 + myKeyId uint32 + sendAESKey, recvAESKey []byte + sendMACKey, recvMACKey []byte + theirLastCtr [8]byte +} + +// akeKeys are generated during key exchange. There's one set for the reveal +// signature message and another for the signature message. In the protocol +// spec the latter are indicated with a prime mark. +type akeKeys struct { + c [16]byte + m1, m2 [32]byte +} + +func (c *Conversation) rand() io.Reader { + if c.Rand != nil { + return c.Rand + } + return rand.Reader +} + +func (c *Conversation) randMPI(buf []byte) *big.Int { + _, err := io.ReadFull(c.rand(), buf) + if err != nil { + panic("otr: short read from random source") + } + + return new(big.Int).SetBytes(buf) +} + +// tlv represents the type-length value from the protocol. +type tlv struct { + typ, length uint16 + data []byte +} + +const ( + tlvTypePadding = 0 + tlvTypeDisconnected = 1 + tlvTypeSMP1 = 2 + tlvTypeSMP2 = 3 + tlvTypeSMP3 = 4 + tlvTypeSMP4 = 5 + tlvTypeSMPAbort = 6 + tlvTypeSMP1WithQuestion = 7 +) + +// Receive handles a message from a peer. It returns a human readable message, +// an indicator of whether that message was encrypted, a hint about the +// encryption state and zero or more messages to send back to the peer. +// These messages do not need to be passed to Send before transmission. +func (c *Conversation) Receive(in []byte) (out []byte, encrypted bool, change SecurityChange, toSend [][]byte, err error) { + if bytes.HasPrefix(in, fragmentPrefix) { + in, err = c.processFragment(in) + if in == nil || err != nil { + return + } + } + + if bytes.HasPrefix(in, msgPrefix) && in[len(in)-1] == '.' { + in = in[len(msgPrefix) : len(in)-1] + } else if version := isQuery(in); version > 0 { + c.authState = authStateAwaitingDHKey + c.reset() + toSend = c.encode(c.generateDHCommit()) + return + } else { + // plaintext message + out = in + return + } + + msg := make([]byte, base64.StdEncoding.DecodedLen(len(in))) + msgLen, err := base64.StdEncoding.Decode(msg, in) + if err != nil { + err = errors.New("otr: invalid base64 encoding in message") + return + } + msg = msg[:msgLen] + + // The first two bytes are the protocol version (2) + if len(msg) < 3 || msg[0] != 0 || msg[1] != 2 { + err = errors.New("otr: invalid OTR message") + return + } + + msgType := int(msg[2]) + msg = msg[3:] + + switch msgType { + case msgTypeDHCommit: + switch c.authState { + case authStateNone: + c.authState = authStateAwaitingRevealSig + if err = c.processDHCommit(msg); err != nil { + return + } + c.reset() + toSend = c.encode(c.generateDHKey()) + return + case authStateAwaitingDHKey: + // This is a 'SYN-crossing'. The greater digest wins. + var cmp int + if cmp, err = c.compareToDHCommit(msg); err != nil { + return + } + if cmp > 0 { + // We win. Retransmit DH commit. + toSend = c.encode(c.serializeDHCommit()) + return + } else { + // They win. We forget about our DH commit. + c.authState = authStateAwaitingRevealSig + if err = c.processDHCommit(msg); err != nil { + return + } + c.reset() + toSend = c.encode(c.generateDHKey()) + return + } + case authStateAwaitingRevealSig: + if err = c.processDHCommit(msg); err != nil { + return + } + toSend = c.encode(c.serializeDHKey()) + case authStateAwaitingSig: + if err = c.processDHCommit(msg); err != nil { + return + } + c.reset() + toSend = c.encode(c.generateDHKey()) + c.authState = authStateAwaitingRevealSig + default: + panic("bad state") + } + case msgTypeDHKey: + switch c.authState { + case authStateAwaitingDHKey: + var isSame bool + if isSame, err = c.processDHKey(msg); err != nil { + return + } + if isSame { + err = errors.New("otr: unexpected duplicate DH key") + return + } + toSend = c.encode(c.generateRevealSig()) + c.authState = authStateAwaitingSig + case authStateAwaitingSig: + var isSame bool + if isSame, err = c.processDHKey(msg); err != nil { + return + } + if isSame { + toSend = c.encode(c.serializeDHKey()) + } + } + case msgTypeRevealSig: + if c.authState != authStateAwaitingRevealSig { + return + } + if err = c.processRevealSig(msg); err != nil { + return + } + toSend = c.encode(c.generateSig()) + c.authState = authStateNone + c.state = stateEncrypted + change = NewKeys + case msgTypeSig: + if c.authState != authStateAwaitingSig { + return + } + if err = c.processSig(msg); err != nil { + return + } + c.authState = authStateNone + c.state = stateEncrypted + change = NewKeys + case msgTypeData: + if c.state != stateEncrypted { + err = errors.New("otr: encrypted message received without encrypted session established") + return + } + var tlvs []tlv + out, tlvs, err = c.processData(msg) + encrypted = true + + EachTLV: + for _, inTLV := range tlvs { + switch inTLV.typ { + case tlvTypeDisconnected: + change = ConversationEnded + c.state = stateFinished + break EachTLV + case tlvTypeSMP1, tlvTypeSMP2, tlvTypeSMP3, tlvTypeSMP4, tlvTypeSMPAbort, tlvTypeSMP1WithQuestion: + var reply tlv + var complete bool + reply, complete, err = c.processSMP(inTLV) + if err == smpSecretMissingError { + err = nil + change = SMPSecretNeeded + c.smp.saved = &inTLV + return + } + if err == smpFailureError { + err = nil + change = SMPFailed + } else if complete { + change = SMPComplete + } + if reply.typ != 0 { + toSend = c.encode(c.generateData(nil, &reply)) + } + break EachTLV + default: + // skip unknown TLVs + } + } + default: + err = errors.New("otr: unknown message type " + strconv.Itoa(msgType)) + } + + return +} + +// Send takes a human readable message from the local user, possibly encrypts +// it and returns zero one or more messages to send to the peer. +func (c *Conversation) Send(msg []byte) ([][]byte, error) { + switch c.state { + case statePlaintext: + return [][]byte{msg}, nil + case stateEncrypted: + return c.encode(c.generateData(msg, nil)), nil + case stateFinished: + return nil, errors.New("otr: cannot send message because secure conversation has finished") + } + + return nil, errors.New("otr: cannot send message in current state") +} + +// SMPQuestion returns the human readable challenge question from the peer. +// It's only valid after Receive has returned SMPSecretNeeded. +func (c *Conversation) SMPQuestion() string { + return c.smp.question +} + +// Authenticate begins an authentication with the peer. Authentication involves +// an optional challenge message and a shared secret. The authentication +// proceeds until either Receive returns SMPComplete, SMPSecretNeeded (which +// indicates that a new authentication is happening and thus this one was +// aborted) or SMPFailed. +func (c *Conversation) Authenticate(question string, mutualSecret []byte) (toSend [][]byte, err error) { + if c.state != stateEncrypted { + err = errors.New("otr: can't authenticate a peer without a secure conversation established") + return + } + + if c.smp.saved != nil { + c.calcSMPSecret(mutualSecret, false /* they started it */) + + var out tlv + var complete bool + out, complete, err = c.processSMP(*c.smp.saved) + if complete { + panic("SMP completed on the first message") + } + c.smp.saved = nil + if out.typ != 0 { + toSend = c.encode(c.generateData(nil, &out)) + } + return + } + + c.calcSMPSecret(mutualSecret, true /* we started it */) + outs := c.startSMP(question) + for _, out := range outs { + toSend = append(toSend, c.encode(c.generateData(nil, &out))...) + } + return +} + +// End ends a secure conversation by generating a termination message for +// the peer and switches to unencrypted communication. +func (c *Conversation) End() (toSend [][]byte) { + switch c.state { + case statePlaintext: + return nil + case stateEncrypted: + c.state = statePlaintext + return c.encode(c.generateData(nil, &tlv{typ: tlvTypeDisconnected})) + case stateFinished: + c.state = statePlaintext + return nil + } + panic("unreachable") +} + +// IsEncrypted returns true if a message passed to Send would be encrypted +// before transmission. This result remains valid until the next call to +// Receive or End, which may change the state of the Conversation. +func (c *Conversation) IsEncrypted() bool { + return c.state == stateEncrypted +} + +var fragmentError = errors.New("otr: invalid OTR fragment") + +// processFragment processes a fragmented OTR message and possibly returns a +// complete message. Fragmented messages look like "?OTR,k,n,msg," where k is +// the fragment number (starting from 1), n is the number of fragments in this +// message and msg is a substring of the base64 encoded message. +func (c *Conversation) processFragment(in []byte) (out []byte, err error) { + in = in[len(fragmentPrefix):] // remove "?OTR," + parts := bytes.Split(in, fragmentPartSeparator) + if len(parts) != 4 || len(parts[3]) != 0 { + return nil, fragmentError + } + + k, err := strconv.Atoi(string(parts[0])) + if err != nil { + return nil, fragmentError + } + + n, err := strconv.Atoi(string(parts[1])) + if err != nil { + return nil, fragmentError + } + + if k < 1 || n < 1 || k > n { + return nil, fragmentError + } + + if k == 1 { + c.frag = append(c.frag[:0], parts[2]...) + c.k, c.n = k, n + } else if n == c.n && k == c.k+1 { + c.frag = append(c.frag, parts[2]...) + c.k++ + } else { + c.frag = c.frag[:0] + c.n, c.k = 0, 0 + } + + if c.n > 0 && c.k == c.n { + c.n, c.k = 0, 0 + return c.frag, nil + } + + return nil, nil +} + +func (c *Conversation) generateDHCommit() []byte { + _, err := io.ReadFull(c.rand(), c.r[:]) + if err != nil { + panic("otr: short read from random source") + } + + var xBytes [dhPrivateBytes]byte + c.x = c.randMPI(xBytes[:]) + c.gx = new(big.Int).Exp(g, c.x, p) + c.gy = nil + c.gxBytes = appendMPI(nil, c.gx) + + h := sha256.New() + h.Write(c.gxBytes) + h.Sum(c.digest[:0]) + + aesCipher, err := aes.NewCipher(c.r[:]) + if err != nil { + panic(err.Error()) + } + + var iv [aes.BlockSize]byte + ctr := cipher.NewCTR(aesCipher, iv[:]) + ctr.XORKeyStream(c.gxBytes, c.gxBytes) + + return c.serializeDHCommit() +} + +func (c *Conversation) serializeDHCommit() []byte { + var ret []byte + ret = appendU16(ret, 2) // protocol version + ret = append(ret, msgTypeDHCommit) + ret = appendData(ret, c.gxBytes) + ret = appendData(ret, c.digest[:]) + return ret +} + +func (c *Conversation) processDHCommit(in []byte) error { + var ok1, ok2 bool + c.gxBytes, in, ok1 = getData(in) + digest, in, ok2 := getData(in) + if !ok1 || !ok2 || len(in) > 0 { + return errors.New("otr: corrupt DH commit message") + } + copy(c.digest[:], digest) + return nil +} + +func (c *Conversation) compareToDHCommit(in []byte) (int, error) { + _, in, ok1 := getData(in) + digest, in, ok2 := getData(in) + if !ok1 || !ok2 || len(in) > 0 { + return 0, errors.New("otr: corrupt DH commit message") + } + return bytes.Compare(c.digest[:], digest), nil +} + +func (c *Conversation) generateDHKey() []byte { + var yBytes [dhPrivateBytes]byte + c.y = c.randMPI(yBytes[:]) + c.gy = new(big.Int).Exp(g, c.y, p) + return c.serializeDHKey() +} + +func (c *Conversation) serializeDHKey() []byte { + var ret []byte + ret = appendU16(ret, 2) // protocol version + ret = append(ret, msgTypeDHKey) + ret = appendMPI(ret, c.gy) + return ret +} + +func (c *Conversation) processDHKey(in []byte) (isSame bool, err error) { + gy, in, ok := getMPI(in) + if !ok { + err = errors.New("otr: corrupt DH key message") + return + } + if gy.Cmp(g) < 0 || gy.Cmp(pMinus2) > 0 { + err = errors.New("otr: DH value out of range") + return + } + if c.gy != nil { + isSame = c.gy.Cmp(gy) == 0 + return + } + c.gy = gy + return +} + +func (c *Conversation) generateEncryptedSignature(keys *akeKeys, xFirst bool) ([]byte, []byte) { + var xb []byte + xb = c.PrivateKey.PublicKey.Serialize(xb) + + var verifyData []byte + if xFirst { + verifyData = appendMPI(verifyData, c.gx) + verifyData = appendMPI(verifyData, c.gy) + } else { + verifyData = appendMPI(verifyData, c.gy) + verifyData = appendMPI(verifyData, c.gx) + } + verifyData = append(verifyData, xb...) + verifyData = appendU32(verifyData, c.myKeyId) + + mac := hmac.New(sha256.New, keys.m1[:]) + mac.Write(verifyData) + mb := mac.Sum(nil) + + xb = appendU32(xb, c.myKeyId) + xb = append(xb, c.PrivateKey.Sign(c.rand(), mb)...) + + aesCipher, err := aes.NewCipher(keys.c[:]) + if err != nil { + panic(err.Error()) + } + var iv [aes.BlockSize]byte + ctr := cipher.NewCTR(aesCipher, iv[:]) + ctr.XORKeyStream(xb, xb) + + mac = hmac.New(sha256.New, keys.m2[:]) + encryptedSig := appendData(nil, xb) + mac.Write(encryptedSig) + + return encryptedSig, mac.Sum(nil) +} + +func (c *Conversation) generateRevealSig() []byte { + s := new(big.Int).Exp(c.gy, c.x, p) + c.calcAKEKeys(s) + c.myKeyId++ + + encryptedSig, mac := c.generateEncryptedSignature(&c.revealKeys, true /* gx comes first */) + + c.myCurrentDHPub = c.gx + c.myCurrentDHPriv = c.x + c.rotateDHKeys() + incCounter(&c.myCounter) + + var ret []byte + ret = appendU16(ret, 2) + ret = append(ret, msgTypeRevealSig) + ret = appendData(ret, c.r[:]) + ret = append(ret, encryptedSig...) + ret = append(ret, mac[:20]...) + return ret +} + +func (c *Conversation) processEncryptedSig(encryptedSig, theirMAC []byte, keys *akeKeys, xFirst bool) error { + mac := hmac.New(sha256.New, keys.m2[:]) + mac.Write(appendData(nil, encryptedSig)) + myMAC := mac.Sum(nil)[:20] + + if len(myMAC) != len(theirMAC) || subtle.ConstantTimeCompare(myMAC, theirMAC) == 0 { + return errors.New("bad signature MAC in encrypted signature") + } + + aesCipher, err := aes.NewCipher(keys.c[:]) + if err != nil { + panic(err.Error()) + } + var iv [aes.BlockSize]byte + ctr := cipher.NewCTR(aesCipher, iv[:]) + ctr.XORKeyStream(encryptedSig, encryptedSig) + + sig := encryptedSig + sig, ok1 := c.TheirPublicKey.Parse(sig) + keyId, sig, ok2 := getU32(sig) + if !ok1 || !ok2 { + return errors.New("otr: corrupt encrypted signature") + } + + var verifyData []byte + if xFirst { + verifyData = appendMPI(verifyData, c.gx) + verifyData = appendMPI(verifyData, c.gy) + } else { + verifyData = appendMPI(verifyData, c.gy) + verifyData = appendMPI(verifyData, c.gx) + } + verifyData = c.TheirPublicKey.Serialize(verifyData) + verifyData = appendU32(verifyData, keyId) + + mac = hmac.New(sha256.New, keys.m1[:]) + mac.Write(verifyData) + mb := mac.Sum(nil) + + sig, ok1 = c.TheirPublicKey.Verify(mb, sig) + if !ok1 { + return errors.New("bad signature in encrypted signature") + } + if len(sig) > 0 { + return errors.New("corrupt encrypted signature") + } + + c.theirKeyId = keyId + zero(c.theirLastCtr[:]) + return nil +} + +func (c *Conversation) processRevealSig(in []byte) error { + r, in, ok1 := getData(in) + encryptedSig, in, ok2 := getData(in) + theirMAC := in + if !ok1 || !ok2 || len(theirMAC) != 20 { + return errors.New("otr: corrupt reveal signature message") + } + + aesCipher, err := aes.NewCipher(r) + if err != nil { + return errors.New("otr: cannot create AES cipher from reveal signature message: " + err.Error()) + } + var iv [aes.BlockSize]byte + ctr := cipher.NewCTR(aesCipher, iv[:]) + ctr.XORKeyStream(c.gxBytes, c.gxBytes) + h := sha256.New() + h.Write(c.gxBytes) + digest := h.Sum(nil) + if len(digest) != len(c.digest) || subtle.ConstantTimeCompare(digest, c.digest[:]) == 0 { + return errors.New("otr: bad commit MAC in reveal signature message") + } + var rest []byte + c.gx, rest, ok1 = getMPI(c.gxBytes) + if !ok1 || len(rest) > 0 { + return errors.New("otr: gx corrupt after decryption") + } + if c.gx.Cmp(g) < 0 || c.gx.Cmp(pMinus2) > 0 { + return errors.New("otr: DH value out of range") + } + s := new(big.Int).Exp(c.gx, c.y, p) + c.calcAKEKeys(s) + + if err := c.processEncryptedSig(encryptedSig, theirMAC, &c.revealKeys, true /* gx comes first */); err != nil { + return errors.New("otr: in reveal signature message: " + err.Error()) + } + + c.theirCurrentDHPub = c.gx + c.theirLastDHPub = nil + + return nil +} + +func (c *Conversation) generateSig() []byte { + c.myKeyId++ + + encryptedSig, mac := c.generateEncryptedSignature(&c.sigKeys, false /* gy comes first */) + + c.myCurrentDHPub = c.gy + c.myCurrentDHPriv = c.y + c.rotateDHKeys() + incCounter(&c.myCounter) + + var ret []byte + ret = appendU16(ret, 2) + ret = append(ret, msgTypeSig) + ret = append(ret, encryptedSig...) + ret = append(ret, mac[:macPrefixBytes]...) + return ret +} + +func (c *Conversation) processSig(in []byte) error { + encryptedSig, in, ok1 := getData(in) + theirMAC := in + if !ok1 || len(theirMAC) != macPrefixBytes { + return errors.New("otr: corrupt signature message") + } + + if err := c.processEncryptedSig(encryptedSig, theirMAC, &c.sigKeys, false /* gy comes first */); err != nil { + return errors.New("otr: in signature message: " + err.Error()) + } + + c.theirCurrentDHPub = c.gy + c.theirLastDHPub = nil + + return nil +} + +func (c *Conversation) rotateDHKeys() { + // evict slots using our retired key id + for i := range c.keySlots { + slot := &c.keySlots[i] + if slot.used && slot.myKeyId == c.myKeyId-1 { + slot.used = false + c.oldMACs = append(c.oldMACs, slot.recvMACKey...) + } + } + + c.myLastDHPriv = c.myCurrentDHPriv + c.myLastDHPub = c.myCurrentDHPub + + var xBytes [dhPrivateBytes]byte + c.myCurrentDHPriv = c.randMPI(xBytes[:]) + c.myCurrentDHPub = new(big.Int).Exp(g, c.myCurrentDHPriv, p) + c.myKeyId++ +} + +func (c *Conversation) processData(in []byte) (out []byte, tlvs []tlv, err error) { + origIn := in + flags, in, ok1 := getU8(in) + theirKeyId, in, ok2 := getU32(in) + myKeyId, in, ok3 := getU32(in) + y, in, ok4 := getMPI(in) + counter, in, ok5 := getNBytes(in, 8) + encrypted, in, ok6 := getData(in) + macedData := origIn[:len(origIn)-len(in)] + theirMAC, in, ok7 := getNBytes(in, macPrefixBytes) + _, in, ok8 := getData(in) + if !ok1 || !ok2 || !ok3 || !ok4 || !ok5 || !ok6 || !ok7 || !ok8 || len(in) > 0 { + err = errors.New("otr: corrupt data message") + return + } + + ignoreErrors := flags&1 != 0 + + slot, err := c.calcDataKeys(myKeyId, theirKeyId) + if err != nil { + if ignoreErrors { + err = nil + } + return + } + + mac := hmac.New(sha1.New, slot.recvMACKey) + mac.Write([]byte{0, 2, 3}) + mac.Write(macedData) + myMAC := mac.Sum(nil) + if len(myMAC) != len(theirMAC) || subtle.ConstantTimeCompare(myMAC, theirMAC) == 0 { + if !ignoreErrors { + err = errors.New("otr: bad MAC on data message") + } + return + } + + if bytes.Compare(counter, slot.theirLastCtr[:]) <= 0 { + err = errors.New("otr: counter regressed") + return + } + copy(slot.theirLastCtr[:], counter) + + var iv [aes.BlockSize]byte + copy(iv[:], counter) + aesCipher, err := aes.NewCipher(slot.recvAESKey) + if err != nil { + panic(err.Error()) + } + ctr := cipher.NewCTR(aesCipher, iv[:]) + ctr.XORKeyStream(encrypted, encrypted) + decrypted := encrypted + + if myKeyId == c.myKeyId { + c.rotateDHKeys() + } + if theirKeyId == c.theirKeyId { + // evict slots using their retired key id + for i := range c.keySlots { + slot := &c.keySlots[i] + if slot.used && slot.theirKeyId == theirKeyId-1 { + slot.used = false + c.oldMACs = append(c.oldMACs, slot.recvMACKey...) + } + } + + c.theirLastDHPub = c.theirCurrentDHPub + c.theirKeyId++ + c.theirCurrentDHPub = y + } + + if nulPos := bytes.IndexByte(decrypted, 0); nulPos >= 0 { + out = decrypted[:nulPos] + tlvData := decrypted[nulPos+1:] + for len(tlvData) > 0 { + var t tlv + var ok1, ok2, ok3 bool + + t.typ, tlvData, ok1 = getU16(tlvData) + t.length, tlvData, ok2 = getU16(tlvData) + t.data, tlvData, ok3 = getNBytes(tlvData, int(t.length)) + if !ok1 || !ok2 || !ok3 { + err = errors.New("otr: corrupt tlv data") + return + } + tlvs = append(tlvs, t) + } + } else { + out = decrypted + } + + return +} + +func (c *Conversation) generateData(msg []byte, extra *tlv) []byte { + slot, err := c.calcDataKeys(c.myKeyId-1, c.theirKeyId) + if err != nil { + panic("otr: failed to generate sending keys: " + err.Error()) + } + + var plaintext []byte + plaintext = append(plaintext, msg...) + plaintext = append(plaintext, 0) + + padding := paddingGranularity - ((len(plaintext) + 4) % paddingGranularity) + plaintext = appendU16(plaintext, tlvTypePadding) + plaintext = appendU16(plaintext, uint16(padding)) + for i := 0; i < padding; i++ { + plaintext = append(plaintext, 0) + } + + if extra != nil { + plaintext = appendU16(plaintext, extra.typ) + plaintext = appendU16(plaintext, uint16(len(extra.data))) + plaintext = append(plaintext, extra.data...) + } + + encrypted := make([]byte, len(plaintext)) + + var iv [aes.BlockSize]byte + copy(iv[:], c.myCounter[:]) + aesCipher, err := aes.NewCipher(slot.sendAESKey) + if err != nil { + panic(err.Error()) + } + ctr := cipher.NewCTR(aesCipher, iv[:]) + ctr.XORKeyStream(encrypted, plaintext) + + var ret []byte + ret = appendU16(ret, 2) + ret = append(ret, msgTypeData) + ret = append(ret, 0 /* flags */) + ret = appendU32(ret, c.myKeyId-1) + ret = appendU32(ret, c.theirKeyId) + ret = appendMPI(ret, c.myCurrentDHPub) + ret = append(ret, c.myCounter[:]...) + ret = appendData(ret, encrypted) + + mac := hmac.New(sha1.New, slot.sendMACKey) + mac.Write(ret) + ret = append(ret, mac.Sum(nil)[:macPrefixBytes]...) + ret = appendData(ret, c.oldMACs) + c.oldMACs = nil + incCounter(&c.myCounter) + + return ret +} + +func incCounter(counter *[8]byte) { + for i := 7; i >= 0; i-- { + counter[i]++ + if counter[i] > 0 { + break + } + } +} + +// calcDataKeys computes the keys used to encrypt a data message given the key +// IDs. +func (c *Conversation) calcDataKeys(myKeyId, theirKeyId uint32) (slot *keySlot, err error) { + // Check for a cache hit. + for i := range c.keySlots { + slot = &c.keySlots[i] + if slot.used && slot.theirKeyId == theirKeyId && slot.myKeyId == myKeyId { + return + } + } + + // Find an empty slot to write into. + slot = nil + for i := range c.keySlots { + if !c.keySlots[i].used { + slot = &c.keySlots[i] + break + } + } + if slot == nil { + return nil, errors.New("otr: internal error: no more key slots") + } + + var myPriv, myPub, theirPub *big.Int + + if myKeyId == c.myKeyId { + myPriv = c.myCurrentDHPriv + myPub = c.myCurrentDHPub + } else if myKeyId == c.myKeyId-1 { + myPriv = c.myLastDHPriv + myPub = c.myLastDHPub + } else { + err = errors.New("otr: peer requested keyid " + strconv.FormatUint(uint64(myKeyId), 10) + " when I'm on " + strconv.FormatUint(uint64(c.myKeyId), 10)) + return + } + + if theirKeyId == c.theirKeyId { + theirPub = c.theirCurrentDHPub + } else if theirKeyId == c.theirKeyId-1 && c.theirLastDHPub != nil { + theirPub = c.theirLastDHPub + } else { + err = errors.New("otr: peer requested keyid " + strconv.FormatUint(uint64(myKeyId), 10) + " when they're on " + strconv.FormatUint(uint64(c.myKeyId), 10)) + return + } + + var sendPrefixByte, recvPrefixByte [1]byte + + if myPub.Cmp(theirPub) > 0 { + // we're the high end + sendPrefixByte[0], recvPrefixByte[0] = 1, 2 + } else { + // we're the low end + sendPrefixByte[0], recvPrefixByte[0] = 2, 1 + } + + s := new(big.Int).Exp(theirPub, myPriv, p) + sBytes := appendMPI(nil, s) + + h := sha1.New() + h.Write(sendPrefixByte[:]) + h.Write(sBytes) + slot.sendAESKey = h.Sum(slot.sendAESKey[:0])[:16] + + h.Reset() + h.Write(slot.sendAESKey) + slot.sendMACKey = h.Sum(slot.sendMACKey[:0]) + + h.Reset() + h.Write(recvPrefixByte[:]) + h.Write(sBytes) + slot.recvAESKey = h.Sum(slot.recvAESKey[:0])[:16] + + h.Reset() + h.Write(slot.recvAESKey) + slot.recvMACKey = h.Sum(slot.recvMACKey[:0]) + + slot.theirKeyId = theirKeyId + slot.myKeyId = myKeyId + slot.used = true + + zero(slot.theirLastCtr[:]) + return +} + +func (c *Conversation) calcAKEKeys(s *big.Int) { + mpi := appendMPI(nil, s) + h := sha256.New() + + var cBytes [32]byte + hashWithPrefix(c.SSID[:], 0, mpi, h) + + hashWithPrefix(cBytes[:], 1, mpi, h) + copy(c.revealKeys.c[:], cBytes[:16]) + copy(c.sigKeys.c[:], cBytes[16:]) + + hashWithPrefix(c.revealKeys.m1[:], 2, mpi, h) + hashWithPrefix(c.revealKeys.m2[:], 3, mpi, h) + hashWithPrefix(c.sigKeys.m1[:], 4, mpi, h) + hashWithPrefix(c.sigKeys.m2[:], 5, mpi, h) +} + +func hashWithPrefix(out []byte, prefix byte, in []byte, h hash.Hash) { + h.Reset() + var p [1]byte + p[0] = prefix + h.Write(p[:]) + h.Write(in) + if len(out) == h.Size() { + h.Sum(out[:0]) + } else { + digest := h.Sum(nil) + copy(out, digest) + } +} + +func (c *Conversation) encode(msg []byte) [][]byte { + b64 := make([]byte, base64.StdEncoding.EncodedLen(len(msg))+len(msgPrefix)+1) + base64.StdEncoding.Encode(b64[len(msgPrefix):], msg) + copy(b64, msgPrefix) + b64[len(b64)-1] = '.' + + if c.FragmentSize < minFragmentSize || len(b64) <= c.FragmentSize { + // We can encode this in a single fragment. + return [][]byte{b64} + } + + // We have to fragment this message. + var ret [][]byte + bytesPerFragment := c.FragmentSize - minFragmentSize + numFragments := (len(b64) + bytesPerFragment) / bytesPerFragment + + for i := 0; i < numFragments; i++ { + frag := []byte("?OTR," + strconv.Itoa(i+1) + "," + strconv.Itoa(numFragments) + ",") + todo := bytesPerFragment + if todo > len(b64) { + todo = len(b64) + } + frag = append(frag, b64[:todo]...) + b64 = b64[todo:] + frag = append(frag, ',') + ret = append(ret, frag) + } + + return ret +} + +func (c *Conversation) reset() { + c.myKeyId = 0 + + for i := range c.keySlots { + c.keySlots[i].used = false + } +} + +type PublicKey struct { + dsa.PublicKey +} + +func (pk *PublicKey) Parse(in []byte) ([]byte, bool) { + var ok bool + var pubKeyType uint16 + + if pubKeyType, in, ok = getU16(in); !ok || pubKeyType != 0 { + return nil, false + } + if pk.P, in, ok = getMPI(in); !ok { + return nil, false + } + if pk.Q, in, ok = getMPI(in); !ok { + return nil, false + } + if pk.G, in, ok = getMPI(in); !ok { + return nil, false + } + if pk.Y, in, ok = getMPI(in); !ok { + return nil, false + } + + return in, true +} + +func (pk *PublicKey) Serialize(in []byte) []byte { + in = appendU16(in, 0) + in = appendMPI(in, pk.P) + in = appendMPI(in, pk.Q) + in = appendMPI(in, pk.G) + in = appendMPI(in, pk.Y) + return in +} + +// Fingerprint returns the 20-byte, binary fingerprint of the PublicKey. +func (pk *PublicKey) Fingerprint() []byte { + b := pk.Serialize(nil) + h := sha1.New() + h.Write(b[2:]) + return h.Sum(nil) +} + +func (pk *PublicKey) Verify(hashed, sig []byte) ([]byte, bool) { + if len(sig) != 2*dsaSubgroupBytes { + return nil, false + } + r := new(big.Int).SetBytes(sig[:dsaSubgroupBytes]) + s := new(big.Int).SetBytes(sig[dsaSubgroupBytes:]) + ok := dsa.Verify(&pk.PublicKey, hashed, r, s) + return sig[dsaSubgroupBytes*2:], ok +} + +type PrivateKey struct { + PublicKey + dsa.PrivateKey +} + +func (priv *PrivateKey) Sign(rand io.Reader, hashed []byte) []byte { + r, s, err := dsa.Sign(rand, &priv.PrivateKey, hashed) + if err != nil { + panic(err.Error()) + } + rBytes := r.Bytes() + sBytes := s.Bytes() + if len(rBytes) > dsaSubgroupBytes || len(sBytes) > dsaSubgroupBytes { + panic("DSA signature too large") + } + + out := make([]byte, 2*dsaSubgroupBytes) + copy(out[dsaSubgroupBytes-len(rBytes):], rBytes) + copy(out[len(out)-len(sBytes):], sBytes) + return out +} + +func (priv *PrivateKey) Serialize(in []byte) []byte { + in = priv.PublicKey.Serialize(in) + in = appendMPI(in, priv.PrivateKey.X) + return in +} + +func (priv *PrivateKey) Parse(in []byte) ([]byte, bool) { + in, ok := priv.PublicKey.Parse(in) + if !ok { + return in, ok + } + priv.PrivateKey.PublicKey = priv.PublicKey.PublicKey + priv.PrivateKey.X, in, ok = getMPI(in) + return in, ok +} + +func (priv *PrivateKey) Generate(rand io.Reader) { + if err := dsa.GenerateParameters(&priv.PrivateKey.PublicKey.Parameters, rand, dsa.L1024N160); err != nil { + panic(err.Error()) + } + if err := dsa.GenerateKey(&priv.PrivateKey, rand); err != nil { + panic(err.Error()) + } + priv.PublicKey.PublicKey = priv.PrivateKey.PublicKey +} + +func notHex(r rune) bool { + if r >= '0' && r <= '9' || + r >= 'a' && r <= 'f' || + r >= 'A' && r <= 'F' { + return false + } + + return true +} + +// Import parses the contents of a libotr private key file. +func (priv *PrivateKey) Import(in []byte) bool { + mpiStart := []byte(" #") + + mpis := make([]*big.Int, 5) + + for i := 0; i < len(mpis); i++ { + start := bytes.Index(in, mpiStart) + if start == -1 { + return false + } + in = in[start+len(mpiStart):] + end := bytes.IndexFunc(in, notHex) + if end == -1 { + return false + } + hexBytes := in[:end] + in = in[end:] + + if len(hexBytes)&1 != 0 { + return false + } + + mpiBytes := make([]byte, len(hexBytes)/2) + if _, err := hex.Decode(mpiBytes, hexBytes); err != nil { + return false + } + + mpis[i] = new(big.Int).SetBytes(mpiBytes) + } + + for _, mpi := range mpis { + if mpi.Sign() <= 0 { + return false + } + } + + priv.PrivateKey.P = mpis[0] + priv.PrivateKey.Q = mpis[1] + priv.PrivateKey.G = mpis[2] + priv.PrivateKey.Y = mpis[3] + priv.PrivateKey.X = mpis[4] + priv.PublicKey.PublicKey = priv.PrivateKey.PublicKey + + a := new(big.Int).Exp(priv.PrivateKey.G, priv.PrivateKey.X, priv.PrivateKey.P) + return a.Cmp(priv.PrivateKey.Y) == 0 +} + +func getU8(in []byte) (uint8, []byte, bool) { + if len(in) < 1 { + return 0, in, false + } + return in[0], in[1:], true +} + +func getU16(in []byte) (uint16, []byte, bool) { + if len(in) < 2 { + return 0, in, false + } + r := uint16(in[0])<<8 | uint16(in[1]) + return r, in[2:], true +} + +func getU32(in []byte) (uint32, []byte, bool) { + if len(in) < 4 { + return 0, in, false + } + r := uint32(in[0])<<24 | uint32(in[1])<<16 | uint32(in[2])<<8 | uint32(in[3]) + return r, in[4:], true +} + +func getMPI(in []byte) (*big.Int, []byte, bool) { + l, in, ok := getU32(in) + if !ok || uint32(len(in)) < l { + return nil, in, false + } + r := new(big.Int).SetBytes(in[:l]) + return r, in[l:], true +} + +func getData(in []byte) ([]byte, []byte, bool) { + l, in, ok := getU32(in) + if !ok || uint32(len(in)) < l { + return nil, in, false + } + return in[:l], in[l:], true +} + +func getNBytes(in []byte, n int) ([]byte, []byte, bool) { + if len(in) < n { + return nil, in, false + } + return in[:n], in[n:], true +} + +func appendU16(out []byte, v uint16) []byte { + out = append(out, byte(v>>8), byte(v)) + return out +} + +func appendU32(out []byte, v uint32) []byte { + out = append(out, byte(v>>24), byte(v>>16), byte(v>>8), byte(v)) + return out +} + +func appendData(out, v []byte) []byte { + out = appendU32(out, uint32(len(v))) + out = append(out, v...) + return out +} + +func appendMPI(out []byte, v *big.Int) []byte { + vBytes := v.Bytes() + out = appendU32(out, uint32(len(vBytes))) + out = append(out, vBytes...) + return out +} + +func appendMPIs(out []byte, mpis ...*big.Int) []byte { + for _, mpi := range mpis { + out = appendMPI(out, mpi) + } + return out +} + +func zero(b []byte) { + for i := range b { + b[i] = 0 + } +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/otr/smp.go b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/otr/smp.go new file mode 100644 index 0000000000..dc6de4ee0e --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/otr/smp.go @@ -0,0 +1,572 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file implements the Socialist Millionaires Protocol as described in +// http://www.cypherpunks.ca/otr/Protocol-v2-3.1.0.html. The protocol +// specification is required in order to understand this code and, where +// possible, the variable names in the code match up with the spec. + +package otr + +import ( + "bytes" + "crypto/sha256" + "errors" + "hash" + "math/big" +) + +type smpFailure string + +func (s smpFailure) Error() string { + return string(s) +} + +var smpFailureError = smpFailure("otr: SMP protocol failed") +var smpSecretMissingError = smpFailure("otr: mutual secret needed") + +const smpVersion = 1 + +const ( + smpState1 = iota + smpState2 + smpState3 + smpState4 +) + +type smpState struct { + state int + a2, a3, b2, b3, pb, qb *big.Int + g2a, g3a *big.Int + g2, g3 *big.Int + g3b, papb, qaqb, ra *big.Int + saved *tlv + secret *big.Int + question string +} + +func (c *Conversation) startSMP(question string) (tlvs []tlv) { + if c.smp.state != smpState1 { + tlvs = append(tlvs, c.generateSMPAbort()) + } + tlvs = append(tlvs, c.generateSMP1(question)) + c.smp.question = "" + c.smp.state = smpState2 + return +} + +func (c *Conversation) resetSMP() { + c.smp.state = smpState1 + c.smp.secret = nil + c.smp.question = "" +} + +func (c *Conversation) processSMP(in tlv) (out tlv, complete bool, err error) { + data := in.data + + switch in.typ { + case tlvTypeSMPAbort: + if c.smp.state != smpState1 { + err = smpFailureError + } + c.resetSMP() + return + case tlvTypeSMP1WithQuestion: + // We preprocess this into a SMP1 message. + nulPos := bytes.IndexByte(data, 0) + if nulPos == -1 { + err = errors.New("otr: SMP message with question didn't contain a NUL byte") + return + } + c.smp.question = string(data[:nulPos]) + data = data[nulPos+1:] + } + + numMPIs, data, ok := getU32(data) + if !ok || numMPIs > 20 { + err = errors.New("otr: corrupt SMP message") + return + } + + mpis := make([]*big.Int, numMPIs) + for i := range mpis { + var ok bool + mpis[i], data, ok = getMPI(data) + if !ok { + err = errors.New("otr: corrupt SMP message") + return + } + } + + switch in.typ { + case tlvTypeSMP1, tlvTypeSMP1WithQuestion: + if c.smp.state != smpState1 { + c.resetSMP() + out = c.generateSMPAbort() + return + } + if c.smp.secret == nil { + err = smpSecretMissingError + return + } + if err = c.processSMP1(mpis); err != nil { + return + } + c.smp.state = smpState3 + out = c.generateSMP2() + case tlvTypeSMP2: + if c.smp.state != smpState2 { + c.resetSMP() + out = c.generateSMPAbort() + return + } + if out, err = c.processSMP2(mpis); err != nil { + out = c.generateSMPAbort() + return + } + c.smp.state = smpState4 + case tlvTypeSMP3: + if c.smp.state != smpState3 { + c.resetSMP() + out = c.generateSMPAbort() + return + } + if out, err = c.processSMP3(mpis); err != nil { + return + } + c.smp.state = smpState1 + c.smp.secret = nil + complete = true + case tlvTypeSMP4: + if c.smp.state != smpState4 { + c.resetSMP() + out = c.generateSMPAbort() + return + } + if err = c.processSMP4(mpis); err != nil { + out = c.generateSMPAbort() + return + } + c.smp.state = smpState1 + c.smp.secret = nil + complete = true + default: + panic("unknown SMP message") + } + + return +} + +func (c *Conversation) calcSMPSecret(mutualSecret []byte, weStarted bool) { + h := sha256.New() + h.Write([]byte{smpVersion}) + if weStarted { + h.Write(c.PrivateKey.PublicKey.Fingerprint()) + h.Write(c.TheirPublicKey.Fingerprint()) + } else { + h.Write(c.TheirPublicKey.Fingerprint()) + h.Write(c.PrivateKey.PublicKey.Fingerprint()) + } + h.Write(c.SSID[:]) + h.Write(mutualSecret) + c.smp.secret = new(big.Int).SetBytes(h.Sum(nil)) +} + +func (c *Conversation) generateSMP1(question string) tlv { + var randBuf [16]byte + c.smp.a2 = c.randMPI(randBuf[:]) + c.smp.a3 = c.randMPI(randBuf[:]) + g2a := new(big.Int).Exp(g, c.smp.a2, p) + g3a := new(big.Int).Exp(g, c.smp.a3, p) + h := sha256.New() + + r2 := c.randMPI(randBuf[:]) + r := new(big.Int).Exp(g, r2, p) + c2 := new(big.Int).SetBytes(hashMPIs(h, 1, r)) + d2 := new(big.Int).Mul(c.smp.a2, c2) + d2.Sub(r2, d2) + d2.Mod(d2, q) + if d2.Sign() < 0 { + d2.Add(d2, q) + } + + r3 := c.randMPI(randBuf[:]) + r.Exp(g, r3, p) + c3 := new(big.Int).SetBytes(hashMPIs(h, 2, r)) + d3 := new(big.Int).Mul(c.smp.a3, c3) + d3.Sub(r3, d3) + d3.Mod(d3, q) + if d3.Sign() < 0 { + d3.Add(d3, q) + } + + var ret tlv + if len(question) > 0 { + ret.typ = tlvTypeSMP1WithQuestion + ret.data = append(ret.data, question...) + ret.data = append(ret.data, 0) + } else { + ret.typ = tlvTypeSMP1 + } + ret.data = appendU32(ret.data, 6) + ret.data = appendMPIs(ret.data, g2a, c2, d2, g3a, c3, d3) + return ret +} + +func (c *Conversation) processSMP1(mpis []*big.Int) error { + if len(mpis) != 6 { + return errors.New("otr: incorrect number of arguments in SMP1 message") + } + g2a := mpis[0] + c2 := mpis[1] + d2 := mpis[2] + g3a := mpis[3] + c3 := mpis[4] + d3 := mpis[5] + h := sha256.New() + + r := new(big.Int).Exp(g, d2, p) + s := new(big.Int).Exp(g2a, c2, p) + r.Mul(r, s) + r.Mod(r, p) + t := new(big.Int).SetBytes(hashMPIs(h, 1, r)) + if c2.Cmp(t) != 0 { + return errors.New("otr: ZKP c2 incorrect in SMP1 message") + } + r.Exp(g, d3, p) + s.Exp(g3a, c3, p) + r.Mul(r, s) + r.Mod(r, p) + t.SetBytes(hashMPIs(h, 2, r)) + if c3.Cmp(t) != 0 { + return errors.New("otr: ZKP c3 incorrect in SMP1 message") + } + + c.smp.g2a = g2a + c.smp.g3a = g3a + return nil +} + +func (c *Conversation) generateSMP2() tlv { + var randBuf [16]byte + b2 := c.randMPI(randBuf[:]) + c.smp.b3 = c.randMPI(randBuf[:]) + r2 := c.randMPI(randBuf[:]) + r3 := c.randMPI(randBuf[:]) + r4 := c.randMPI(randBuf[:]) + r5 := c.randMPI(randBuf[:]) + r6 := c.randMPI(randBuf[:]) + + g2b := new(big.Int).Exp(g, b2, p) + g3b := new(big.Int).Exp(g, c.smp.b3, p) + + r := new(big.Int).Exp(g, r2, p) + h := sha256.New() + c2 := new(big.Int).SetBytes(hashMPIs(h, 3, r)) + d2 := new(big.Int).Mul(b2, c2) + d2.Sub(r2, d2) + d2.Mod(d2, q) + if d2.Sign() < 0 { + d2.Add(d2, q) + } + + r.Exp(g, r3, p) + c3 := new(big.Int).SetBytes(hashMPIs(h, 4, r)) + d3 := new(big.Int).Mul(c.smp.b3, c3) + d3.Sub(r3, d3) + d3.Mod(d3, q) + if d3.Sign() < 0 { + d3.Add(d3, q) + } + + c.smp.g2 = new(big.Int).Exp(c.smp.g2a, b2, p) + c.smp.g3 = new(big.Int).Exp(c.smp.g3a, c.smp.b3, p) + c.smp.pb = new(big.Int).Exp(c.smp.g3, r4, p) + c.smp.qb = new(big.Int).Exp(g, r4, p) + r.Exp(c.smp.g2, c.smp.secret, p) + c.smp.qb.Mul(c.smp.qb, r) + c.smp.qb.Mod(c.smp.qb, p) + + s := new(big.Int) + s.Exp(c.smp.g2, r6, p) + r.Exp(g, r5, p) + s.Mul(r, s) + s.Mod(s, p) + r.Exp(c.smp.g3, r5, p) + cp := new(big.Int).SetBytes(hashMPIs(h, 5, r, s)) + + // D5 = r5 - r4 cP mod q and D6 = r6 - y cP mod q + + s.Mul(r4, cp) + r.Sub(r5, s) + d5 := new(big.Int).Mod(r, q) + if d5.Sign() < 0 { + d5.Add(d5, q) + } + + s.Mul(c.smp.secret, cp) + r.Sub(r6, s) + d6 := new(big.Int).Mod(r, q) + if d6.Sign() < 0 { + d6.Add(d6, q) + } + + var ret tlv + ret.typ = tlvTypeSMP2 + ret.data = appendU32(ret.data, 11) + ret.data = appendMPIs(ret.data, g2b, c2, d2, g3b, c3, d3, c.smp.pb, c.smp.qb, cp, d5, d6) + return ret +} + +func (c *Conversation) processSMP2(mpis []*big.Int) (out tlv, err error) { + if len(mpis) != 11 { + err = errors.New("otr: incorrect number of arguments in SMP2 message") + return + } + g2b := mpis[0] + c2 := mpis[1] + d2 := mpis[2] + g3b := mpis[3] + c3 := mpis[4] + d3 := mpis[5] + pb := mpis[6] + qb := mpis[7] + cp := mpis[8] + d5 := mpis[9] + d6 := mpis[10] + h := sha256.New() + + r := new(big.Int).Exp(g, d2, p) + s := new(big.Int).Exp(g2b, c2, p) + r.Mul(r, s) + r.Mod(r, p) + s.SetBytes(hashMPIs(h, 3, r)) + if c2.Cmp(s) != 0 { + err = errors.New("otr: ZKP c2 failed in SMP2 message") + return + } + + r.Exp(g, d3, p) + s.Exp(g3b, c3, p) + r.Mul(r, s) + r.Mod(r, p) + s.SetBytes(hashMPIs(h, 4, r)) + if c3.Cmp(s) != 0 { + err = errors.New("otr: ZKP c3 failed in SMP2 message") + return + } + + c.smp.g2 = new(big.Int).Exp(g2b, c.smp.a2, p) + c.smp.g3 = new(big.Int).Exp(g3b, c.smp.a3, p) + + r.Exp(g, d5, p) + s.Exp(c.smp.g2, d6, p) + r.Mul(r, s) + s.Exp(qb, cp, p) + r.Mul(r, s) + r.Mod(r, p) + + s.Exp(c.smp.g3, d5, p) + t := new(big.Int).Exp(pb, cp, p) + s.Mul(s, t) + s.Mod(s, p) + t.SetBytes(hashMPIs(h, 5, s, r)) + if cp.Cmp(t) != 0 { + err = errors.New("otr: ZKP cP failed in SMP2 message") + return + } + + var randBuf [16]byte + r4 := c.randMPI(randBuf[:]) + r5 := c.randMPI(randBuf[:]) + r6 := c.randMPI(randBuf[:]) + r7 := c.randMPI(randBuf[:]) + + pa := new(big.Int).Exp(c.smp.g3, r4, p) + r.Exp(c.smp.g2, c.smp.secret, p) + qa := new(big.Int).Exp(g, r4, p) + qa.Mul(qa, r) + qa.Mod(qa, p) + + r.Exp(g, r5, p) + s.Exp(c.smp.g2, r6, p) + r.Mul(r, s) + r.Mod(r, p) + + s.Exp(c.smp.g3, r5, p) + cp.SetBytes(hashMPIs(h, 6, s, r)) + + r.Mul(r4, cp) + d5 = new(big.Int).Sub(r5, r) + d5.Mod(d5, q) + if d5.Sign() < 0 { + d5.Add(d5, q) + } + + r.Mul(c.smp.secret, cp) + d6 = new(big.Int).Sub(r6, r) + d6.Mod(d6, q) + if d6.Sign() < 0 { + d6.Add(d6, q) + } + + r.ModInverse(qb, p) + qaqb := new(big.Int).Mul(qa, r) + qaqb.Mod(qaqb, p) + + ra := new(big.Int).Exp(qaqb, c.smp.a3, p) + r.Exp(qaqb, r7, p) + s.Exp(g, r7, p) + cr := new(big.Int).SetBytes(hashMPIs(h, 7, s, r)) + + r.Mul(c.smp.a3, cr) + d7 := new(big.Int).Sub(r7, r) + d7.Mod(d7, q) + if d7.Sign() < 0 { + d7.Add(d7, q) + } + + c.smp.g3b = g3b + c.smp.qaqb = qaqb + + r.ModInverse(pb, p) + c.smp.papb = new(big.Int).Mul(pa, r) + c.smp.papb.Mod(c.smp.papb, p) + c.smp.ra = ra + + out.typ = tlvTypeSMP3 + out.data = appendU32(out.data, 8) + out.data = appendMPIs(out.data, pa, qa, cp, d5, d6, ra, cr, d7) + return +} + +func (c *Conversation) processSMP3(mpis []*big.Int) (out tlv, err error) { + if len(mpis) != 8 { + err = errors.New("otr: incorrect number of arguments in SMP3 message") + return + } + pa := mpis[0] + qa := mpis[1] + cp := mpis[2] + d5 := mpis[3] + d6 := mpis[4] + ra := mpis[5] + cr := mpis[6] + d7 := mpis[7] + h := sha256.New() + + r := new(big.Int).Exp(g, d5, p) + s := new(big.Int).Exp(c.smp.g2, d6, p) + r.Mul(r, s) + s.Exp(qa, cp, p) + r.Mul(r, s) + r.Mod(r, p) + + s.Exp(c.smp.g3, d5, p) + t := new(big.Int).Exp(pa, cp, p) + s.Mul(s, t) + s.Mod(s, p) + t.SetBytes(hashMPIs(h, 6, s, r)) + if t.Cmp(cp) != 0 { + err = errors.New("otr: ZKP cP failed in SMP3 message") + return + } + + r.ModInverse(c.smp.qb, p) + qaqb := new(big.Int).Mul(qa, r) + qaqb.Mod(qaqb, p) + + r.Exp(qaqb, d7, p) + s.Exp(ra, cr, p) + r.Mul(r, s) + r.Mod(r, p) + + s.Exp(g, d7, p) + t.Exp(c.smp.g3a, cr, p) + s.Mul(s, t) + s.Mod(s, p) + t.SetBytes(hashMPIs(h, 7, s, r)) + if t.Cmp(cr) != 0 { + err = errors.New("otr: ZKP cR failed in SMP3 message") + return + } + + var randBuf [16]byte + r7 := c.randMPI(randBuf[:]) + rb := new(big.Int).Exp(qaqb, c.smp.b3, p) + + r.Exp(qaqb, r7, p) + s.Exp(g, r7, p) + cr = new(big.Int).SetBytes(hashMPIs(h, 8, s, r)) + + r.Mul(c.smp.b3, cr) + d7 = new(big.Int).Sub(r7, r) + d7.Mod(d7, q) + if d7.Sign() < 0 { + d7.Add(d7, q) + } + + out.typ = tlvTypeSMP4 + out.data = appendU32(out.data, 3) + out.data = appendMPIs(out.data, rb, cr, d7) + + r.ModInverse(c.smp.pb, p) + r.Mul(pa, r) + r.Mod(r, p) + s.Exp(ra, c.smp.b3, p) + if r.Cmp(s) != 0 { + err = smpFailureError + } + + return +} + +func (c *Conversation) processSMP4(mpis []*big.Int) error { + if len(mpis) != 3 { + return errors.New("otr: incorrect number of arguments in SMP4 message") + } + rb := mpis[0] + cr := mpis[1] + d7 := mpis[2] + h := sha256.New() + + r := new(big.Int).Exp(c.smp.qaqb, d7, p) + s := new(big.Int).Exp(rb, cr, p) + r.Mul(r, s) + r.Mod(r, p) + + s.Exp(g, d7, p) + t := new(big.Int).Exp(c.smp.g3b, cr, p) + s.Mul(s, t) + s.Mod(s, p) + t.SetBytes(hashMPIs(h, 8, s, r)) + if t.Cmp(cr) != 0 { + return errors.New("otr: ZKP cR failed in SMP4 message") + } + + r.Exp(rb, c.smp.a3, p) + if r.Cmp(c.smp.papb) != 0 { + return smpFailureError + } + + return nil +} + +func (c *Conversation) generateSMPAbort() tlv { + return tlv{typ: tlvTypeSMPAbort} +} + +func hashMPIs(h hash.Hash, magic byte, mpis ...*big.Int) []byte { + if h != nil { + h.Reset() + } else { + h = sha256.New() + } + + h.Write([]byte{magic}) + for _, mpi := range mpis { + h.Write(appendMPI(nil, mpi)) + } + return h.Sum(nil) +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/ssh/terminal/terminal.go b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/ssh/terminal/terminal.go new file mode 100644 index 0000000000..9a887598ff --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/ssh/terminal/terminal.go @@ -0,0 +1,951 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package terminal + +import ( + "bytes" + "io" + "sync" + "unicode/utf8" +) + +// EscapeCodes contains escape sequences that can be written to the terminal in +// order to achieve different styles of text. +type EscapeCodes struct { + // Foreground colors + Black, Red, Green, Yellow, Blue, Magenta, Cyan, White []byte + + // Reset all attributes + Reset []byte +} + +var vt100EscapeCodes = EscapeCodes{ + Black: []byte{keyEscape, '[', '3', '0', 'm'}, + Red: []byte{keyEscape, '[', '3', '1', 'm'}, + Green: []byte{keyEscape, '[', '3', '2', 'm'}, + Yellow: []byte{keyEscape, '[', '3', '3', 'm'}, + Blue: []byte{keyEscape, '[', '3', '4', 'm'}, + Magenta: []byte{keyEscape, '[', '3', '5', 'm'}, + Cyan: []byte{keyEscape, '[', '3', '6', 'm'}, + White: []byte{keyEscape, '[', '3', '7', 'm'}, + + Reset: []byte{keyEscape, '[', '0', 'm'}, +} + +// Terminal contains the state for running a VT100 terminal that is capable of +// reading lines of input. +type Terminal struct { + // AutoCompleteCallback, if non-null, is called for each keypress with + // the full input line and the current position of the cursor (in + // bytes, as an index into |line|). If it returns ok=false, the key + // press is processed normally. Otherwise it returns a replacement line + // and the new cursor position. + AutoCompleteCallback func(line string, pos int, key rune) (newLine string, newPos int, ok bool) + + // Escape contains a pointer to the escape codes for this terminal. + // It's always a valid pointer, although the escape codes themselves + // may be empty if the terminal doesn't support them. + Escape *EscapeCodes + + // lock protects the terminal and the state in this object from + // concurrent processing of a key press and a Write() call. + lock sync.Mutex + + c io.ReadWriter + prompt []rune + + // line is the current line being entered. + line []rune + // pos is the logical position of the cursor in line + pos int + // echo is true if local echo is enabled + echo bool + // pasteActive is true iff there is a bracketed paste operation in + // progress. + pasteActive bool + + // cursorX contains the current X value of the cursor where the left + // edge is 0. cursorY contains the row number where the first row of + // the current line is 0. + cursorX, cursorY int + // maxLine is the greatest value of cursorY so far. + maxLine int + + termWidth, termHeight int + + // outBuf contains the terminal data to be sent. + outBuf []byte + // remainder contains the remainder of any partial key sequences after + // a read. It aliases into inBuf. + remainder []byte + inBuf [256]byte + + // history contains previously entered commands so that they can be + // accessed with the up and down keys. + history stRingBuffer + // historyIndex stores the currently accessed history entry, where zero + // means the immediately previous entry. + historyIndex int + // When navigating up and down the history it's possible to return to + // the incomplete, initial line. That value is stored in + // historyPending. + historyPending string +} + +// NewTerminal runs a VT100 terminal on the given ReadWriter. If the ReadWriter is +// a local terminal, that terminal must first have been put into raw mode. +// prompt is a string that is written at the start of each input line (i.e. +// "> "). +func NewTerminal(c io.ReadWriter, prompt string) *Terminal { + return &Terminal{ + Escape: &vt100EscapeCodes, + c: c, + prompt: []rune(prompt), + termWidth: 80, + termHeight: 24, + echo: true, + historyIndex: -1, + } +} + +const ( + keyCtrlD = 4 + keyCtrlU = 21 + keyEnter = '\r' + keyEscape = 27 + keyBackspace = 127 + keyUnknown = 0xd800 /* UTF-16 surrogate area */ + iota + keyUp + keyDown + keyLeft + keyRight + keyAltLeft + keyAltRight + keyHome + keyEnd + keyDeleteWord + keyDeleteLine + keyClearScreen + keyPasteStart + keyPasteEnd +) + +var ( + crlf = []byte{'\r', '\n'} + pasteStart = []byte{keyEscape, '[', '2', '0', '0', '~'} + pasteEnd = []byte{keyEscape, '[', '2', '0', '1', '~'} +) + +// bytesToKey tries to parse a key sequence from b. If successful, it returns +// the key and the remainder of the input. Otherwise it returns utf8.RuneError. +func bytesToKey(b []byte, pasteActive bool) (rune, []byte) { + if len(b) == 0 { + return utf8.RuneError, nil + } + + if !pasteActive { + switch b[0] { + case 1: // ^A + return keyHome, b[1:] + case 5: // ^E + return keyEnd, b[1:] + case 8: // ^H + return keyBackspace, b[1:] + case 11: // ^K + return keyDeleteLine, b[1:] + case 12: // ^L + return keyClearScreen, b[1:] + case 23: // ^W + return keyDeleteWord, b[1:] + } + } + + if b[0] != keyEscape { + if !utf8.FullRune(b) { + return utf8.RuneError, b + } + r, l := utf8.DecodeRune(b) + return r, b[l:] + } + + if !pasteActive && len(b) >= 3 && b[0] == keyEscape && b[1] == '[' { + switch b[2] { + case 'A': + return keyUp, b[3:] + case 'B': + return keyDown, b[3:] + case 'C': + return keyRight, b[3:] + case 'D': + return keyLeft, b[3:] + case 'H': + return keyHome, b[3:] + case 'F': + return keyEnd, b[3:] + } + } + + if !pasteActive && len(b) >= 6 && b[0] == keyEscape && b[1] == '[' && b[2] == '1' && b[3] == ';' && b[4] == '3' { + switch b[5] { + case 'C': + return keyAltRight, b[6:] + case 'D': + return keyAltLeft, b[6:] + } + } + + if !pasteActive && len(b) >= 6 && bytes.Equal(b[:6], pasteStart) { + return keyPasteStart, b[6:] + } + + if pasteActive && len(b) >= 6 && bytes.Equal(b[:6], pasteEnd) { + return keyPasteEnd, b[6:] + } + + // If we get here then we have a key that we don't recognise, or a + // partial sequence. It's not clear how one should find the end of a + // sequence without knowing them all, but it seems that [a-zA-Z~] only + // appears at the end of a sequence. + for i, c := range b[0:] { + if c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '~' { + return keyUnknown, b[i+1:] + } + } + + return utf8.RuneError, b +} + +// queue appends data to the end of t.outBuf +func (t *Terminal) queue(data []rune) { + t.outBuf = append(t.outBuf, []byte(string(data))...) +} + +var eraseUnderCursor = []rune{' ', keyEscape, '[', 'D'} +var space = []rune{' '} + +func isPrintable(key rune) bool { + isInSurrogateArea := key >= 0xd800 && key <= 0xdbff + return key >= 32 && !isInSurrogateArea +} + +// moveCursorToPos appends data to t.outBuf which will move the cursor to the +// given, logical position in the text. +func (t *Terminal) moveCursorToPos(pos int) { + if !t.echo { + return + } + + x := visualLength(t.prompt) + pos + y := x / t.termWidth + x = x % t.termWidth + + up := 0 + if y < t.cursorY { + up = t.cursorY - y + } + + down := 0 + if y > t.cursorY { + down = y - t.cursorY + } + + left := 0 + if x < t.cursorX { + left = t.cursorX - x + } + + right := 0 + if x > t.cursorX { + right = x - t.cursorX + } + + t.cursorX = x + t.cursorY = y + t.move(up, down, left, right) +} + +func (t *Terminal) move(up, down, left, right int) { + movement := make([]rune, 3*(up+down+left+right)) + m := movement + for i := 0; i < up; i++ { + m[0] = keyEscape + m[1] = '[' + m[2] = 'A' + m = m[3:] + } + for i := 0; i < down; i++ { + m[0] = keyEscape + m[1] = '[' + m[2] = 'B' + m = m[3:] + } + for i := 0; i < left; i++ { + m[0] = keyEscape + m[1] = '[' + m[2] = 'D' + m = m[3:] + } + for i := 0; i < right; i++ { + m[0] = keyEscape + m[1] = '[' + m[2] = 'C' + m = m[3:] + } + + t.queue(movement) +} + +func (t *Terminal) clearLineToRight() { + op := []rune{keyEscape, '[', 'K'} + t.queue(op) +} + +const maxLineLength = 4096 + +func (t *Terminal) setLine(newLine []rune, newPos int) { + if t.echo { + t.moveCursorToPos(0) + t.writeLine(newLine) + for i := len(newLine); i < len(t.line); i++ { + t.writeLine(space) + } + t.moveCursorToPos(newPos) + } + t.line = newLine + t.pos = newPos +} + +func (t *Terminal) advanceCursor(places int) { + t.cursorX += places + t.cursorY += t.cursorX / t.termWidth + if t.cursorY > t.maxLine { + t.maxLine = t.cursorY + } + t.cursorX = t.cursorX % t.termWidth + + if places > 0 && t.cursorX == 0 { + // Normally terminals will advance the current position + // when writing a character. But that doesn't happen + // for the last character in a line. However, when + // writing a character (except a new line) that causes + // a line wrap, the position will be advanced two + // places. + // + // So, if we are stopping at the end of a line, we + // need to write a newline so that our cursor can be + // advanced to the next line. + t.outBuf = append(t.outBuf, '\r', '\n') + } +} + +func (t *Terminal) eraseNPreviousChars(n int) { + if n == 0 { + return + } + + if t.pos < n { + n = t.pos + } + t.pos -= n + t.moveCursorToPos(t.pos) + + copy(t.line[t.pos:], t.line[n+t.pos:]) + t.line = t.line[:len(t.line)-n] + if t.echo { + t.writeLine(t.line[t.pos:]) + for i := 0; i < n; i++ { + t.queue(space) + } + t.advanceCursor(n) + t.moveCursorToPos(t.pos) + } +} + +// countToLeftWord returns then number of characters from the cursor to the +// start of the previous word. +func (t *Terminal) countToLeftWord() int { + if t.pos == 0 { + return 0 + } + + pos := t.pos - 1 + for pos > 0 { + if t.line[pos] != ' ' { + break + } + pos-- + } + for pos > 0 { + if t.line[pos] == ' ' { + pos++ + break + } + pos-- + } + + return t.pos - pos +} + +// countToRightWord returns then number of characters from the cursor to the +// start of the next word. +func (t *Terminal) countToRightWord() int { + pos := t.pos + for pos < len(t.line) { + if t.line[pos] == ' ' { + break + } + pos++ + } + for pos < len(t.line) { + if t.line[pos] != ' ' { + break + } + pos++ + } + return pos - t.pos +} + +// visualLength returns the number of visible glyphs in s. +func visualLength(runes []rune) int { + inEscapeSeq := false + length := 0 + + for _, r := range runes { + switch { + case inEscapeSeq: + if (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') { + inEscapeSeq = false + } + case r == '\x1b': + inEscapeSeq = true + default: + length++ + } + } + + return length +} + +// handleKey processes the given key and, optionally, returns a line of text +// that the user has entered. +func (t *Terminal) handleKey(key rune) (line string, ok bool) { + if t.pasteActive && key != keyEnter { + t.addKeyToLine(key) + return + } + + switch key { + case keyBackspace: + if t.pos == 0 { + return + } + t.eraseNPreviousChars(1) + case keyAltLeft: + // move left by a word. + t.pos -= t.countToLeftWord() + t.moveCursorToPos(t.pos) + case keyAltRight: + // move right by a word. + t.pos += t.countToRightWord() + t.moveCursorToPos(t.pos) + case keyLeft: + if t.pos == 0 { + return + } + t.pos-- + t.moveCursorToPos(t.pos) + case keyRight: + if t.pos == len(t.line) { + return + } + t.pos++ + t.moveCursorToPos(t.pos) + case keyHome: + if t.pos == 0 { + return + } + t.pos = 0 + t.moveCursorToPos(t.pos) + case keyEnd: + if t.pos == len(t.line) { + return + } + t.pos = len(t.line) + t.moveCursorToPos(t.pos) + case keyUp: + entry, ok := t.history.NthPreviousEntry(t.historyIndex + 1) + if !ok { + return "", false + } + if t.historyIndex == -1 { + t.historyPending = string(t.line) + } + t.historyIndex++ + runes := []rune(entry) + t.setLine(runes, len(runes)) + case keyDown: + switch t.historyIndex { + case -1: + return + case 0: + runes := []rune(t.historyPending) + t.setLine(runes, len(runes)) + t.historyIndex-- + default: + entry, ok := t.history.NthPreviousEntry(t.historyIndex - 1) + if ok { + t.historyIndex-- + runes := []rune(entry) + t.setLine(runes, len(runes)) + } + } + case keyEnter: + t.moveCursorToPos(len(t.line)) + t.queue([]rune("\r\n")) + line = string(t.line) + ok = true + t.line = t.line[:0] + t.pos = 0 + t.cursorX = 0 + t.cursorY = 0 + t.maxLine = 0 + case keyDeleteWord: + // Delete zero or more spaces and then one or more characters. + t.eraseNPreviousChars(t.countToLeftWord()) + case keyDeleteLine: + // Delete everything from the current cursor position to the + // end of line. + for i := t.pos; i < len(t.line); i++ { + t.queue(space) + t.advanceCursor(1) + } + t.line = t.line[:t.pos] + t.moveCursorToPos(t.pos) + case keyCtrlD: + // Erase the character under the current position. + // The EOF case when the line is empty is handled in + // readLine(). + if t.pos < len(t.line) { + t.pos++ + t.eraseNPreviousChars(1) + } + case keyCtrlU: + t.eraseNPreviousChars(t.pos) + case keyClearScreen: + // Erases the screen and moves the cursor to the home position. + t.queue([]rune("\x1b[2J\x1b[H")) + t.queue(t.prompt) + t.cursorX, t.cursorY = 0, 0 + t.advanceCursor(visualLength(t.prompt)) + t.setLine(t.line, t.pos) + default: + if t.AutoCompleteCallback != nil { + prefix := string(t.line[:t.pos]) + suffix := string(t.line[t.pos:]) + + t.lock.Unlock() + newLine, newPos, completeOk := t.AutoCompleteCallback(prefix+suffix, len(prefix), key) + t.lock.Lock() + + if completeOk { + t.setLine([]rune(newLine), utf8.RuneCount([]byte(newLine)[:newPos])) + return + } + } + if !isPrintable(key) { + return + } + if len(t.line) == maxLineLength { + return + } + t.addKeyToLine(key) + } + return +} + +// addKeyToLine inserts the given key at the current position in the current +// line. +func (t *Terminal) addKeyToLine(key rune) { + if len(t.line) == cap(t.line) { + newLine := make([]rune, len(t.line), 2*(1+len(t.line))) + copy(newLine, t.line) + t.line = newLine + } + t.line = t.line[:len(t.line)+1] + copy(t.line[t.pos+1:], t.line[t.pos:]) + t.line[t.pos] = key + if t.echo { + t.writeLine(t.line[t.pos:]) + } + t.pos++ + t.moveCursorToPos(t.pos) +} + +func (t *Terminal) writeLine(line []rune) { + for len(line) != 0 { + remainingOnLine := t.termWidth - t.cursorX + todo := len(line) + if todo > remainingOnLine { + todo = remainingOnLine + } + t.queue(line[:todo]) + t.advanceCursor(visualLength(line[:todo])) + line = line[todo:] + } +} + +// writeWithCRLF writes buf to w but replaces all occurrences of \n with \r\n. +func writeWithCRLF(w io.Writer, buf []byte) (n int, err error) { + for len(buf) > 0 { + i := bytes.IndexByte(buf, '\n') + todo := len(buf) + if i >= 0 { + todo = i + } + + var nn int + nn, err = w.Write(buf[:todo]) + n += nn + if err != nil { + return n, err + } + buf = buf[todo:] + + if i >= 0 { + if _, err = w.Write(crlf); err != nil { + return n, err + } + n++ + buf = buf[1:] + } + } + + return n, nil +} + +func (t *Terminal) Write(buf []byte) (n int, err error) { + t.lock.Lock() + defer t.lock.Unlock() + + if t.cursorX == 0 && t.cursorY == 0 { + // This is the easy case: there's nothing on the screen that we + // have to move out of the way. + return writeWithCRLF(t.c, buf) + } + + // We have a prompt and possibly user input on the screen. We + // have to clear it first. + t.move(0 /* up */, 0 /* down */, t.cursorX /* left */, 0 /* right */) + t.cursorX = 0 + t.clearLineToRight() + + for t.cursorY > 0 { + t.move(1 /* up */, 0, 0, 0) + t.cursorY-- + t.clearLineToRight() + } + + if _, err = t.c.Write(t.outBuf); err != nil { + return + } + t.outBuf = t.outBuf[:0] + + if n, err = writeWithCRLF(t.c, buf); err != nil { + return + } + + t.writeLine(t.prompt) + if t.echo { + t.writeLine(t.line) + } + + t.moveCursorToPos(t.pos) + + if _, err = t.c.Write(t.outBuf); err != nil { + return + } + t.outBuf = t.outBuf[:0] + return +} + +// ReadPassword temporarily changes the prompt and reads a password, without +// echo, from the terminal. +func (t *Terminal) ReadPassword(prompt string) (line string, err error) { + t.lock.Lock() + defer t.lock.Unlock() + + oldPrompt := t.prompt + t.prompt = []rune(prompt) + t.echo = false + + line, err = t.readLine() + + t.prompt = oldPrompt + t.echo = true + + return +} + +// ReadLine returns a line of input from the terminal. +func (t *Terminal) ReadLine() (line string, err error) { + t.lock.Lock() + defer t.lock.Unlock() + + return t.readLine() +} + +func (t *Terminal) readLine() (line string, err error) { + // t.lock must be held at this point + + if t.cursorX == 0 && t.cursorY == 0 { + t.writeLine(t.prompt) + t.c.Write(t.outBuf) + t.outBuf = t.outBuf[:0] + } + + lineIsPasted := t.pasteActive + + for { + rest := t.remainder + lineOk := false + for !lineOk { + var key rune + key, rest = bytesToKey(rest, t.pasteActive) + if key == utf8.RuneError { + break + } + if !t.pasteActive { + if key == keyCtrlD { + if len(t.line) == 0 { + return "", io.EOF + } + } + if key == keyPasteStart { + t.pasteActive = true + if len(t.line) == 0 { + lineIsPasted = true + } + continue + } + } else if key == keyPasteEnd { + t.pasteActive = false + continue + } + if !t.pasteActive { + lineIsPasted = false + } + line, lineOk = t.handleKey(key) + } + if len(rest) > 0 { + n := copy(t.inBuf[:], rest) + t.remainder = t.inBuf[:n] + } else { + t.remainder = nil + } + t.c.Write(t.outBuf) + t.outBuf = t.outBuf[:0] + if lineOk { + if t.echo { + t.historyIndex = -1 + t.history.Add(line) + } + if lineIsPasted { + err = ErrPasteIndicator + } + return + } + + // t.remainder is a slice at the beginning of t.inBuf + // containing a partial key sequence + readBuf := t.inBuf[len(t.remainder):] + var n int + + t.lock.Unlock() + n, err = t.c.Read(readBuf) + t.lock.Lock() + + if err != nil { + return + } + + t.remainder = t.inBuf[:n+len(t.remainder)] + } +} + +// SetPrompt sets the prompt to be used when reading subsequent lines. +func (t *Terminal) SetPrompt(prompt string) { + t.lock.Lock() + defer t.lock.Unlock() + + t.prompt = []rune(prompt) +} + +func (t *Terminal) clearAndRepaintLinePlusNPrevious(numPrevLines int) { + // Move cursor to column zero at the start of the line. + t.move(t.cursorY, 0, t.cursorX, 0) + t.cursorX, t.cursorY = 0, 0 + t.clearLineToRight() + for t.cursorY < numPrevLines { + // Move down a line + t.move(0, 1, 0, 0) + t.cursorY++ + t.clearLineToRight() + } + // Move back to beginning. + t.move(t.cursorY, 0, 0, 0) + t.cursorX, t.cursorY = 0, 0 + + t.queue(t.prompt) + t.advanceCursor(visualLength(t.prompt)) + t.writeLine(t.line) + t.moveCursorToPos(t.pos) +} + +func (t *Terminal) SetSize(width, height int) error { + t.lock.Lock() + defer t.lock.Unlock() + + if width == 0 { + width = 1 + } + + oldWidth := t.termWidth + t.termWidth, t.termHeight = width, height + + switch { + case width == oldWidth: + // If the width didn't change then nothing else needs to be + // done. + return nil + case len(t.line) == 0 && t.cursorX == 0 && t.cursorY == 0: + // If there is nothing on current line and no prompt printed, + // just do nothing + return nil + case width < oldWidth: + // Some terminals (e.g. xterm) will truncate lines that were + // too long when shinking. Others, (e.g. gnome-terminal) will + // attempt to wrap them. For the former, repainting t.maxLine + // works great, but that behaviour goes badly wrong in the case + // of the latter because they have doubled every full line. + + // We assume that we are working on a terminal that wraps lines + // and adjust the cursor position based on every previous line + // wrapping and turning into two. This causes the prompt on + // xterms to move upwards, which isn't great, but it avoids a + // huge mess with gnome-terminal. + if t.cursorX >= t.termWidth { + t.cursorX = t.termWidth - 1 + } + t.cursorY *= 2 + t.clearAndRepaintLinePlusNPrevious(t.maxLine * 2) + case width > oldWidth: + // If the terminal expands then our position calculations will + // be wrong in the future because we think the cursor is + // |t.pos| chars into the string, but there will be a gap at + // the end of any wrapped line. + // + // But the position will actually be correct until we move, so + // we can move back to the beginning and repaint everything. + t.clearAndRepaintLinePlusNPrevious(t.maxLine) + } + + _, err := t.c.Write(t.outBuf) + t.outBuf = t.outBuf[:0] + return err +} + +type pasteIndicatorError struct{} + +func (pasteIndicatorError) Error() string { + return "terminal: ErrPasteIndicator not correctly handled" +} + +// ErrPasteIndicator may be returned from ReadLine as the error, in addition +// to valid line data. It indicates that bracketed paste mode is enabled and +// that the returned line consists only of pasted data. Programs may wish to +// interpret pasted data more literally than typed data. +var ErrPasteIndicator = pasteIndicatorError{} + +// SetBracketedPasteMode requests that the terminal bracket paste operations +// with markers. Not all terminals support this but, if it is supported, then +// enabling this mode will stop any autocomplete callback from running due to +// pastes. Additionally, any lines that are completely pasted will be returned +// from ReadLine with the error set to ErrPasteIndicator. +func (t *Terminal) SetBracketedPasteMode(on bool) { + if on { + io.WriteString(t.c, "\x1b[?2004h") + } else { + io.WriteString(t.c, "\x1b[?2004l") + } +} + +// stRingBuffer is a ring buffer of strings. +type stRingBuffer struct { + // entries contains max elements. + entries []string + max int + // head contains the index of the element most recently added to the ring. + head int + // size contains the number of elements in the ring. + size int +} + +func (s *stRingBuffer) Add(a string) { + if s.entries == nil { + const defaultNumEntries = 100 + s.entries = make([]string, defaultNumEntries) + s.max = defaultNumEntries + } + + s.head = (s.head + 1) % s.max + s.entries[s.head] = a + if s.size < s.max { + s.size++ + } +} + +// NthPreviousEntry returns the value passed to the nth previous call to Add. +// If n is zero then the immediately prior value is returned, if one, then the +// next most recent, and so on. If such an element doesn't exist then ok is +// false. +func (s *stRingBuffer) NthPreviousEntry(n int) (value string, ok bool) { + if n >= s.size { + return "", false + } + index := s.head - n + if index < 0 { + index += s.max + } + return s.entries[index], true +} + +// readPasswordLine reads from reader until it finds \n or io.EOF. +// The slice returned does not include the \n. +// readPasswordLine also ignores any \r it finds. +func readPasswordLine(reader io.Reader) ([]byte, error) { + var buf [1]byte + var ret []byte + + for { + n, err := reader.Read(buf[:]) + if n > 0 { + switch buf[0] { + case '\n': + return ret, nil + case '\r': + // remove \r from passwords on Windows + default: + ret = append(ret, buf[0]) + } + continue + } + if err != nil { + if err == io.EOF && len(ret) > 0 { + return ret, nil + } + return ret, err + } + } +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/ssh/terminal/util.go b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/ssh/terminal/util.go new file mode 100644 index 0000000000..3911040840 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/ssh/terminal/util.go @@ -0,0 +1,114 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build aix darwin dragonfly freebsd linux,!appengine netbsd openbsd + +// Package terminal provides support functions for dealing with terminals, as +// commonly found on UNIX systems. +// +// Putting a terminal into raw mode is the most common requirement: +// +// oldState, err := terminal.MakeRaw(0) +// if err != nil { +// panic(err) +// } +// defer terminal.Restore(0, oldState) +package terminal // import "golang.org/x/crypto/ssh/terminal" + +import ( + "golang.org/x/sys/unix" +) + +// State contains the state of a terminal. +type State struct { + termios unix.Termios +} + +// IsTerminal returns whether the given file descriptor is a terminal. +func IsTerminal(fd int) bool { + _, err := unix.IoctlGetTermios(fd, ioctlReadTermios) + return err == nil +} + +// MakeRaw put the terminal connected to the given file descriptor into raw +// mode and returns the previous state of the terminal so that it can be +// restored. +func MakeRaw(fd int) (*State, error) { + termios, err := unix.IoctlGetTermios(fd, ioctlReadTermios) + if err != nil { + return nil, err + } + + oldState := State{termios: *termios} + + // This attempts to replicate the behaviour documented for cfmakeraw in + // the termios(3) manpage. + termios.Iflag &^= unix.IGNBRK | unix.BRKINT | unix.PARMRK | unix.ISTRIP | unix.INLCR | unix.IGNCR | unix.ICRNL | unix.IXON + termios.Oflag &^= unix.OPOST + termios.Lflag &^= unix.ECHO | unix.ECHONL | unix.ICANON | unix.ISIG | unix.IEXTEN + termios.Cflag &^= unix.CSIZE | unix.PARENB + termios.Cflag |= unix.CS8 + termios.Cc[unix.VMIN] = 1 + termios.Cc[unix.VTIME] = 0 + if err := unix.IoctlSetTermios(fd, ioctlWriteTermios, termios); err != nil { + return nil, err + } + + return &oldState, nil +} + +// GetState returns the current state of a terminal which may be useful to +// restore the terminal after a signal. +func GetState(fd int) (*State, error) { + termios, err := unix.IoctlGetTermios(fd, ioctlReadTermios) + if err != nil { + return nil, err + } + + return &State{termios: *termios}, nil +} + +// Restore restores the terminal connected to the given file descriptor to a +// previous state. +func Restore(fd int, state *State) error { + return unix.IoctlSetTermios(fd, ioctlWriteTermios, &state.termios) +} + +// GetSize returns the dimensions of the given terminal. +func GetSize(fd int) (width, height int, err error) { + ws, err := unix.IoctlGetWinsize(fd, unix.TIOCGWINSZ) + if err != nil { + return -1, -1, err + } + return int(ws.Col), int(ws.Row), nil +} + +// passwordReader is an io.Reader that reads from a specific file descriptor. +type passwordReader int + +func (r passwordReader) Read(buf []byte) (int, error) { + return unix.Read(int(r), buf) +} + +// ReadPassword reads a line of input from a terminal without local echo. This +// is commonly used for inputting passwords and other sensitive data. The slice +// returned does not include the \n. +func ReadPassword(fd int) ([]byte, error) { + termios, err := unix.IoctlGetTermios(fd, ioctlReadTermios) + if err != nil { + return nil, err + } + + newState := *termios + newState.Lflag &^= unix.ECHO + newState.Lflag |= unix.ICANON | unix.ISIG + newState.Iflag |= unix.ICRNL + if err := unix.IoctlSetTermios(fd, ioctlWriteTermios, &newState); err != nil { + return nil, err + } + + defer unix.IoctlSetTermios(fd, ioctlWriteTermios, termios) + + return readPasswordLine(passwordReader(fd)) +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/ssh/terminal/util_aix.go b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/ssh/terminal/util_aix.go new file mode 100644 index 0000000000..dfcd627859 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/ssh/terminal/util_aix.go @@ -0,0 +1,12 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build aix + +package terminal + +import "golang.org/x/sys/unix" + +const ioctlReadTermios = unix.TCGETS +const ioctlWriteTermios = unix.TCSETS diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/ssh/terminal/util_bsd.go b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/ssh/terminal/util_bsd.go new file mode 100644 index 0000000000..cb23a59049 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/ssh/terminal/util_bsd.go @@ -0,0 +1,12 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin dragonfly freebsd netbsd openbsd + +package terminal + +import "golang.org/x/sys/unix" + +const ioctlReadTermios = unix.TIOCGETA +const ioctlWriteTermios = unix.TIOCSETA diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/ssh/terminal/util_linux.go b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/ssh/terminal/util_linux.go new file mode 100644 index 0000000000..5fadfe8a1d --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/ssh/terminal/util_linux.go @@ -0,0 +1,10 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package terminal + +import "golang.org/x/sys/unix" + +const ioctlReadTermios = unix.TCGETS +const ioctlWriteTermios = unix.TCSETS diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/ssh/terminal/util_plan9.go b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/ssh/terminal/util_plan9.go new file mode 100644 index 0000000000..9317ac7ede --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/ssh/terminal/util_plan9.go @@ -0,0 +1,58 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package terminal provides support functions for dealing with terminals, as +// commonly found on UNIX systems. +// +// Putting a terminal into raw mode is the most common requirement: +// +// oldState, err := terminal.MakeRaw(0) +// if err != nil { +// panic(err) +// } +// defer terminal.Restore(0, oldState) +package terminal + +import ( + "fmt" + "runtime" +) + +type State struct{} + +// IsTerminal returns whether the given file descriptor is a terminal. +func IsTerminal(fd int) bool { + return false +} + +// MakeRaw put the terminal connected to the given file descriptor into raw +// mode and returns the previous state of the terminal so that it can be +// restored. +func MakeRaw(fd int) (*State, error) { + return nil, fmt.Errorf("terminal: MakeRaw not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) +} + +// GetState returns the current state of a terminal which may be useful to +// restore the terminal after a signal. +func GetState(fd int) (*State, error) { + return nil, fmt.Errorf("terminal: GetState not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) +} + +// Restore restores the terminal connected to the given file descriptor to a +// previous state. +func Restore(fd int, state *State) error { + return fmt.Errorf("terminal: Restore not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) +} + +// GetSize returns the dimensions of the given terminal. +func GetSize(fd int) (width, height int, err error) { + return 0, 0, fmt.Errorf("terminal: GetSize not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) +} + +// ReadPassword reads a line of input from a terminal without local echo. This +// is commonly used for inputting passwords and other sensitive data. The slice +// returned does not include the \n. +func ReadPassword(fd int) ([]byte, error) { + return nil, fmt.Errorf("terminal: ReadPassword not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/ssh/terminal/util_solaris.go b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/ssh/terminal/util_solaris.go new file mode 100644 index 0000000000..3d5f06a9f0 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/ssh/terminal/util_solaris.go @@ -0,0 +1,124 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build solaris + +package terminal // import "golang.org/x/crypto/ssh/terminal" + +import ( + "golang.org/x/sys/unix" + "io" + "syscall" +) + +// State contains the state of a terminal. +type State struct { + termios unix.Termios +} + +// IsTerminal returns whether the given file descriptor is a terminal. +func IsTerminal(fd int) bool { + _, err := unix.IoctlGetTermio(fd, unix.TCGETA) + return err == nil +} + +// ReadPassword reads a line of input from a terminal without local echo. This +// is commonly used for inputting passwords and other sensitive data. The slice +// returned does not include the \n. +func ReadPassword(fd int) ([]byte, error) { + // see also: http://src.illumos.org/source/xref/illumos-gate/usr/src/lib/libast/common/uwin/getpass.c + val, err := unix.IoctlGetTermios(fd, unix.TCGETS) + if err != nil { + return nil, err + } + oldState := *val + + newState := oldState + newState.Lflag &^= syscall.ECHO + newState.Lflag |= syscall.ICANON | syscall.ISIG + newState.Iflag |= syscall.ICRNL + err = unix.IoctlSetTermios(fd, unix.TCSETS, &newState) + if err != nil { + return nil, err + } + + defer unix.IoctlSetTermios(fd, unix.TCSETS, &oldState) + + var buf [16]byte + var ret []byte + for { + n, err := syscall.Read(fd, buf[:]) + if err != nil { + return nil, err + } + if n == 0 { + if len(ret) == 0 { + return nil, io.EOF + } + break + } + if buf[n-1] == '\n' { + n-- + } + ret = append(ret, buf[:n]...) + if n < len(buf) { + break + } + } + + return ret, nil +} + +// MakeRaw puts the terminal connected to the given file descriptor into raw +// mode and returns the previous state of the terminal so that it can be +// restored. +// see http://cr.illumos.org/~webrev/andy_js/1060/ +func MakeRaw(fd int) (*State, error) { + termios, err := unix.IoctlGetTermios(fd, unix.TCGETS) + if err != nil { + return nil, err + } + + oldState := State{termios: *termios} + + termios.Iflag &^= unix.IGNBRK | unix.BRKINT | unix.PARMRK | unix.ISTRIP | unix.INLCR | unix.IGNCR | unix.ICRNL | unix.IXON + termios.Oflag &^= unix.OPOST + termios.Lflag &^= unix.ECHO | unix.ECHONL | unix.ICANON | unix.ISIG | unix.IEXTEN + termios.Cflag &^= unix.CSIZE | unix.PARENB + termios.Cflag |= unix.CS8 + termios.Cc[unix.VMIN] = 1 + termios.Cc[unix.VTIME] = 0 + + if err := unix.IoctlSetTermios(fd, unix.TCSETS, termios); err != nil { + return nil, err + } + + return &oldState, nil +} + +// Restore restores the terminal connected to the given file descriptor to a +// previous state. +func Restore(fd int, oldState *State) error { + return unix.IoctlSetTermios(fd, unix.TCSETS, &oldState.termios) +} + +// GetState returns the current state of a terminal which may be useful to +// restore the terminal after a signal. +func GetState(fd int) (*State, error) { + termios, err := unix.IoctlGetTermios(fd, unix.TCGETS) + if err != nil { + return nil, err + } + + return &State{termios: *termios}, nil +} + +// GetSize returns the dimensions of the given terminal. +func GetSize(fd int) (width, height int, err error) { + ws, err := unix.IoctlGetWinsize(fd, unix.TIOCGWINSZ) + if err != nil { + return 0, 0, err + } + return int(ws.Col), int(ws.Row), nil +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/ssh/terminal/util_windows.go b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/ssh/terminal/util_windows.go new file mode 100644 index 0000000000..6cb8a95038 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/ssh/terminal/util_windows.go @@ -0,0 +1,103 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +// Package terminal provides support functions for dealing with terminals, as +// commonly found on UNIX systems. +// +// Putting a terminal into raw mode is the most common requirement: +// +// oldState, err := terminal.MakeRaw(0) +// if err != nil { +// panic(err) +// } +// defer terminal.Restore(0, oldState) +package terminal + +import ( + "os" + + "golang.org/x/sys/windows" +) + +type State struct { + mode uint32 +} + +// IsTerminal returns whether the given file descriptor is a terminal. +func IsTerminal(fd int) bool { + var st uint32 + err := windows.GetConsoleMode(windows.Handle(fd), &st) + return err == nil +} + +// MakeRaw put the terminal connected to the given file descriptor into raw +// mode and returns the previous state of the terminal so that it can be +// restored. +func MakeRaw(fd int) (*State, error) { + var st uint32 + if err := windows.GetConsoleMode(windows.Handle(fd), &st); err != nil { + return nil, err + } + raw := st &^ (windows.ENABLE_ECHO_INPUT | windows.ENABLE_PROCESSED_INPUT | windows.ENABLE_LINE_INPUT | windows.ENABLE_PROCESSED_OUTPUT) + if err := windows.SetConsoleMode(windows.Handle(fd), raw); err != nil { + return nil, err + } + return &State{st}, nil +} + +// GetState returns the current state of a terminal which may be useful to +// restore the terminal after a signal. +func GetState(fd int) (*State, error) { + var st uint32 + if err := windows.GetConsoleMode(windows.Handle(fd), &st); err != nil { + return nil, err + } + return &State{st}, nil +} + +// Restore restores the terminal connected to the given file descriptor to a +// previous state. +func Restore(fd int, state *State) error { + return windows.SetConsoleMode(windows.Handle(fd), state.mode) +} + +// GetSize returns the dimensions of the given terminal. +func GetSize(fd int) (width, height int, err error) { + var info windows.ConsoleScreenBufferInfo + if err := windows.GetConsoleScreenBufferInfo(windows.Handle(fd), &info); err != nil { + return 0, 0, err + } + return int(info.Size.X), int(info.Size.Y), nil +} + +// ReadPassword reads a line of input from a terminal without local echo. This +// is commonly used for inputting passwords and other sensitive data. The slice +// returned does not include the \n. +func ReadPassword(fd int) ([]byte, error) { + var st uint32 + if err := windows.GetConsoleMode(windows.Handle(fd), &st); err != nil { + return nil, err + } + old := st + + st &^= (windows.ENABLE_ECHO_INPUT) + st |= (windows.ENABLE_PROCESSED_INPUT | windows.ENABLE_LINE_INPUT | windows.ENABLE_PROCESSED_OUTPUT) + if err := windows.SetConsoleMode(windows.Handle(fd), st); err != nil { + return nil, err + } + + defer windows.SetConsoleMode(windows.Handle(fd), old) + + var h windows.Handle + p, _ := windows.GetCurrentProcess() + if err := windows.DuplicateHandle(p, windows.Handle(fd), p, &h, 0, false, windows.DUPLICATE_SAME_ACCESS); err != nil { + return nil, err + } + + f := os.NewFile(uintptr(h), "stdin") + defer f.Close() + return readPasswordLine(f) +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/ssh/test/doc.go b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/ssh/test/doc.go new file mode 100644 index 0000000000..198f0ca1e2 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/ssh/test/doc.go @@ -0,0 +1,7 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package test contains integration tests for the +// golang.org/x/crypto/ssh package. +package test // import "golang.org/x/crypto/ssh/test" diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/ssh/test/sshd_test_pw.c b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/ssh/test/sshd_test_pw.c new file mode 100644 index 0000000000..2794a563a4 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/crypto/ssh/test/sshd_test_pw.c @@ -0,0 +1,173 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// sshd_test_pw.c +// Wrapper to inject test password data for sshd PAM authentication +// +// This wrapper implements custom versions of getpwnam, getpwnam_r, +// getspnam and getspnam_r. These functions first call their real +// libc versions, then check if the requested user matches test user +// specified in env variable TEST_USER and if so replace the password +// with crypted() value of TEST_PASSWD env variable. +// +// Compile: +// gcc -Wall -shared -o sshd_test_pw.so -fPIC sshd_test_pw.c +// +// Compile with debug: +// gcc -DVERBOSE -Wall -shared -o sshd_test_pw.so -fPIC sshd_test_pw.c +// +// Run sshd: +// LD_PRELOAD="sshd_test_pw.so" TEST_USER="..." TEST_PASSWD="..." sshd ... + +// +build ignore + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include + +#ifdef VERBOSE +#define DEBUG(X...) fprintf(stderr, X) +#else +#define DEBUG(X...) while (0) { } +#endif + +/* crypt() password */ +static char * +pwhash(char *passwd) { + return strdup(crypt(passwd, "$6$")); +} + +/* Pointers to real functions in libc */ +static struct passwd * (*real_getpwnam)(const char *) = NULL; +static int (*real_getpwnam_r)(const char *, struct passwd *, char *, size_t, struct passwd **) = NULL; +static struct spwd * (*real_getspnam)(const char *) = NULL; +static int (*real_getspnam_r)(const char *, struct spwd *, char *, size_t, struct spwd **) = NULL; + +/* Cached test user and test password */ +static char *test_user = NULL; +static char *test_passwd_hash = NULL; + +static void +init(void) { + /* Fetch real libc function pointers */ + real_getpwnam = dlsym(RTLD_NEXT, "getpwnam"); + real_getpwnam_r = dlsym(RTLD_NEXT, "getpwnam_r"); + real_getspnam = dlsym(RTLD_NEXT, "getspnam"); + real_getspnam_r = dlsym(RTLD_NEXT, "getspnam_r"); + + /* abort if env variables are not defined */ + if (getenv("TEST_USER") == NULL || getenv("TEST_PASSWD") == NULL) { + fprintf(stderr, "env variables TEST_USER and TEST_PASSWD are missing\n"); + abort(); + } + + /* Fetch test user and test password from env */ + test_user = strdup(getenv("TEST_USER")); + test_passwd_hash = pwhash(getenv("TEST_PASSWD")); + + DEBUG("sshd_test_pw init():\n"); + DEBUG("\treal_getpwnam: %p\n", real_getpwnam); + DEBUG("\treal_getpwnam_r: %p\n", real_getpwnam_r); + DEBUG("\treal_getspnam: %p\n", real_getspnam); + DEBUG("\treal_getspnam_r: %p\n", real_getspnam_r); + DEBUG("\tTEST_USER: '%s'\n", test_user); + DEBUG("\tTEST_PASSWD: '%s'\n", getenv("TEST_PASSWD")); + DEBUG("\tTEST_PASSWD_HASH: '%s'\n", test_passwd_hash); +} + +static int +is_test_user(const char *name) { + if (test_user != NULL && strcmp(test_user, name) == 0) + return 1; + return 0; +} + +/* getpwnam */ + +struct passwd * +getpwnam(const char *name) { + struct passwd *pw; + + DEBUG("sshd_test_pw getpwnam(%s)\n", name); + + if (real_getpwnam == NULL) + init(); + if ((pw = real_getpwnam(name)) == NULL) + return NULL; + + if (is_test_user(name)) + pw->pw_passwd = strdup(test_passwd_hash); + + return pw; +} + +/* getpwnam_r */ + +int +getpwnam_r(const char *name, + struct passwd *pwd, + char *buf, + size_t buflen, + struct passwd **result) { + int r; + + DEBUG("sshd_test_pw getpwnam_r(%s)\n", name); + + if (real_getpwnam_r == NULL) + init(); + if ((r = real_getpwnam_r(name, pwd, buf, buflen, result)) != 0 || *result == NULL) + return r; + + if (is_test_user(name)) + pwd->pw_passwd = strdup(test_passwd_hash); + + return 0; +} + +/* getspnam */ + +struct spwd * +getspnam(const char *name) { + struct spwd *sp; + + DEBUG("sshd_test_pw getspnam(%s)\n", name); + + if (real_getspnam == NULL) + init(); + if ((sp = real_getspnam(name)) == NULL) + return NULL; + + if (is_test_user(name)) + sp->sp_pwdp = strdup(test_passwd_hash); + + return sp; +} + +/* getspnam_r */ + +int +getspnam_r(const char *name, + struct spwd *spbuf, + char *buf, + size_t buflen, + struct spwd **spbufp) { + int r; + + DEBUG("sshd_test_pw getspnam_r(%s)\n", name); + + if (real_getspnam_r == NULL) + init(); + if ((r = real_getspnam_r(name, spbuf, buf, buflen, spbufp)) != 0) + return r; + + if (is_test_user(name)) + spbuf->sp_pwdp = strdup(test_passwd_hash); + + return r; +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sync/LICENSE b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sync/LICENSE new file mode 100644 index 0000000000..6a66aea5ea --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sync/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sync/PATENTS b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sync/PATENTS new file mode 100644 index 0000000000..733099041f --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sync/PATENTS @@ -0,0 +1,22 @@ +Additional IP Rights Grant (Patents) + +"This implementation" means the copyrightable works distributed by +Google as part of the Go project. + +Google 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, +transfer and otherwise run, modify and propagate the contents of this +implementation of Go, where such license applies only to those patent +claims, both currently owned or controlled by Google and acquired in +the future, licensable by Google that are necessarily infringed by this +implementation of Go. This grant does not include claims that would be +infringed only as a consequence of further modification of this +implementation. If you or your agent or exclusive licensee institute or +order or agree to the institution of patent litigation against any +entity (including a cross-claim or counterclaim in a lawsuit) alleging +that this implementation of Go or any code incorporated within this +implementation of Go constitutes direct or contributory patent +infringement, or inducement of patent infringement, then any patent +rights granted to you under this License for this implementation of Go +shall terminate as of the date such litigation is filed. diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sync/README.md b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sync/README.md new file mode 100644 index 0000000000..1f8436cc9c --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sync/README.md @@ -0,0 +1,18 @@ +# Go Sync + +This repository provides Go concurrency primitives in addition to the +ones provided by the language and "sync" and "sync/atomic" packages. + +## Download/Install + +The easiest way to install is to run `go get -u golang.org/x/sync`. You can +also manually git clone the repository to `$GOPATH/src/golang.org/x/sync`. + +## Report Issues / Send Patches + +This repository uses Gerrit for code changes. To learn how to submit changes to +this repository, see https://golang.org/doc/contribute.html. + +The main issue tracker for the sync repository is located at +https://github.com/golang/go/issues. Prefix your issue with "x/sync:" in the +subject line, so it is easy to find. diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sync/errgroup/errgroup.go b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sync/errgroup/errgroup.go new file mode 100644 index 0000000000..9857fe53d3 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sync/errgroup/errgroup.go @@ -0,0 +1,66 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package errgroup provides synchronization, error propagation, and Context +// cancelation for groups of goroutines working on subtasks of a common task. +package errgroup + +import ( + "context" + "sync" +) + +// A Group is a collection of goroutines working on subtasks that are part of +// the same overall task. +// +// A zero Group is valid and does not cancel on error. +type Group struct { + cancel func() + + wg sync.WaitGroup + + errOnce sync.Once + err error +} + +// WithContext returns a new Group and an associated Context derived from ctx. +// +// The derived Context is canceled the first time a function passed to Go +// returns a non-nil error or the first time Wait returns, whichever occurs +// first. +func WithContext(ctx context.Context) (*Group, context.Context) { + ctx, cancel := context.WithCancel(ctx) + return &Group{cancel: cancel}, ctx +} + +// Wait blocks until all function calls from the Go method have returned, then +// returns the first non-nil error (if any) from them. +func (g *Group) Wait() error { + g.wg.Wait() + if g.cancel != nil { + g.cancel() + } + return g.err +} + +// Go calls the given function in a new goroutine. +// +// The first call to return a non-nil error cancels the group; its error will be +// returned by Wait. +func (g *Group) Go(f func() error) { + g.wg.Add(1) + + go func() { + defer g.wg.Done() + + if err := f(); err != nil { + g.errOnce.Do(func() { + g.err = err + if g.cancel != nil { + g.cancel() + } + }) + } + }() +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/LICENSE b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/LICENSE new file mode 100644 index 0000000000..6a66aea5ea --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/PATENTS b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/PATENTS new file mode 100644 index 0000000000..733099041f --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/PATENTS @@ -0,0 +1,22 @@ +Additional IP Rights Grant (Patents) + +"This implementation" means the copyrightable works distributed by +Google as part of the Go project. + +Google 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, +transfer and otherwise run, modify and propagate the contents of this +implementation of Go, where such license applies only to those patent +claims, both currently owned or controlled by Google and acquired in +the future, licensable by Google that are necessarily infringed by this +implementation of Go. This grant does not include claims that would be +infringed only as a consequence of further modification of this +implementation. If you or your agent or exclusive licensee institute or +order or agree to the institution of patent litigation against any +entity (including a cross-claim or counterclaim in a lawsuit) alleging +that this implementation of Go or any code incorporated within this +implementation of Go constitutes direct or contributory patent +infringement, or inducement of patent infringement, then any patent +rights granted to you under this License for this implementation of Go +shall terminate as of the date such litigation is filed. diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/README.md b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/README.md new file mode 100644 index 0000000000..ef6c9e59c2 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/README.md @@ -0,0 +1,18 @@ +# sys + +This repository holds supplemental Go packages for low-level interactions with +the operating system. + +## Download/Install + +The easiest way to install is to run `go get -u golang.org/x/sys`. You can +also manually git clone the repository to `$GOPATH/src/golang.org/x/sys`. + +## Report Issues / Send Patches + +This repository uses Gerrit for code changes. To learn how to submit changes to +this repository, see https://golang.org/doc/contribute.html. + +The main issue tracker for the sys repository is located at +https://github.com/golang/go/issues. Prefix your issue with "x/sys:" in the +subject line, so it is easy to find. diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/cpu/cpu.go b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/cpu/cpu.go new file mode 100644 index 0000000000..84962cf0f0 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/cpu/cpu.go @@ -0,0 +1,87 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package cpu implements processor feature detection for +// various CPU architectures. +package cpu + +// CacheLinePad is used to pad structs to avoid false sharing. +type CacheLinePad struct{ _ [cacheLineSize]byte } + +// X86 contains the supported CPU features of the +// current X86/AMD64 platform. If the current platform +// is not X86/AMD64 then all feature flags are false. +// +// X86 is padded to avoid false sharing. Further the HasAVX +// and HasAVX2 are only set if the OS supports XMM and YMM +// registers in addition to the CPUID feature bit being set. +var X86 struct { + _ CacheLinePad + HasAES bool // AES hardware implementation (AES NI) + HasADX bool // Multi-precision add-carry instruction extensions + HasAVX bool // Advanced vector extension + HasAVX2 bool // Advanced vector extension 2 + HasBMI1 bool // Bit manipulation instruction set 1 + HasBMI2 bool // Bit manipulation instruction set 2 + HasERMS bool // Enhanced REP for MOVSB and STOSB + HasFMA bool // Fused-multiply-add instructions + HasOSXSAVE bool // OS supports XSAVE/XRESTOR for saving/restoring XMM registers. + HasPCLMULQDQ bool // PCLMULQDQ instruction - most often used for AES-GCM + HasPOPCNT bool // Hamming weight instruction POPCNT. + HasSSE2 bool // Streaming SIMD extension 2 (always available on amd64) + HasSSE3 bool // Streaming SIMD extension 3 + HasSSSE3 bool // Supplemental streaming SIMD extension 3 + HasSSE41 bool // Streaming SIMD extension 4 and 4.1 + HasSSE42 bool // Streaming SIMD extension 4 and 4.2 + _ CacheLinePad +} + +// ARM64 contains the supported CPU features of the +// current ARMv8(aarch64) platform. If the current platform +// is not arm64 then all feature flags are false. +var ARM64 struct { + _ CacheLinePad + HasFP bool // Floating-point instruction set (always available) + HasASIMD bool // Advanced SIMD (always available) + HasEVTSTRM bool // Event stream support + HasAES bool // AES hardware implementation + HasPMULL bool // Polynomial multiplication instruction set + HasSHA1 bool // SHA1 hardware implementation + HasSHA2 bool // SHA2 hardware implementation + HasCRC32 bool // CRC32 hardware implementation + HasATOMICS bool // Atomic memory operation instruction set + HasFPHP bool // Half precision floating-point instruction set + HasASIMDHP bool // Advanced SIMD half precision instruction set + HasCPUID bool // CPUID identification scheme registers + HasASIMDRDM bool // Rounding double multiply add/subtract instruction set + HasJSCVT bool // Javascript conversion from floating-point to integer + HasFCMA bool // Floating-point multiplication and addition of complex numbers + HasLRCPC bool // Release Consistent processor consistent support + HasDCPOP bool // Persistent memory support + HasSHA3 bool // SHA3 hardware implementation + HasSM3 bool // SM3 hardware implementation + HasSM4 bool // SM4 hardware implementation + HasASIMDDP bool // Advanced SIMD double precision instruction set + HasSHA512 bool // SHA512 hardware implementation + HasSVE bool // Scalable Vector Extensions + HasASIMDFHM bool // Advanced SIMD multiplication FP16 to FP32 + _ CacheLinePad +} + +// PPC64 contains the supported CPU features of the current ppc64/ppc64le platforms. +// If the current platform is not ppc64/ppc64le then all feature flags are false. +// +// For ppc64/ppc64le, it is safe to check only for ISA level starting on ISA v3.00, +// since there are no optional categories. There are some exceptions that also +// require kernel support to work (DARN, SCV), so there are feature bits for +// those as well. The minimum processor requirement is POWER8 (ISA 2.07). +// The struct is padded to avoid false sharing. +var PPC64 struct { + _ CacheLinePad + HasDARN bool // Hardware random number generator (requires kernel enablement) + HasSCV bool // Syscall vectored (requires kernel enablement) + IsPOWER8 bool // ISA v2.07 (POWER8) + IsPOWER9 bool // ISA v3.00 (POWER9) + _ CacheLinePad +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/cpu/cpu_arm.go b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/cpu/cpu_arm.go new file mode 100644 index 0000000000..7f2348b7d4 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/cpu/cpu_arm.go @@ -0,0 +1,9 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cpu + +const cacheLineSize = 32 + +func doinit() {} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/cpu/cpu_arm64.go b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/cpu/cpu_arm64.go new file mode 100644 index 0000000000..02ed58b30d --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/cpu/cpu_arm64.go @@ -0,0 +1,67 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cpu + +const cacheLineSize = 64 + +// HWCAP/HWCAP2 bits. These are exposed by Linux. +const ( + hwcap_FP = 1 << 0 + hwcap_ASIMD = 1 << 1 + hwcap_EVTSTRM = 1 << 2 + hwcap_AES = 1 << 3 + hwcap_PMULL = 1 << 4 + hwcap_SHA1 = 1 << 5 + hwcap_SHA2 = 1 << 6 + hwcap_CRC32 = 1 << 7 + hwcap_ATOMICS = 1 << 8 + hwcap_FPHP = 1 << 9 + hwcap_ASIMDHP = 1 << 10 + hwcap_CPUID = 1 << 11 + hwcap_ASIMDRDM = 1 << 12 + hwcap_JSCVT = 1 << 13 + hwcap_FCMA = 1 << 14 + hwcap_LRCPC = 1 << 15 + hwcap_DCPOP = 1 << 16 + hwcap_SHA3 = 1 << 17 + hwcap_SM3 = 1 << 18 + hwcap_SM4 = 1 << 19 + hwcap_ASIMDDP = 1 << 20 + hwcap_SHA512 = 1 << 21 + hwcap_SVE = 1 << 22 + hwcap_ASIMDFHM = 1 << 23 +) + +func doinit() { + // HWCAP feature bits + ARM64.HasFP = isSet(HWCap, hwcap_FP) + ARM64.HasASIMD = isSet(HWCap, hwcap_ASIMD) + ARM64.HasEVTSTRM = isSet(HWCap, hwcap_EVTSTRM) + ARM64.HasAES = isSet(HWCap, hwcap_AES) + ARM64.HasPMULL = isSet(HWCap, hwcap_PMULL) + ARM64.HasSHA1 = isSet(HWCap, hwcap_SHA1) + ARM64.HasSHA2 = isSet(HWCap, hwcap_SHA2) + ARM64.HasCRC32 = isSet(HWCap, hwcap_CRC32) + ARM64.HasATOMICS = isSet(HWCap, hwcap_ATOMICS) + ARM64.HasFPHP = isSet(HWCap, hwcap_FPHP) + ARM64.HasASIMDHP = isSet(HWCap, hwcap_ASIMDHP) + ARM64.HasCPUID = isSet(HWCap, hwcap_CPUID) + ARM64.HasASIMDRDM = isSet(HWCap, hwcap_ASIMDRDM) + ARM64.HasJSCVT = isSet(HWCap, hwcap_JSCVT) + ARM64.HasFCMA = isSet(HWCap, hwcap_FCMA) + ARM64.HasLRCPC = isSet(HWCap, hwcap_LRCPC) + ARM64.HasDCPOP = isSet(HWCap, hwcap_DCPOP) + ARM64.HasSHA3 = isSet(HWCap, hwcap_SHA3) + ARM64.HasSM3 = isSet(HWCap, hwcap_SM3) + ARM64.HasSM4 = isSet(HWCap, hwcap_SM4) + ARM64.HasASIMDDP = isSet(HWCap, hwcap_ASIMDDP) + ARM64.HasSHA512 = isSet(HWCap, hwcap_SHA512) + ARM64.HasSVE = isSet(HWCap, hwcap_SVE) + ARM64.HasASIMDFHM = isSet(HWCap, hwcap_ASIMDFHM) +} + +func isSet(hwc uint, value uint) bool { + return hwc&value != 0 +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/cpu/cpu_gc_x86.go b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/cpu/cpu_gc_x86.go new file mode 100644 index 0000000000..f7cb46971c --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/cpu/cpu_gc_x86.go @@ -0,0 +1,16 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build 386 amd64 amd64p32 +// +build !gccgo + +package cpu + +// cpuid is implemented in cpu_x86.s for gc compiler +// and in cpu_gccgo.c for gccgo. +func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32) + +// xgetbv with ecx = 0 is implemented in cpu_x86.s for gc compiler +// and in cpu_gccgo.c for gccgo. +func xgetbv() (eax, edx uint32) diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/cpu/cpu_gccgo.c b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/cpu/cpu_gccgo.c new file mode 100644 index 0000000000..e363c7d131 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/cpu/cpu_gccgo.c @@ -0,0 +1,43 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build 386 amd64 amd64p32 +// +build gccgo + +#include +#include + +// Need to wrap __get_cpuid_count because it's declared as static. +int +gccgoGetCpuidCount(uint32_t leaf, uint32_t subleaf, + uint32_t *eax, uint32_t *ebx, + uint32_t *ecx, uint32_t *edx) +{ + return __get_cpuid_count(leaf, subleaf, eax, ebx, ecx, edx); +} + +// xgetbv reads the contents of an XCR (Extended Control Register) +// specified in the ECX register into registers EDX:EAX. +// Currently, the only supported value for XCR is 0. +// +// TODO: Replace with a better alternative: +// +// #include +// +// #pragma GCC target("xsave") +// +// void gccgoXgetbv(uint32_t *eax, uint32_t *edx) { +// unsigned long long x = _xgetbv(0); +// *eax = x & 0xffffffff; +// *edx = (x >> 32) & 0xffffffff; +// } +// +// Note that _xgetbv is defined starting with GCC 8. +void +gccgoXgetbv(uint32_t *eax, uint32_t *edx) +{ + __asm(" xorl %%ecx, %%ecx\n" + " xgetbv" + : "=a"(*eax), "=d"(*edx)); +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/cpu/cpu_gccgo.go b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/cpu/cpu_gccgo.go new file mode 100644 index 0000000000..ba49b91bd3 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/cpu/cpu_gccgo.go @@ -0,0 +1,26 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build 386 amd64 amd64p32 +// +build gccgo + +package cpu + +//extern gccgoGetCpuidCount +func gccgoGetCpuidCount(eaxArg, ecxArg uint32, eax, ebx, ecx, edx *uint32) + +func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32) { + var a, b, c, d uint32 + gccgoGetCpuidCount(eaxArg, ecxArg, &a, &b, &c, &d) + return a, b, c, d +} + +//extern gccgoXgetbv +func gccgoXgetbv(eax, edx *uint32) + +func xgetbv() (eax, edx uint32) { + var a, d uint32 + gccgoXgetbv(&a, &d) + return a, d +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/cpu/cpu_linux.go b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/cpu/cpu_linux.go new file mode 100644 index 0000000000..a8452e094b --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/cpu/cpu_linux.go @@ -0,0 +1,61 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//+build !amd64,!amd64p32,!386 + +package cpu + +import ( + "encoding/binary" + "io/ioutil" + "runtime" +) + +const ( + _AT_HWCAP = 16 + _AT_HWCAP2 = 26 + + procAuxv = "/proc/self/auxv" + + uintSize uint = 32 << (^uint(0) >> 63) +) + +// For those platforms don't have a 'cpuid' equivalent we use HWCAP/HWCAP2 +// These are initialized in cpu_$GOARCH.go +// and should not be changed after they are initialized. +var HWCap uint +var HWCap2 uint + +func init() { + buf, err := ioutil.ReadFile(procAuxv) + if err != nil { + panic("read proc auxv failed: " + err.Error()) + } + + pb := int(uintSize / 8) + + for i := 0; i < len(buf)-pb*2; i += pb * 2 { + var tag, val uint + switch uintSize { + case 32: + tag = uint(binary.LittleEndian.Uint32(buf[i:])) + val = uint(binary.LittleEndian.Uint32(buf[i+pb:])) + case 64: + if runtime.GOARCH == "ppc64" { + tag = uint(binary.BigEndian.Uint64(buf[i:])) + val = uint(binary.BigEndian.Uint64(buf[i+pb:])) + } else { + tag = uint(binary.LittleEndian.Uint64(buf[i:])) + val = uint(binary.LittleEndian.Uint64(buf[i+pb:])) + } + } + switch tag { + case _AT_HWCAP: + HWCap = val + case _AT_HWCAP2: + HWCap2 = val + } + } + doinit() +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/cpu/cpu_mips64x.go b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/cpu/cpu_mips64x.go new file mode 100644 index 0000000000..f55e0c82c7 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/cpu/cpu_mips64x.go @@ -0,0 +1,11 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build mips64 mips64le + +package cpu + +const cacheLineSize = 32 + +func doinit() {} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/cpu/cpu_mipsx.go b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/cpu/cpu_mipsx.go new file mode 100644 index 0000000000..cda87b1a1b --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/cpu/cpu_mipsx.go @@ -0,0 +1,11 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build mips mipsle + +package cpu + +const cacheLineSize = 32 + +func doinit() {} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/cpu/cpu_ppc64x.go b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/cpu/cpu_ppc64x.go new file mode 100644 index 0000000000..ed975de621 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/cpu/cpu_ppc64x.go @@ -0,0 +1,32 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build ppc64 ppc64le + +package cpu + +const cacheLineSize = 128 + +// HWCAP/HWCAP2 bits. These are exposed by the kernel. +const ( + // ISA Level + _PPC_FEATURE2_ARCH_2_07 = 0x80000000 + _PPC_FEATURE2_ARCH_3_00 = 0x00800000 + + // CPU features + _PPC_FEATURE2_DARN = 0x00200000 + _PPC_FEATURE2_SCV = 0x00100000 +) + +func doinit() { + // HWCAP2 feature bits + PPC64.IsPOWER8 = isSet(HWCap2, _PPC_FEATURE2_ARCH_2_07) + PPC64.IsPOWER9 = isSet(HWCap2, _PPC_FEATURE2_ARCH_3_00) + PPC64.HasDARN = isSet(HWCap2, _PPC_FEATURE2_DARN) + PPC64.HasSCV = isSet(HWCap2, _PPC_FEATURE2_SCV) +} + +func isSet(hwc uint, value uint) bool { + return hwc&value != 0 +} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/cpu/cpu_s390x.go b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/cpu/cpu_s390x.go new file mode 100644 index 0000000000..ce8a2289e0 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/cpu/cpu_s390x.go @@ -0,0 +1,9 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cpu + +const cacheLineSize = 256 + +func doinit() {} diff --git a/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/cpu/cpu_x86.go b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/cpu/cpu_x86.go new file mode 100644 index 0000000000..71e288b062 --- /dev/null +++ b/vendor/github.com/Microsoft/hcsshim/vendor/golang.org/x/sys/cpu/cpu_x86.go @@ -0,0 +1,55 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build 386 amd64 amd64p32 + +package cpu + +const cacheLineSize = 64 + +func init() { + maxID, _, _, _ := cpuid(0, 0) + + if maxID < 1 { + return + } + + _, _, ecx1, edx1 := cpuid(1, 0) + X86.HasSSE2 = isSet(26, edx1) + + X86.HasSSE3 = isSet(0, ecx1) + X86.HasPCLMULQDQ = isSet(1, ecx1) + X86.HasSSSE3 = isSet(9, ecx1) + X86.HasFMA = isSet(12, ecx1) + X86.HasSSE41 = isSet(19, ecx1) + X86.HasSSE42 = isSet(20, ecx1) + X86.HasPOPCNT = isSet(23, ecx1) + X86.HasAES = isSet(25, ecx1) + X86.HasOSXSAVE = isSet(27, ecx1) + + osSupportsAVX := false + // For XGETBV, OSXSAVE bit is required and sufficient. + if X86.HasOSXSAVE { + eax, _ := xgetbv() + // Check if XMM and YMM registers have OS support. + osSupportsAVX = isSet(1, eax) && isSet(2, eax) + } + + X86.HasAVX = isSet(28, ecx1) && osSupportsAVX + + if maxID < 7 { + return + } + + _, ebx7, _, _ := cpuid(7, 0) + X86.HasBMI1 = isSet(3, ebx7) + X86.HasAVX2 = isSet(5, ebx7) && osSupportsAVX + X86.HasBMI2 = isSet(8, ebx7) + X86.HasERMS = isSet(9, ebx7) + X86.HasADX = isSet(19, ebx7) +} + +func isSet(bitpos uint, value uint32) bool { + return value&(1<