WIP: testing from my fork
full diff: https://github.com/moby/buildkit/compare/v0.12.0...619a20df406b Signed-off-by: Sebastiaan van Stijn <github@gone.nl>pull/1949/head
parent
2717d897ee
commit
dbda0d0fe5
@ -1,201 +0,0 @@
|
|||||||
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.
|
|
@ -1,207 +0,0 @@
|
|||||||
package testing
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
fuzz "github.com/AdaLogics/go-fuzz-headers"
|
|
||||||
"os"
|
|
||||||
"reflect"
|
|
||||||
)
|
|
||||||
|
|
||||||
type F struct {
|
|
||||||
Data []byte
|
|
||||||
T *T
|
|
||||||
FuzzFunc func(*T, any)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *F) CleanupTempDirs() {
|
|
||||||
f.T.CleanupTempDirs()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *F) Add(args ...any) {}
|
|
||||||
func (c *F) Cleanup(f func()) {}
|
|
||||||
func (c *F) Error(args ...any) {}
|
|
||||||
func (c *F) Errorf(format string, args ...any) {}
|
|
||||||
func (f *F) Fail() {}
|
|
||||||
func (c *F) FailNow() {}
|
|
||||||
func (c *F) Failed() bool { return false }
|
|
||||||
func (c *F) Fatal(args ...any) {}
|
|
||||||
func (c *F) Fatalf(format string, args ...any) {}
|
|
||||||
func (f *F) Fuzz(ff any) {
|
|
||||||
// we are assuming that ff is a func.
|
|
||||||
// TODO: Add a check for UX purposes
|
|
||||||
|
|
||||||
fn := reflect.ValueOf(ff)
|
|
||||||
fnType := fn.Type()
|
|
||||||
var types []reflect.Type
|
|
||||||
for i := 1; i < fnType.NumIn(); i++ {
|
|
||||||
t := fnType.In(i)
|
|
||||||
|
|
||||||
types = append(types, t)
|
|
||||||
}
|
|
||||||
args := []reflect.Value{reflect.ValueOf(f.T)}
|
|
||||||
fuzzConsumer := fuzz.NewConsumer(f.Data)
|
|
||||||
for _, v := range types {
|
|
||||||
switch v.String() {
|
|
||||||
case "[]uint8":
|
|
||||||
b, err := fuzzConsumer.GetBytes()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
newBytes := reflect.New(v)
|
|
||||||
newBytes.Elem().SetBytes(b)
|
|
||||||
args = append(args, newBytes.Elem())
|
|
||||||
case "string":
|
|
||||||
s, err := fuzzConsumer.GetString()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
newString := reflect.New(v)
|
|
||||||
newString.Elem().SetString(s)
|
|
||||||
args = append(args, newString.Elem())
|
|
||||||
case "int":
|
|
||||||
randInt, err := fuzzConsumer.GetInt()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
newInt := reflect.New(v)
|
|
||||||
newInt.Elem().SetInt(int64(randInt))
|
|
||||||
args = append(args, newInt.Elem())
|
|
||||||
case "int8":
|
|
||||||
randInt, err := fuzzConsumer.GetInt()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
newInt := reflect.New(v)
|
|
||||||
newInt.Elem().SetInt(int64(randInt))
|
|
||||||
args = append(args, newInt.Elem())
|
|
||||||
case "int16":
|
|
||||||
randInt, err := fuzzConsumer.GetInt()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
newInt := reflect.New(v)
|
|
||||||
newInt.Elem().SetInt(int64(randInt))
|
|
||||||
args = append(args, newInt.Elem())
|
|
||||||
case "int32":
|
|
||||||
randInt, err := fuzzConsumer.GetInt()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
newInt := reflect.New(v)
|
|
||||||
newInt.Elem().SetInt(int64(randInt))
|
|
||||||
args = append(args, newInt.Elem())
|
|
||||||
case "int64":
|
|
||||||
randInt, err := fuzzConsumer.GetInt()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
newInt := reflect.New(v)
|
|
||||||
newInt.Elem().SetInt(int64(randInt))
|
|
||||||
args = append(args, newInt.Elem())
|
|
||||||
case "uint":
|
|
||||||
randInt, err := fuzzConsumer.GetInt()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
newUint := reflect.New(v)
|
|
||||||
newUint.Elem().SetUint(uint64(randInt))
|
|
||||||
args = append(args, newUint.Elem())
|
|
||||||
case "uint8":
|
|
||||||
randInt, err := fuzzConsumer.GetInt()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
newUint := reflect.New(v)
|
|
||||||
newUint.Elem().SetUint(uint64(randInt))
|
|
||||||
args = append(args, newUint.Elem())
|
|
||||||
case "uint16":
|
|
||||||
randInt, err := fuzzConsumer.GetUint16()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
newUint16 := reflect.New(v)
|
|
||||||
newUint16.Elem().SetUint(uint64(randInt))
|
|
||||||
args = append(args, newUint16.Elem())
|
|
||||||
case "uint32":
|
|
||||||
randInt, err := fuzzConsumer.GetUint32()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
newUint32 := reflect.New(v)
|
|
||||||
newUint32.Elem().SetUint(uint64(randInt))
|
|
||||||
args = append(args, newUint32.Elem())
|
|
||||||
case "uint64":
|
|
||||||
randInt, err := fuzzConsumer.GetUint64()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
newUint64 := reflect.New(v)
|
|
||||||
newUint64.Elem().SetUint(uint64(randInt))
|
|
||||||
args = append(args, newUint64.Elem())
|
|
||||||
case "rune":
|
|
||||||
randRune, err := fuzzConsumer.GetRune()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
newRune := reflect.New(v)
|
|
||||||
newRune.Elem().Set(reflect.ValueOf(randRune))
|
|
||||||
args = append(args, newRune.Elem())
|
|
||||||
case "float32":
|
|
||||||
randFloat, err := fuzzConsumer.GetFloat32()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
newFloat := reflect.New(v)
|
|
||||||
newFloat.Elem().Set(reflect.ValueOf(randFloat))
|
|
||||||
args = append(args, newFloat.Elem())
|
|
||||||
case "float64":
|
|
||||||
randFloat, err := fuzzConsumer.GetFloat64()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
newFloat := reflect.New(v)
|
|
||||||
newFloat.Elem().Set(reflect.ValueOf(randFloat))
|
|
||||||
args = append(args, newFloat.Elem())
|
|
||||||
case "bool":
|
|
||||||
randBool, err := fuzzConsumer.GetBool()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
newBool := reflect.New(v)
|
|
||||||
newBool.Elem().Set(reflect.ValueOf(randBool))
|
|
||||||
args = append(args, newBool.Elem())
|
|
||||||
default:
|
|
||||||
fmt.Println(v.String())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn.Call(args)
|
|
||||||
}
|
|
||||||
func (f *F) Helper() {}
|
|
||||||
func (c *F) Log(args ...any) {
|
|
||||||
fmt.Println(args...)
|
|
||||||
}
|
|
||||||
func (c *F) Logf(format string, args ...any) {
|
|
||||||
fmt.Println(format, args)
|
|
||||||
}
|
|
||||||
func (c *F) Name() string { return "libFuzzer" }
|
|
||||||
func (c *F) Setenv(key, value string) {}
|
|
||||||
func (c *F) Skip(args ...any) {
|
|
||||||
panic("GO-FUZZ-BUILD-PANIC")
|
|
||||||
}
|
|
||||||
func (c *F) SkipNow() {
|
|
||||||
panic("GO-FUZZ-BUILD-PANIC")
|
|
||||||
}
|
|
||||||
func (c *F) Skipf(format string, args ...any) {
|
|
||||||
panic("GO-FUZZ-BUILD-PANIC")
|
|
||||||
}
|
|
||||||
func (f *F) Skipped() bool { return false }
|
|
||||||
|
|
||||||
func (f *F) TempDir() string {
|
|
||||||
dir, err := os.MkdirTemp("", "fuzzdir-")
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
f.T.TempDirs = append(f.T.TempDirs, dir)
|
|
||||||
|
|
||||||
return dir
|
|
||||||
}
|
|
@ -1,129 +0,0 @@
|
|||||||
package testing
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// T can be used to terminate the current fuzz iteration
|
|
||||||
// without terminating the whole fuzz run. To do so, simply
|
|
||||||
// panic with the text "GO-FUZZ-BUILD-PANIC" and the fuzzer
|
|
||||||
// will recover.
|
|
||||||
type T struct {
|
|
||||||
TempDirs []string
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewT() *T {
|
|
||||||
tempDirs := make([]string, 0)
|
|
||||||
return &T{TempDirs: tempDirs}
|
|
||||||
}
|
|
||||||
|
|
||||||
func unsupportedApi(name string) string {
|
|
||||||
plsOpenIss := "Please open an issue https://github.com/AdamKorcz/go-118-fuzz-build if you need this feature."
|
|
||||||
var b strings.Builder
|
|
||||||
b.WriteString(fmt.Sprintf("%s is not supported when fuzzing in libFuzzer mode\n.", name))
|
|
||||||
b.WriteString(plsOpenIss)
|
|
||||||
return b.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *T) Cleanup(f func()) {
|
|
||||||
f()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *T) Deadline() (deadline time.Time, ok bool) {
|
|
||||||
panic(unsupportedApi("t.Deadline()"))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *T) Error(args ...any) {
|
|
||||||
fmt.Println(args...)
|
|
||||||
panic("error")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *T) Errorf(format string, args ...any) {
|
|
||||||
fmt.Printf(format+"\n", args...)
|
|
||||||
panic("errorf")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *T) Fail() {
|
|
||||||
panic("Called T.Fail()")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *T) FailNow() {
|
|
||||||
panic("Called T.Fail()")
|
|
||||||
panic(unsupportedApi("t.FailNow()"))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *T) Failed() bool {
|
|
||||||
panic(unsupportedApi("t.Failed()"))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *T) Fatal(args ...any) {
|
|
||||||
fmt.Println(args...)
|
|
||||||
panic("fatal")
|
|
||||||
}
|
|
||||||
func (t *T) Fatalf(format string, args ...any) {
|
|
||||||
fmt.Printf(format+"\n", args...)
|
|
||||||
panic("fatal")
|
|
||||||
}
|
|
||||||
func (t *T) Helper() {
|
|
||||||
// We can't support it, but it also just impacts how failures are reported, so we can ignore it
|
|
||||||
}
|
|
||||||
func (t *T) Log(args ...any) {
|
|
||||||
fmt.Println(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *T) Logf(format string, args ...any) {
|
|
||||||
fmt.Println(format)
|
|
||||||
fmt.Println(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *T) Name() string {
|
|
||||||
return "libFuzzer"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *T) Parallel() {
|
|
||||||
panic(unsupportedApi("t.Parallel()"))
|
|
||||||
}
|
|
||||||
func (t *T) Run(name string, f func(t *T)) bool {
|
|
||||||
panic(unsupportedApi("t.Run()"))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *T) Setenv(key, value string) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *T) Skip(args ...any) {
|
|
||||||
panic("GO-FUZZ-BUILD-PANIC")
|
|
||||||
}
|
|
||||||
func (t *T) SkipNow() {
|
|
||||||
panic("GO-FUZZ-BUILD-PANIC")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Is not really supported. We just skip instead
|
|
||||||
// of printing any message. A log message can be
|
|
||||||
// added if need be.
|
|
||||||
func (t *T) Skipf(format string, args ...any) {
|
|
||||||
panic("GO-FUZZ-BUILD-PANIC")
|
|
||||||
}
|
|
||||||
func (t *T) Skipped() bool {
|
|
||||||
panic(unsupportedApi("t.Skipped()"))
|
|
||||||
}
|
|
||||||
func (t *T) TempDir() string {
|
|
||||||
dir, err := os.MkdirTemp("", "fuzzdir-")
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
t.TempDirs = append(t.TempDirs, dir)
|
|
||||||
|
|
||||||
return dir
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *T) CleanupTempDirs() {
|
|
||||||
if len(t.TempDirs) > 0 {
|
|
||||||
for _, tempDir := range t.TempDirs {
|
|
||||||
os.RemoveAll(tempDir)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,42 +0,0 @@
|
|||||||
package testing
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func AllocsPerRun(runs int, f func()) (avg float64) {
|
|
||||||
panic(unsupportedApi("testing.AllocsPerRun"))
|
|
||||||
}
|
|
||||||
func CoverMode() string {
|
|
||||||
panic(unsupportedApi("testing.CoverMode"))
|
|
||||||
}
|
|
||||||
func Coverage() float64 {
|
|
||||||
panic(unsupportedApi("testing.Coverage"))
|
|
||||||
}
|
|
||||||
func Init() {
|
|
||||||
panic(unsupportedApi("testing.Init"))
|
|
||||||
|
|
||||||
}
|
|
||||||
func RegisterCover(c testing.Cover) {
|
|
||||||
panic(unsupportedApi("testing.RegisterCover"))
|
|
||||||
}
|
|
||||||
func RunExamples(matchString func(pat, str string) (bool, error), examples []testing.InternalExample) (ok bool) {
|
|
||||||
panic(unsupportedApi("testing.RunExamples"))
|
|
||||||
}
|
|
||||||
|
|
||||||
func RunTests(matchString func(pat, str string) (bool, error), tests []testing.InternalTest) (ok bool) {
|
|
||||||
panic(unsupportedApi("testing.RunTests"))
|
|
||||||
}
|
|
||||||
|
|
||||||
func Short() bool {
|
|
||||||
panic(unsupportedApi("testing.Short"))
|
|
||||||
}
|
|
||||||
|
|
||||||
func Verbose() bool {
|
|
||||||
panic(unsupportedApi("testing.Verbose"))
|
|
||||||
}
|
|
||||||
|
|
||||||
type M struct {}
|
|
||||||
func (m *M) Run() (code int) {
|
|
||||||
panic("testing.M is not support in libFuzzer Mode")
|
|
||||||
}
|
|
@ -1,3 +0,0 @@
|
|||||||
// This file only exists to allow go get on non-Windows platforms.
|
|
||||||
|
|
||||||
package backuptar
|
|
@ -1,70 +0,0 @@
|
|||||||
//go:build windows
|
|
||||||
|
|
||||||
package backuptar
|
|
||||||
|
|
||||||
import (
|
|
||||||
"archive/tar"
|
|
||||||
"fmt"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Functions copied from https://github.com/golang/go/blob/master/src/archive/tar/strconv.go
|
|
||||||
// as we need to manage the LIBARCHIVE.creationtime PAXRecord manually.
|
|
||||||
// Idea taken from containerd which did the same thing.
|
|
||||||
|
|
||||||
// parsePAXTime takes a string of the form %d.%d as described in the PAX
|
|
||||||
// specification. Note that this implementation allows for negative timestamps,
|
|
||||||
// which is allowed for by the PAX specification, but not always portable.
|
|
||||||
func parsePAXTime(s string) (time.Time, error) {
|
|
||||||
const maxNanoSecondDigits = 9
|
|
||||||
|
|
||||||
// Split string into seconds and sub-seconds parts.
|
|
||||||
ss, sn := s, ""
|
|
||||||
if pos := strings.IndexByte(s, '.'); pos >= 0 {
|
|
||||||
ss, sn = s[:pos], s[pos+1:]
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse the seconds.
|
|
||||||
secs, err := strconv.ParseInt(ss, 10, 64)
|
|
||||||
if err != nil {
|
|
||||||
return time.Time{}, tar.ErrHeader
|
|
||||||
}
|
|
||||||
if len(sn) == 0 {
|
|
||||||
return time.Unix(secs, 0), nil // No sub-second values
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse the nanoseconds.
|
|
||||||
if strings.Trim(sn, "0123456789") != "" {
|
|
||||||
return time.Time{}, tar.ErrHeader
|
|
||||||
}
|
|
||||||
if len(sn) < maxNanoSecondDigits {
|
|
||||||
sn += strings.Repeat("0", maxNanoSecondDigits-len(sn)) // Right pad
|
|
||||||
} else {
|
|
||||||
sn = sn[:maxNanoSecondDigits] // Right truncate
|
|
||||||
}
|
|
||||||
nsecs, _ := strconv.ParseInt(sn, 10, 64) // Must succeed
|
|
||||||
if len(ss) > 0 && ss[0] == '-' {
|
|
||||||
return time.Unix(secs, -1*nsecs), nil // Negative correction
|
|
||||||
}
|
|
||||||
return time.Unix(secs, nsecs), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// formatPAXTime converts ts into a time of the form %d.%d as described in the
|
|
||||||
// PAX specification. This function is capable of negative timestamps.
|
|
||||||
func formatPAXTime(ts time.Time) (s string) {
|
|
||||||
secs, nsecs := ts.Unix(), ts.Nanosecond()
|
|
||||||
if nsecs == 0 {
|
|
||||||
return strconv.FormatInt(secs, 10)
|
|
||||||
}
|
|
||||||
|
|
||||||
// If seconds is negative, then perform correction.
|
|
||||||
sign := ""
|
|
||||||
if secs < 0 {
|
|
||||||
sign = "-" // Remember sign
|
|
||||||
secs = -(secs + 1) // Add a second to secs
|
|
||||||
nsecs = -(nsecs - 1e9) // Take that second away from nsecs
|
|
||||||
}
|
|
||||||
return strings.TrimRight(fmt.Sprintf("%s%d.%09d", sign, secs, nsecs), "0")
|
|
||||||
}
|
|
@ -1,509 +0,0 @@
|
|||||||
//go:build windows
|
|
||||||
// +build windows
|
|
||||||
|
|
||||||
package backuptar
|
|
||||||
|
|
||||||
import (
|
|
||||||
"archive/tar"
|
|
||||||
"encoding/base64"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"path/filepath"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"syscall"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/Microsoft/go-winio"
|
|
||||||
"golang.org/x/sys/windows"
|
|
||||||
)
|
|
||||||
|
|
||||||
//nolint:deadcode,varcheck // keep unused constants for potential future use
|
|
||||||
const (
|
|
||||||
cISUID = 0004000 // Set uid
|
|
||||||
cISGID = 0002000 // Set gid
|
|
||||||
cISVTX = 0001000 // Save text (sticky bit)
|
|
||||||
cISDIR = 0040000 // Directory
|
|
||||||
cISFIFO = 0010000 // FIFO
|
|
||||||
cISREG = 0100000 // Regular file
|
|
||||||
cISLNK = 0120000 // Symbolic link
|
|
||||||
cISBLK = 0060000 // Block special file
|
|
||||||
cISCHR = 0020000 // Character special file
|
|
||||||
cISSOCK = 0140000 // Socket
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
hdrFileAttributes = "MSWINDOWS.fileattr"
|
|
||||||
hdrSecurityDescriptor = "MSWINDOWS.sd"
|
|
||||||
hdrRawSecurityDescriptor = "MSWINDOWS.rawsd"
|
|
||||||
hdrMountPoint = "MSWINDOWS.mountpoint"
|
|
||||||
hdrEaPrefix = "MSWINDOWS.xattr."
|
|
||||||
|
|
||||||
hdrCreationTime = "LIBARCHIVE.creationtime"
|
|
||||||
)
|
|
||||||
|
|
||||||
// zeroReader is an io.Reader that always returns 0s.
|
|
||||||
type zeroReader struct{}
|
|
||||||
|
|
||||||
func (zeroReader) Read(b []byte) (int, error) {
|
|
||||||
for i := range b {
|
|
||||||
b[i] = 0
|
|
||||||
}
|
|
||||||
return len(b), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func copySparse(t *tar.Writer, br *winio.BackupStreamReader) error {
|
|
||||||
curOffset := int64(0)
|
|
||||||
for {
|
|
||||||
bhdr, err := br.Next()
|
|
||||||
if err == io.EOF { //nolint:errorlint
|
|
||||||
err = io.ErrUnexpectedEOF
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if bhdr.Id != winio.BackupSparseBlock {
|
|
||||||
return fmt.Errorf("unexpected stream %d", bhdr.Id)
|
|
||||||
}
|
|
||||||
|
|
||||||
// We can't seek backwards, since we have already written that data to the tar.Writer.
|
|
||||||
if bhdr.Offset < curOffset {
|
|
||||||
return fmt.Errorf("cannot seek back from %d to %d", curOffset, bhdr.Offset)
|
|
||||||
}
|
|
||||||
// archive/tar does not support writing sparse files
|
|
||||||
// so just write zeroes to catch up to the current offset.
|
|
||||||
if _, err = io.CopyN(t, zeroReader{}, bhdr.Offset-curOffset); err != nil {
|
|
||||||
return fmt.Errorf("seek to offset %d: %w", bhdr.Offset, err)
|
|
||||||
}
|
|
||||||
if bhdr.Size == 0 {
|
|
||||||
// A sparse block with size = 0 is used to mark the end of the sparse blocks.
|
|
||||||
break
|
|
||||||
}
|
|
||||||
n, err := io.Copy(t, br)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if n != bhdr.Size {
|
|
||||||
return fmt.Errorf("copied %d bytes instead of %d at offset %d", n, bhdr.Size, bhdr.Offset)
|
|
||||||
}
|
|
||||||
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{
|
|
||||||
Format: tar.FormatPAX,
|
|
||||||
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()),
|
|
||||||
PAXRecords: make(map[string]string),
|
|
||||||
}
|
|
||||||
hdr.PAXRecords[hdrFileAttributes] = fmt.Sprintf("%d", fileInfo.FileAttributes)
|
|
||||||
hdr.PAXRecords[hdrCreationTime] = formatPAXTime(time.Unix(0, fileInfo.CreationTime.Nanoseconds()))
|
|
||||||
|
|
||||||
if (fileInfo.FileAttributes & syscall.FILE_ATTRIBUTE_DIRECTORY) != 0 {
|
|
||||||
hdr.Mode |= cISDIR
|
|
||||||
hdr.Size = 0
|
|
||||||
hdr.Typeflag = tar.TypeDir
|
|
||||||
}
|
|
||||||
return hdr
|
|
||||||
}
|
|
||||||
|
|
||||||
// SecurityDescriptorFromTarHeader reads the SDDL associated with the header of the current file
|
|
||||||
// from the tar header and returns the security descriptor into a byte slice.
|
|
||||||
func SecurityDescriptorFromTarHeader(hdr *tar.Header) ([]byte, error) {
|
|
||||||
if sdraw, ok := hdr.PAXRecords[hdrRawSecurityDescriptor]; ok {
|
|
||||||
sd, err := base64.StdEncoding.DecodeString(sdraw)
|
|
||||||
if err != nil {
|
|
||||||
// Not returning sd as-is in the error-case, as base64.DecodeString
|
|
||||||
// may return partially decoded data (not nil or empty slice) in case
|
|
||||||
// of a failure: https://github.com/golang/go/blob/go1.17.7/src/encoding/base64/base64.go#L382-L387
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return sd, nil
|
|
||||||
}
|
|
||||||
// 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.PAXRecords[hdrSecurityDescriptor]; ok {
|
|
||||||
return winio.SddlToSecurityDescriptor(sddl)
|
|
||||||
}
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExtendedAttributesFromTarHeader reads the EAs associated with the header of the
|
|
||||||
// current file from the tar header and returns it as a byte slice.
|
|
||||||
func ExtendedAttributesFromTarHeader(hdr *tar.Header) ([]byte, error) {
|
|
||||||
var eas []winio.ExtendedAttribute //nolint:prealloc // len(eas) <= len(hdr.PAXRecords); prealloc is wasteful
|
|
||||||
for k, v := range hdr.PAXRecords {
|
|
||||||
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,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
var eaData []byte
|
|
||||||
var err error
|
|
||||||
if len(eas) != 0 {
|
|
||||||
eaData, err = winio.EncodeExtendedAttributes(eas)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return eaData, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// EncodeReparsePointFromTarHeader reads the ReparsePoint structure from the tar header
|
|
||||||
// and encodes it into a byte slice. The file for which this function is called must be a
|
|
||||||
// symlink.
|
|
||||||
func EncodeReparsePointFromTarHeader(hdr *tar.Header) []byte {
|
|
||||||
_, isMountPoint := hdr.PAXRecords[hdrMountPoint]
|
|
||||||
rp := winio.ReparsePoint{
|
|
||||||
Target: filepath.FromSlash(hdr.Linkname),
|
|
||||||
IsMountPoint: isMountPoint,
|
|
||||||
}
|
|
||||||
return winio.EncodeReparsePoint(&rp)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 { //nolint:errorlint
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
switch bhdr.Id {
|
|
||||||
case winio.BackupData:
|
|
||||||
hdr.Mode |= cISREG
|
|
||||||
if !readTwice {
|
|
||||||
dataHdr = bhdr
|
|
||||||
}
|
|
||||||
case winio.BackupSecurity:
|
|
||||||
sd, err := io.ReadAll(br)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
hdr.PAXRecords[hdrRawSecurityDescriptor] = base64.StdEncoding.EncodeToString(sd)
|
|
||||||
|
|
||||||
case winio.BackupReparseData:
|
|
||||||
hdr.Mode |= cISLNK
|
|
||||||
hdr.Typeflag = tar.TypeSymlink
|
|
||||||
reparseBuffer, _ := io.ReadAll(br)
|
|
||||||
rp, err := winio.DecodeReparsePoint(reparseBuffer)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if rp.IsMountPoint {
|
|
||||||
hdr.PAXRecords[hdrMountPoint] = "1"
|
|
||||||
}
|
|
||||||
hdr.Linkname = rp.Target
|
|
||||||
|
|
||||||
case winio.BackupEaData:
|
|
||||||
eab, err := io.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.PAXRecords[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 { //nolint:errorlint
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if bhdr.Id == winio.BackupData {
|
|
||||||
dataHdr = bhdr
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The logic for copying file contents is fairly complicated due to the need for handling sparse files,
|
|
||||||
// and the weird ways they are represented by BackupRead. A normal file will always either have a data stream
|
|
||||||
// with size and content, or no data stream at all (if empty). However, for a sparse file, the content can also
|
|
||||||
// be represented using a series of sparse block streams following the data stream. Additionally, the way sparse
|
|
||||||
// files are handled by BackupRead has changed in the OS recently. The specifics of the representation are described
|
|
||||||
// in the list at the bottom of this block comment.
|
|
||||||
//
|
|
||||||
// Sparse files can be represented in four different ways, based on the specifics of the file.
|
|
||||||
// - Size = 0:
|
|
||||||
// Previously: BackupRead yields no data stream and no sparse block streams.
|
|
||||||
// Recently: BackupRead yields a data stream with size = 0. There are no following sparse block streams.
|
|
||||||
// - Size > 0, no allocated ranges:
|
|
||||||
// BackupRead yields a data stream with size = 0. Following is a single sparse block stream with
|
|
||||||
// size = 0 and offset = <file size>.
|
|
||||||
// - Size > 0, one allocated range:
|
|
||||||
// BackupRead yields a data stream with size = <file size> containing the file contents. There are no
|
|
||||||
// sparse block streams. This is the case if you take a normal file with contents and simply set the
|
|
||||||
// sparse flag on it.
|
|
||||||
// - Size > 0, multiple allocated ranges:
|
|
||||||
// BackupRead yields a data stream with size = 0. Following are sparse block streams for each allocated
|
|
||||||
// range of the file containing the range contents. Finally there is a sparse block stream with
|
|
||||||
// size = 0 and offset = <file size>.
|
|
||||||
|
|
||||||
if dataHdr != nil { //nolint:nestif // todo: reduce nesting complexity
|
|
||||||
// A data stream was found. Copy the data.
|
|
||||||
// We assume that we will either have a data stream size > 0 XOR have sparse block streams.
|
|
||||||
if dataHdr.Size > 0 || (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)
|
|
||||||
}
|
|
||||||
if _, err = io.Copy(t, br); err != nil {
|
|
||||||
return fmt.Errorf("%s: copying contents from data stream: %w", name, err)
|
|
||||||
}
|
|
||||||
} else if size > 0 {
|
|
||||||
// As of a recent OS change, BackupRead now returns a data stream for empty sparse files.
|
|
||||||
// These files have no sparse block streams, so skip the copySparse call if file size = 0.
|
|
||||||
if err = copySparse(t, br); err != nil {
|
|
||||||
return fmt.Errorf("%s: copying contents from sparse block stream: %w", name, 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 { //nolint:errorlint
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
switch bhdr.Id {
|
|
||||||
case winio.BackupAlternateData:
|
|
||||||
if (bhdr.Attributes & winio.StreamSparseAttributes) != 0 {
|
|
||||||
// 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 fmt.Errorf("%s: tar of sparse alternate data streams is unsupported", name)
|
|
||||||
}
|
|
||||||
altName := strings.TrimSuffix(bhdr.Name, ":$DATA")
|
|
||||||
hdr = &tar.Header{
|
|
||||||
Format: hdr.Format,
|
|
||||||
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
|
|
||||||
}
|
|
||||||
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: windows.NsecToFiletime(hdr.AccessTime.UnixNano()),
|
|
||||||
LastWriteTime: windows.NsecToFiletime(hdr.ModTime.UnixNano()),
|
|
||||||
ChangeTime: windows.NsecToFiletime(hdr.ChangeTime.UnixNano()),
|
|
||||||
// Default to ModTime, we'll pull hdrCreationTime below if present
|
|
||||||
CreationTime: windows.NsecToFiletime(hdr.ModTime.UnixNano()),
|
|
||||||
}
|
|
||||||
if attrStr, ok := hdr.PAXRecords[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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if creationTimeStr, ok := hdr.PAXRecords[hdrCreationTime]; ok {
|
|
||||||
creationTime, err := parsePAXTime(creationTimeStr)
|
|
||||||
if err != nil {
|
|
||||||
return "", 0, nil, err
|
|
||||||
}
|
|
||||||
fileInfo.CreationTime = windows.NsecToFiletime(creationTime.UnixNano())
|
|
||||||
}
|
|
||||||
return name, size, fileInfo, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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)
|
|
||||||
|
|
||||||
sd, err := SecurityDescriptorFromTarHeader(hdr)
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
eadata, err := ExtendedAttributesFromTarHeader(hdr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if len(eadata) != 0 {
|
|
||||||
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 {
|
|
||||||
reparse := EncodeReparsePointFromTarHeader(hdr)
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,308 +0,0 @@
|
|||||||
//go:build windows
|
|
||||||
// +build windows
|
|
||||||
|
|
||||||
package bindfilter
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"encoding/binary"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
"syscall"
|
|
||||||
"unsafe"
|
|
||||||
|
|
||||||
"golang.org/x/sys/windows"
|
|
||||||
)
|
|
||||||
|
|
||||||
//go:generate go run github.com/Microsoft/go-winio/tools/mkwinsyscall -output zsyscall_windows.go ./bind_filter.go
|
|
||||||
//sys bfSetupFilter(jobHandle windows.Handle, flags uint32, virtRootPath string, virtTargetPath string, virtExceptions **uint16, virtExceptionPathCount uint32) (hr error) = bindfltapi.BfSetupFilter?
|
|
||||||
//sys bfRemoveMapping(jobHandle windows.Handle, virtRootPath string) (hr error) = bindfltapi.BfRemoveMapping?
|
|
||||||
//sys bfGetMappings(flags uint32, jobHandle windows.Handle, virtRootPath *uint16, sid *windows.SID, bufferSize *uint32, outBuffer *byte) (hr error) = bindfltapi.BfGetMappings?
|
|
||||||
|
|
||||||
// BfSetupFilter flags. See:
|
|
||||||
// https://github.com/microsoft/BuildXL/blob/a6dce509f0d4f774255e5fbfb75fa6d5290ed163/Public/Src/Utilities/Native/Processes/Windows/NativeContainerUtilities.cs#L193-L240
|
|
||||||
//
|
|
||||||
//nolint:revive // var-naming: ALL_CAPS
|
|
||||||
const (
|
|
||||||
BINDFLT_FLAG_READ_ONLY_MAPPING uint32 = 0x00000001
|
|
||||||
// Tells bindflt to fail mapping with STATUS_INVALID_PARAMETER if a mapping produces
|
|
||||||
// multiple targets.
|
|
||||||
BINDFLT_FLAG_NO_MULTIPLE_TARGETS uint32 = 0x00000040
|
|
||||||
)
|
|
||||||
|
|
||||||
//nolint:revive // var-naming: ALL_CAPS
|
|
||||||
const (
|
|
||||||
BINDFLT_GET_MAPPINGS_FLAG_VOLUME uint32 = 0x00000001
|
|
||||||
BINDFLT_GET_MAPPINGS_FLAG_SILO uint32 = 0x00000002
|
|
||||||
BINDFLT_GET_MAPPINGS_FLAG_USER uint32 = 0x00000004
|
|
||||||
)
|
|
||||||
|
|
||||||
// ApplyFileBinding creates a global mount of the source in root, with an optional
|
|
||||||
// read only flag.
|
|
||||||
// The bind filter allows us to create mounts of directories and volumes. By default it allows
|
|
||||||
// us to mount multiple sources inside a single root, acting as an overlay. Files from the
|
|
||||||
// second source will superscede the first source that was mounted.
|
|
||||||
// This function disables this behavior and sets the BINDFLT_FLAG_NO_MULTIPLE_TARGETS flag
|
|
||||||
// on the mount.
|
|
||||||
func ApplyFileBinding(root, source string, readOnly bool) error {
|
|
||||||
// The parent directory needs to exist for the bind to work. MkdirAll stats and
|
|
||||||
// returns nil if the directory exists internally so we should be fine to mkdirall
|
|
||||||
// every time.
|
|
||||||
if err := os.MkdirAll(filepath.Dir(root), 0); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.Contains(source, "Volume{") && !strings.HasSuffix(source, "\\") {
|
|
||||||
// Add trailing slash to volumes, otherwise we get an error when binding it to
|
|
||||||
// a folder.
|
|
||||||
source = source + "\\"
|
|
||||||
}
|
|
||||||
|
|
||||||
flags := BINDFLT_FLAG_NO_MULTIPLE_TARGETS
|
|
||||||
if readOnly {
|
|
||||||
flags |= BINDFLT_FLAG_READ_ONLY_MAPPING
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the job handle to 0 to create a global mount.
|
|
||||||
if err := bfSetupFilter(
|
|
||||||
0,
|
|
||||||
flags,
|
|
||||||
root,
|
|
||||||
source,
|
|
||||||
nil,
|
|
||||||
0,
|
|
||||||
); err != nil {
|
|
||||||
return fmt.Errorf("failed to bind target %q to root %q: %w", source, root, err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveFileBinding removes a mount from the root path.
|
|
||||||
func RemoveFileBinding(root string) error {
|
|
||||||
if err := bfRemoveMapping(0, root); err != nil {
|
|
||||||
return fmt.Errorf("removing file binding: %w", err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetBindMappings returns a list of bind mappings that have their root on a
|
|
||||||
// particular volume. The volumePath parameter can be any path that exists on
|
|
||||||
// a volume. For example, if a number of mappings are created in C:\ProgramData\test,
|
|
||||||
// to get a list of those mappings, the volumePath parameter would have to be set to
|
|
||||||
// C:\ or the VOLUME_NAME_GUID notation of C:\ (\\?\Volume{GUID}\), or any child
|
|
||||||
// path that exists.
|
|
||||||
func GetBindMappings(volumePath string) ([]BindMapping, error) {
|
|
||||||
rootPtr, err := windows.UTF16PtrFromString(volumePath)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
flags := BINDFLT_GET_MAPPINGS_FLAG_VOLUME
|
|
||||||
// allocate a large buffer for results
|
|
||||||
var outBuffSize uint32 = 256 * 1024
|
|
||||||
buf := make([]byte, outBuffSize)
|
|
||||||
|
|
||||||
if err := bfGetMappings(flags, 0, rootPtr, nil, &outBuffSize, &buf[0]); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if outBuffSize < 12 {
|
|
||||||
return nil, fmt.Errorf("invalid buffer returned")
|
|
||||||
}
|
|
||||||
|
|
||||||
result := buf[:outBuffSize]
|
|
||||||
|
|
||||||
// The first 12 bytes are the three uint32 fields in getMappingsResponseHeader{}
|
|
||||||
headerBuffer := result[:12]
|
|
||||||
// The alternative to using unsafe and casting it to the above defined structures, is to manually
|
|
||||||
// parse the fields. Not too terrible, but not sure it'd worth the trouble.
|
|
||||||
header := *(*getMappingsResponseHeader)(unsafe.Pointer(&headerBuffer[0]))
|
|
||||||
|
|
||||||
if header.MappingCount == 0 {
|
|
||||||
// no mappings
|
|
||||||
return []BindMapping{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
mappingsBuffer := result[12 : int(unsafe.Sizeof(mappingEntry{}))*int(header.MappingCount)]
|
|
||||||
// Get a pointer to the first mapping in the slice
|
|
||||||
mappingsPointer := (*mappingEntry)(unsafe.Pointer(&mappingsBuffer[0]))
|
|
||||||
// Get slice of mappings
|
|
||||||
mappings := unsafe.Slice(mappingsPointer, header.MappingCount)
|
|
||||||
|
|
||||||
mappingEntries := make([]BindMapping, header.MappingCount)
|
|
||||||
for i := 0; i < int(header.MappingCount); i++ {
|
|
||||||
bindMapping, err := getBindMappingFromBuffer(result, mappings[i])
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("fetching bind mappings: %w", err)
|
|
||||||
}
|
|
||||||
mappingEntries[i] = bindMapping
|
|
||||||
}
|
|
||||||
|
|
||||||
return mappingEntries, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// mappingEntry holds information about where in the response buffer we can
|
|
||||||
// find information about the virtual root (the mount point) and the targets (sources)
|
|
||||||
// that get mounted, as well as the flags used to bind the targets to the virtual root.
|
|
||||||
type mappingEntry struct {
|
|
||||||
VirtRootLength uint32
|
|
||||||
VirtRootOffset uint32
|
|
||||||
Flags uint32
|
|
||||||
NumberOfTargets uint32
|
|
||||||
TargetEntriesOffset uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
type mappingTargetEntry struct {
|
|
||||||
TargetRootLength uint32
|
|
||||||
TargetRootOffset uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
// getMappingsResponseHeader represents the first 12 bytes of the BfGetMappings() response.
|
|
||||||
// It gives us the size of the buffer, the status of the call and the number of mappings.
|
|
||||||
// A response
|
|
||||||
type getMappingsResponseHeader struct {
|
|
||||||
Size uint32
|
|
||||||
Status uint32
|
|
||||||
MappingCount uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
type BindMapping struct {
|
|
||||||
MountPoint string
|
|
||||||
Flags uint32
|
|
||||||
Targets []string
|
|
||||||
}
|
|
||||||
|
|
||||||
func decodeEntry(buffer []byte) (string, error) {
|
|
||||||
name := make([]uint16, len(buffer)/2)
|
|
||||||
err := binary.Read(bytes.NewReader(buffer), binary.LittleEndian, &name)
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("decoding name: %w", err)
|
|
||||||
}
|
|
||||||
return windows.UTF16ToString(name), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getTargetsFromBuffer(buffer []byte, offset, count int) ([]string, error) {
|
|
||||||
if len(buffer) < offset+count*6 {
|
|
||||||
return nil, fmt.Errorf("invalid buffer")
|
|
||||||
}
|
|
||||||
|
|
||||||
targets := make([]string, count)
|
|
||||||
for i := 0; i < count; i++ {
|
|
||||||
entryBuf := buffer[offset+i*8 : offset+i*8+8]
|
|
||||||
tgt := *(*mappingTargetEntry)(unsafe.Pointer(&entryBuf[0]))
|
|
||||||
if len(buffer) < int(tgt.TargetRootOffset)+int(tgt.TargetRootLength) {
|
|
||||||
return nil, fmt.Errorf("invalid buffer")
|
|
||||||
}
|
|
||||||
decoded, err := decodeEntry(buffer[tgt.TargetRootOffset : tgt.TargetRootOffset+tgt.TargetRootLength])
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("decoding name: %w", err)
|
|
||||||
}
|
|
||||||
decoded, err = getFinalPath(decoded)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("fetching final path: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
targets[i] = decoded
|
|
||||||
}
|
|
||||||
return targets, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getFinalPath(pth string) (string, error) {
|
|
||||||
// BfGetMappings returns VOLUME_NAME_NT paths like \Device\HarddiskVolume2\ProgramData.
|
|
||||||
// These can be accessed by prepending \\.\GLOBALROOT to the path. We use this to get the
|
|
||||||
// DOS paths for these files.
|
|
||||||
if strings.HasPrefix(pth, `\Device`) {
|
|
||||||
pth = `\\.\GLOBALROOT` + pth
|
|
||||||
}
|
|
||||||
|
|
||||||
han, err := openPath(pth)
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("fetching file handle: %w", err)
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
_ = windows.CloseHandle(han)
|
|
||||||
}()
|
|
||||||
|
|
||||||
buf := make([]uint16, 100)
|
|
||||||
var flags uint32 = 0x0
|
|
||||||
for {
|
|
||||||
n, err := windows.GetFinalPathNameByHandle(han, &buf[0], uint32(len(buf)), flags)
|
|
||||||
if err != nil {
|
|
||||||
// if we mounted a volume that does not also have a drive letter assigned, attempting to
|
|
||||||
// fetch the VOLUME_NAME_DOS will fail with os.ErrNotExist. Attempt to get the VOLUME_NAME_GUID.
|
|
||||||
if errors.Is(err, os.ErrNotExist) && flags != 0x1 {
|
|
||||||
flags = 0x1
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
return "", fmt.Errorf("getting final path name: %w", err)
|
|
||||||
}
|
|
||||||
if n < uint32(len(buf)) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
buf = make([]uint16, n)
|
|
||||||
}
|
|
||||||
finalPath := syscall.UTF16ToString(buf)
|
|
||||||
// We got VOLUME_NAME_DOS, we need to strip away some leading slashes.
|
|
||||||
// Leave unchanged if we ended up requesting VOLUME_NAME_GUID
|
|
||||||
if len(finalPath) > 4 && finalPath[:4] == `\\?\` && flags == 0x0 {
|
|
||||||
finalPath = finalPath[4:]
|
|
||||||
if len(finalPath) > 3 && finalPath[:3] == `UNC` {
|
|
||||||
// return path like \\server\share\...
|
|
||||||
finalPath = `\` + finalPath[3:]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return finalPath, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getBindMappingFromBuffer(buffer []byte, entry mappingEntry) (BindMapping, error) {
|
|
||||||
if len(buffer) < int(entry.VirtRootOffset)+int(entry.VirtRootLength) {
|
|
||||||
return BindMapping{}, fmt.Errorf("invalid buffer")
|
|
||||||
}
|
|
||||||
|
|
||||||
src, err := decodeEntry(buffer[entry.VirtRootOffset : entry.VirtRootOffset+entry.VirtRootLength])
|
|
||||||
if err != nil {
|
|
||||||
return BindMapping{}, fmt.Errorf("decoding entry: %w", err)
|
|
||||||
}
|
|
||||||
targets, err := getTargetsFromBuffer(buffer, int(entry.TargetEntriesOffset), int(entry.NumberOfTargets))
|
|
||||||
if err != nil {
|
|
||||||
return BindMapping{}, fmt.Errorf("fetching targets: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
src, err = getFinalPath(src)
|
|
||||||
if err != nil {
|
|
||||||
return BindMapping{}, fmt.Errorf("fetching final path: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return BindMapping{
|
|
||||||
Flags: entry.Flags,
|
|
||||||
Targets: targets,
|
|
||||||
MountPoint: src,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func openPath(path string) (windows.Handle, error) {
|
|
||||||
u16, err := windows.UTF16PtrFromString(path)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
h, err := windows.CreateFile(
|
|
||||||
u16,
|
|
||||||
0,
|
|
||||||
windows.FILE_SHARE_READ|windows.FILE_SHARE_WRITE|windows.FILE_SHARE_DELETE,
|
|
||||||
nil,
|
|
||||||
windows.OPEN_EXISTING,
|
|
||||||
windows.FILE_FLAG_BACKUP_SEMANTICS, // Needed to open a directory handle.
|
|
||||||
0)
|
|
||||||
if err != nil {
|
|
||||||
return 0, &os.PathError{
|
|
||||||
Op: "CreateFile",
|
|
||||||
Path: path,
|
|
||||||
Err: err,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return h, nil
|
|
||||||
}
|
|
@ -1,116 +0,0 @@
|
|||||||
//go:build windows
|
|
||||||
|
|
||||||
// Code generated by 'go generate' using "github.com/Microsoft/go-winio/tools/mkwinsyscall"; DO NOT EDIT.
|
|
||||||
|
|
||||||
package bindfilter
|
|
||||||
|
|
||||||
import (
|
|
||||||
"syscall"
|
|
||||||
"unsafe"
|
|
||||||
|
|
||||||
"golang.org/x/sys/windows"
|
|
||||||
)
|
|
||||||
|
|
||||||
var _ unsafe.Pointer
|
|
||||||
|
|
||||||
// Do the interface allocations only once for common
|
|
||||||
// Errno values.
|
|
||||||
const (
|
|
||||||
errnoERROR_IO_PENDING = 997
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
|
|
||||||
errERROR_EINVAL error = syscall.EINVAL
|
|
||||||
)
|
|
||||||
|
|
||||||
// errnoErr returns common boxed Errno values, to prevent
|
|
||||||
// allocations at runtime.
|
|
||||||
func errnoErr(e syscall.Errno) error {
|
|
||||||
switch e {
|
|
||||||
case 0:
|
|
||||||
return errERROR_EINVAL
|
|
||||||
case errnoERROR_IO_PENDING:
|
|
||||||
return errERROR_IO_PENDING
|
|
||||||
}
|
|
||||||
// TODO: add more here, after collecting data on the common
|
|
||||||
// error values see on Windows. (perhaps when running
|
|
||||||
// all.bat?)
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
modbindfltapi = windows.NewLazySystemDLL("bindfltapi.dll")
|
|
||||||
|
|
||||||
procBfGetMappings = modbindfltapi.NewProc("BfGetMappings")
|
|
||||||
procBfRemoveMapping = modbindfltapi.NewProc("BfRemoveMapping")
|
|
||||||
procBfSetupFilter = modbindfltapi.NewProc("BfSetupFilter")
|
|
||||||
)
|
|
||||||
|
|
||||||
func bfGetMappings(flags uint32, jobHandle windows.Handle, virtRootPath *uint16, sid *windows.SID, bufferSize *uint32, outBuffer *byte) (hr error) {
|
|
||||||
hr = procBfGetMappings.Find()
|
|
||||||
if hr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
r0, _, _ := syscall.Syscall6(procBfGetMappings.Addr(), 6, uintptr(flags), uintptr(jobHandle), uintptr(unsafe.Pointer(virtRootPath)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(bufferSize)), uintptr(unsafe.Pointer(outBuffer)))
|
|
||||||
if int32(r0) < 0 {
|
|
||||||
if r0&0x1fff0000 == 0x00070000 {
|
|
||||||
r0 &= 0xffff
|
|
||||||
}
|
|
||||||
hr = syscall.Errno(r0)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func bfRemoveMapping(jobHandle windows.Handle, virtRootPath string) (hr error) {
|
|
||||||
var _p0 *uint16
|
|
||||||
_p0, hr = syscall.UTF16PtrFromString(virtRootPath)
|
|
||||||
if hr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return _bfRemoveMapping(jobHandle, _p0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func _bfRemoveMapping(jobHandle windows.Handle, virtRootPath *uint16) (hr error) {
|
|
||||||
hr = procBfRemoveMapping.Find()
|
|
||||||
if hr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
r0, _, _ := syscall.Syscall(procBfRemoveMapping.Addr(), 2, uintptr(jobHandle), uintptr(unsafe.Pointer(virtRootPath)), 0)
|
|
||||||
if int32(r0) < 0 {
|
|
||||||
if r0&0x1fff0000 == 0x00070000 {
|
|
||||||
r0 &= 0xffff
|
|
||||||
}
|
|
||||||
hr = syscall.Errno(r0)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func bfSetupFilter(jobHandle windows.Handle, flags uint32, virtRootPath string, virtTargetPath string, virtExceptions **uint16, virtExceptionPathCount uint32) (hr error) {
|
|
||||||
var _p0 *uint16
|
|
||||||
_p0, hr = syscall.UTF16PtrFromString(virtRootPath)
|
|
||||||
if hr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var _p1 *uint16
|
|
||||||
_p1, hr = syscall.UTF16PtrFromString(virtTargetPath)
|
|
||||||
if hr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return _bfSetupFilter(jobHandle, flags, _p0, _p1, virtExceptions, virtExceptionPathCount)
|
|
||||||
}
|
|
||||||
|
|
||||||
func _bfSetupFilter(jobHandle windows.Handle, flags uint32, virtRootPath *uint16, virtTargetPath *uint16, virtExceptions **uint16, virtExceptionPathCount uint32) (hr error) {
|
|
||||||
hr = procBfSetupFilter.Find()
|
|
||||||
if hr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
r0, _, _ := syscall.Syscall6(procBfSetupFilter.Addr(), 6, uintptr(jobHandle), uintptr(flags), uintptr(unsafe.Pointer(virtRootPath)), uintptr(unsafe.Pointer(virtTargetPath)), uintptr(unsafe.Pointer(virtExceptions)), uintptr(virtExceptionPathCount))
|
|
||||||
if int32(r0) < 0 {
|
|
||||||
if r0&0x1fff0000 == 0x00070000 {
|
|
||||||
r0 &= 0xffff
|
|
||||||
}
|
|
||||||
hr = syscall.Errno(r0)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
@ -1,57 +0,0 @@
|
|||||||
/*
|
|
||||||
mkwinsyscall generates windows system call bodies
|
|
||||||
|
|
||||||
It parses all files specified on command line containing function
|
|
||||||
prototypes (like syscall_windows.go) and prints system call bodies
|
|
||||||
to standard output.
|
|
||||||
|
|
||||||
The prototypes are marked by lines beginning with "//sys" and read
|
|
||||||
like func declarations if //sys is replaced by func, but:
|
|
||||||
|
|
||||||
- The parameter lists must give a name for each argument. This
|
|
||||||
includes return parameters.
|
|
||||||
|
|
||||||
- The parameter lists must give a type for each argument:
|
|
||||||
the (x, y, z int) shorthand is not allowed.
|
|
||||||
|
|
||||||
- If the return parameter is an error number, it must be named err.
|
|
||||||
|
|
||||||
- If go func name needs to be different from its winapi dll name,
|
|
||||||
the winapi name could be specified at the end, after "=" sign, like
|
|
||||||
|
|
||||||
//sys LoadLibrary(libname string) (handle uint32, err error) = LoadLibraryA
|
|
||||||
|
|
||||||
- Each function that returns err needs to supply a condition, that
|
|
||||||
return value of winapi will be tested against to detect failure.
|
|
||||||
This would set err to windows "last-error", otherwise it will be nil.
|
|
||||||
The value can be provided at end of //sys declaration, like
|
|
||||||
|
|
||||||
//sys LoadLibrary(libname string) (handle uint32, err error) [failretval==-1] = LoadLibraryA
|
|
||||||
|
|
||||||
and is [failretval==0] by default.
|
|
||||||
|
|
||||||
- If the function name ends in a "?", then the function not existing is non-
|
|
||||||
fatal, and an error will be returned instead of panicking.
|
|
||||||
|
|
||||||
Usage:
|
|
||||||
|
|
||||||
mkwinsyscall [flags] [path ...]
|
|
||||||
|
|
||||||
Flags
|
|
||||||
|
|
||||||
-output string
|
|
||||||
Output file name (standard output if omitted).
|
|
||||||
-sort
|
|
||||||
Sort DLL and function declarations (default true).
|
|
||||||
Intended to help transition from older versions of mkwinsyscall by making diffs
|
|
||||||
easier to read and understand.
|
|
||||||
-systemdll
|
|
||||||
Whether all DLLs should be loaded from the Windows system directory (default true).
|
|
||||||
-trace
|
|
||||||
Generate print statement after every syscall.
|
|
||||||
-utf16
|
|
||||||
Encode string arguments as UTF-16 for syscalls not ending in 'A' or 'W' (default true).
|
|
||||||
-winio
|
|
||||||
Import this package ("github.com/Microsoft/go-winio").
|
|
||||||
*/
|
|
||||||
package main
|
|
File diff suppressed because it is too large
Load Diff
@ -1,377 +0,0 @@
|
|||||||
//go:build windows
|
|
||||||
// +build windows
|
|
||||||
|
|
||||||
package vhd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"github.com/Microsoft/go-winio/pkg/guid"
|
|
||||||
"golang.org/x/sys/windows"
|
|
||||||
)
|
|
||||||
|
|
||||||
//go:generate go run github.com/Microsoft/go-winio/tools/mkwinsyscall -output zvhd_windows.go vhd.go
|
|
||||||
|
|
||||||
//sys createVirtualDisk(virtualStorageType *VirtualStorageType, path string, virtualDiskAccessMask uint32, securityDescriptor *uintptr, createVirtualDiskFlags uint32, providerSpecificFlags uint32, parameters *CreateVirtualDiskParameters, overlapped *syscall.Overlapped, handle *syscall.Handle) (win32err error) = virtdisk.CreateVirtualDisk
|
|
||||||
//sys openVirtualDisk(virtualStorageType *VirtualStorageType, path string, virtualDiskAccessMask uint32, openVirtualDiskFlags uint32, parameters *openVirtualDiskParameters, handle *syscall.Handle) (win32err error) = virtdisk.OpenVirtualDisk
|
|
||||||
//sys attachVirtualDisk(handle syscall.Handle, securityDescriptor *uintptr, attachVirtualDiskFlag uint32, providerSpecificFlags uint32, parameters *AttachVirtualDiskParameters, overlapped *syscall.Overlapped) (win32err error) = virtdisk.AttachVirtualDisk
|
|
||||||
//sys detachVirtualDisk(handle syscall.Handle, detachVirtualDiskFlags uint32, providerSpecificFlags uint32) (win32err error) = virtdisk.DetachVirtualDisk
|
|
||||||
//sys getVirtualDiskPhysicalPath(handle syscall.Handle, diskPathSizeInBytes *uint32, buffer *uint16) (win32err error) = virtdisk.GetVirtualDiskPhysicalPath
|
|
||||||
|
|
||||||
type (
|
|
||||||
CreateVirtualDiskFlag uint32
|
|
||||||
VirtualDiskFlag uint32
|
|
||||||
AttachVirtualDiskFlag uint32
|
|
||||||
DetachVirtualDiskFlag uint32
|
|
||||||
VirtualDiskAccessMask uint32
|
|
||||||
)
|
|
||||||
|
|
||||||
type VirtualStorageType struct {
|
|
||||||
DeviceID uint32
|
|
||||||
VendorID guid.GUID
|
|
||||||
}
|
|
||||||
|
|
||||||
type CreateVersion2 struct {
|
|
||||||
UniqueID guid.GUID
|
|
||||||
MaximumSize uint64
|
|
||||||
BlockSizeInBytes uint32
|
|
||||||
SectorSizeInBytes uint32
|
|
||||||
PhysicalSectorSizeInByte uint32
|
|
||||||
ParentPath *uint16 // string
|
|
||||||
SourcePath *uint16 // string
|
|
||||||
OpenFlags uint32
|
|
||||||
ParentVirtualStorageType VirtualStorageType
|
|
||||||
SourceVirtualStorageType VirtualStorageType
|
|
||||||
ResiliencyGUID guid.GUID
|
|
||||||
}
|
|
||||||
|
|
||||||
type CreateVirtualDiskParameters struct {
|
|
||||||
Version uint32 // Must always be set to 2
|
|
||||||
Version2 CreateVersion2
|
|
||||||
}
|
|
||||||
|
|
||||||
type OpenVersion2 struct {
|
|
||||||
GetInfoOnly bool
|
|
||||||
ReadOnly bool
|
|
||||||
ResiliencyGUID guid.GUID
|
|
||||||
}
|
|
||||||
|
|
||||||
type OpenVirtualDiskParameters struct {
|
|
||||||
Version uint32 // Must always be set to 2
|
|
||||||
Version2 OpenVersion2
|
|
||||||
}
|
|
||||||
|
|
||||||
// The higher level `OpenVersion2` struct uses `bool`s to refer to `GetInfoOnly` and `ReadOnly` for ease of use. However,
|
|
||||||
// the internal windows structure uses `BOOL`s aka int32s for these types. `openVersion2` is used for translating
|
|
||||||
// `OpenVersion2` fields to the correct windows internal field types on the `Open____` methods.
|
|
||||||
type openVersion2 struct {
|
|
||||||
getInfoOnly int32
|
|
||||||
readOnly int32
|
|
||||||
resiliencyGUID guid.GUID
|
|
||||||
}
|
|
||||||
|
|
||||||
type openVirtualDiskParameters struct {
|
|
||||||
version uint32
|
|
||||||
version2 openVersion2
|
|
||||||
}
|
|
||||||
|
|
||||||
type AttachVersion2 struct {
|
|
||||||
RestrictedOffset uint64
|
|
||||||
RestrictedLength uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
type AttachVirtualDiskParameters struct {
|
|
||||||
Version uint32
|
|
||||||
Version2 AttachVersion2
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
//revive:disable-next-line:var-naming ALL_CAPS
|
|
||||||
VIRTUAL_STORAGE_TYPE_DEVICE_VHDX = 0x3
|
|
||||||
|
|
||||||
// Access Mask for opening a VHD.
|
|
||||||
VirtualDiskAccessNone VirtualDiskAccessMask = 0x00000000
|
|
||||||
VirtualDiskAccessAttachRO VirtualDiskAccessMask = 0x00010000
|
|
||||||
VirtualDiskAccessAttachRW VirtualDiskAccessMask = 0x00020000
|
|
||||||
VirtualDiskAccessDetach VirtualDiskAccessMask = 0x00040000
|
|
||||||
VirtualDiskAccessGetInfo VirtualDiskAccessMask = 0x00080000
|
|
||||||
VirtualDiskAccessCreate VirtualDiskAccessMask = 0x00100000
|
|
||||||
VirtualDiskAccessMetaOps VirtualDiskAccessMask = 0x00200000
|
|
||||||
VirtualDiskAccessRead VirtualDiskAccessMask = 0x000d0000
|
|
||||||
VirtualDiskAccessAll VirtualDiskAccessMask = 0x003f0000
|
|
||||||
VirtualDiskAccessWritable VirtualDiskAccessMask = 0x00320000
|
|
||||||
|
|
||||||
// Flags for creating a VHD.
|
|
||||||
CreateVirtualDiskFlagNone CreateVirtualDiskFlag = 0x0
|
|
||||||
CreateVirtualDiskFlagFullPhysicalAllocation CreateVirtualDiskFlag = 0x1
|
|
||||||
CreateVirtualDiskFlagPreventWritesToSourceDisk CreateVirtualDiskFlag = 0x2
|
|
||||||
CreateVirtualDiskFlagDoNotCopyMetadataFromParent CreateVirtualDiskFlag = 0x4
|
|
||||||
CreateVirtualDiskFlagCreateBackingStorage CreateVirtualDiskFlag = 0x8
|
|
||||||
CreateVirtualDiskFlagUseChangeTrackingSourceLimit CreateVirtualDiskFlag = 0x10
|
|
||||||
CreateVirtualDiskFlagPreserveParentChangeTrackingState CreateVirtualDiskFlag = 0x20
|
|
||||||
CreateVirtualDiskFlagVhdSetUseOriginalBackingStorage CreateVirtualDiskFlag = 0x40 //revive:disable-line:var-naming VHD, not Vhd
|
|
||||||
CreateVirtualDiskFlagSparseFile CreateVirtualDiskFlag = 0x80
|
|
||||||
CreateVirtualDiskFlagPmemCompatible CreateVirtualDiskFlag = 0x100 //revive:disable-line:var-naming PMEM, not Pmem
|
|
||||||
CreateVirtualDiskFlagSupportCompressedVolumes CreateVirtualDiskFlag = 0x200
|
|
||||||
|
|
||||||
// Flags for opening a VHD.
|
|
||||||
OpenVirtualDiskFlagNone VirtualDiskFlag = 0x00000000
|
|
||||||
OpenVirtualDiskFlagNoParents VirtualDiskFlag = 0x00000001
|
|
||||||
OpenVirtualDiskFlagBlankFile VirtualDiskFlag = 0x00000002
|
|
||||||
OpenVirtualDiskFlagBootDrive VirtualDiskFlag = 0x00000004
|
|
||||||
OpenVirtualDiskFlagCachedIO VirtualDiskFlag = 0x00000008
|
|
||||||
OpenVirtualDiskFlagCustomDiffChain VirtualDiskFlag = 0x00000010
|
|
||||||
OpenVirtualDiskFlagParentCachedIO VirtualDiskFlag = 0x00000020
|
|
||||||
OpenVirtualDiskFlagVhdsetFileOnly VirtualDiskFlag = 0x00000040
|
|
||||||
OpenVirtualDiskFlagIgnoreRelativeParentLocator VirtualDiskFlag = 0x00000080
|
|
||||||
OpenVirtualDiskFlagNoWriteHardening VirtualDiskFlag = 0x00000100
|
|
||||||
OpenVirtualDiskFlagSupportCompressedVolumes VirtualDiskFlag = 0x00000200
|
|
||||||
|
|
||||||
// Flags for attaching a VHD.
|
|
||||||
AttachVirtualDiskFlagNone AttachVirtualDiskFlag = 0x00000000
|
|
||||||
AttachVirtualDiskFlagReadOnly AttachVirtualDiskFlag = 0x00000001
|
|
||||||
AttachVirtualDiskFlagNoDriveLetter AttachVirtualDiskFlag = 0x00000002
|
|
||||||
AttachVirtualDiskFlagPermanentLifetime AttachVirtualDiskFlag = 0x00000004
|
|
||||||
AttachVirtualDiskFlagNoLocalHost AttachVirtualDiskFlag = 0x00000008
|
|
||||||
AttachVirtualDiskFlagNoSecurityDescriptor AttachVirtualDiskFlag = 0x00000010
|
|
||||||
AttachVirtualDiskFlagBypassDefaultEncryptionPolicy AttachVirtualDiskFlag = 0x00000020
|
|
||||||
AttachVirtualDiskFlagNonPnp AttachVirtualDiskFlag = 0x00000040
|
|
||||||
AttachVirtualDiskFlagRestrictedRange AttachVirtualDiskFlag = 0x00000080
|
|
||||||
AttachVirtualDiskFlagSinglePartition AttachVirtualDiskFlag = 0x00000100
|
|
||||||
AttachVirtualDiskFlagRegisterVolume AttachVirtualDiskFlag = 0x00000200
|
|
||||||
|
|
||||||
// Flags for detaching a VHD.
|
|
||||||
DetachVirtualDiskFlagNone DetachVirtualDiskFlag = 0x0
|
|
||||||
)
|
|
||||||
|
|
||||||
// CreateVhdx is a helper function to create a simple vhdx file at the given path using
|
|
||||||
// default values.
|
|
||||||
//
|
|
||||||
//revive:disable-next-line:var-naming VHDX, not Vhdx
|
|
||||||
func CreateVhdx(path string, maxSizeInGb, blockSizeInMb uint32) error {
|
|
||||||
params := CreateVirtualDiskParameters{
|
|
||||||
Version: 2,
|
|
||||||
Version2: CreateVersion2{
|
|
||||||
MaximumSize: uint64(maxSizeInGb) * 1024 * 1024 * 1024,
|
|
||||||
BlockSizeInBytes: blockSizeInMb * 1024 * 1024,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
handle, err := CreateVirtualDisk(path, VirtualDiskAccessNone, CreateVirtualDiskFlagNone, ¶ms)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return syscall.CloseHandle(handle)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DetachVirtualDisk detaches a virtual hard disk by handle.
|
|
||||||
func DetachVirtualDisk(handle syscall.Handle) (err error) {
|
|
||||||
if err := detachVirtualDisk(handle, 0, 0); err != nil {
|
|
||||||
return fmt.Errorf("failed to detach virtual disk: %w", err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DetachVhd detaches a vhd found at `path`.
|
|
||||||
//
|
|
||||||
//revive:disable-next-line:var-naming VHD, not Vhd
|
|
||||||
func DetachVhd(path string) error {
|
|
||||||
handle, err := OpenVirtualDisk(
|
|
||||||
path,
|
|
||||||
VirtualDiskAccessNone,
|
|
||||||
OpenVirtualDiskFlagCachedIO|OpenVirtualDiskFlagIgnoreRelativeParentLocator,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer syscall.CloseHandle(handle) //nolint:errcheck
|
|
||||||
return DetachVirtualDisk(handle)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AttachVirtualDisk attaches a virtual hard disk for use.
|
|
||||||
func AttachVirtualDisk(
|
|
||||||
handle syscall.Handle,
|
|
||||||
attachVirtualDiskFlag AttachVirtualDiskFlag,
|
|
||||||
parameters *AttachVirtualDiskParameters,
|
|
||||||
) (err error) {
|
|
||||||
// Supports both version 1 and 2 of the attach parameters as version 2 wasn't present in RS5.
|
|
||||||
if err := attachVirtualDisk(
|
|
||||||
handle,
|
|
||||||
nil,
|
|
||||||
uint32(attachVirtualDiskFlag),
|
|
||||||
0,
|
|
||||||
parameters,
|
|
||||||
nil,
|
|
||||||
); err != nil {
|
|
||||||
return fmt.Errorf("failed to attach virtual disk: %w", err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// AttachVhd attaches a virtual hard disk at `path` for use. Attaches using version 2
|
|
||||||
// of the ATTACH_VIRTUAL_DISK_PARAMETERS.
|
|
||||||
//
|
|
||||||
//revive:disable-next-line:var-naming VHD, not Vhd
|
|
||||||
func AttachVhd(path string) (err error) {
|
|
||||||
handle, err := OpenVirtualDisk(
|
|
||||||
path,
|
|
||||||
VirtualDiskAccessNone,
|
|
||||||
OpenVirtualDiskFlagCachedIO|OpenVirtualDiskFlagIgnoreRelativeParentLocator,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
defer syscall.CloseHandle(handle) //nolint:errcheck
|
|
||||||
params := AttachVirtualDiskParameters{Version: 2}
|
|
||||||
if err := AttachVirtualDisk(
|
|
||||||
handle,
|
|
||||||
AttachVirtualDiskFlagNone,
|
|
||||||
¶ms,
|
|
||||||
); err != nil {
|
|
||||||
return fmt.Errorf("failed to attach virtual disk: %w", err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// OpenVirtualDisk obtains a handle to a VHD opened with supplied access mask and flags.
|
|
||||||
func OpenVirtualDisk(
|
|
||||||
vhdPath string,
|
|
||||||
virtualDiskAccessMask VirtualDiskAccessMask,
|
|
||||||
openVirtualDiskFlags VirtualDiskFlag,
|
|
||||||
) (syscall.Handle, error) {
|
|
||||||
parameters := OpenVirtualDiskParameters{Version: 2}
|
|
||||||
handle, err := OpenVirtualDiskWithParameters(
|
|
||||||
vhdPath,
|
|
||||||
virtualDiskAccessMask,
|
|
||||||
openVirtualDiskFlags,
|
|
||||||
¶meters,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
return handle, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// OpenVirtualDiskWithParameters obtains a handle to a VHD opened with supplied access mask, flags and parameters.
|
|
||||||
func OpenVirtualDiskWithParameters(
|
|
||||||
vhdPath string,
|
|
||||||
virtualDiskAccessMask VirtualDiskAccessMask,
|
|
||||||
openVirtualDiskFlags VirtualDiskFlag,
|
|
||||||
parameters *OpenVirtualDiskParameters,
|
|
||||||
) (syscall.Handle, error) {
|
|
||||||
var (
|
|
||||||
handle syscall.Handle
|
|
||||||
defaultType VirtualStorageType
|
|
||||||
getInfoOnly int32
|
|
||||||
readOnly int32
|
|
||||||
)
|
|
||||||
if parameters.Version != 2 {
|
|
||||||
return handle, fmt.Errorf("only version 2 VHDs are supported, found version: %d", parameters.Version)
|
|
||||||
}
|
|
||||||
if parameters.Version2.GetInfoOnly {
|
|
||||||
getInfoOnly = 1
|
|
||||||
}
|
|
||||||
if parameters.Version2.ReadOnly {
|
|
||||||
readOnly = 1
|
|
||||||
}
|
|
||||||
params := &openVirtualDiskParameters{
|
|
||||||
version: parameters.Version,
|
|
||||||
version2: openVersion2{
|
|
||||||
getInfoOnly,
|
|
||||||
readOnly,
|
|
||||||
parameters.Version2.ResiliencyGUID,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
if err := openVirtualDisk(
|
|
||||||
&defaultType,
|
|
||||||
vhdPath,
|
|
||||||
uint32(virtualDiskAccessMask),
|
|
||||||
uint32(openVirtualDiskFlags),
|
|
||||||
params,
|
|
||||||
&handle,
|
|
||||||
); err != nil {
|
|
||||||
return 0, fmt.Errorf("failed to open virtual disk: %w", err)
|
|
||||||
}
|
|
||||||
return handle, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateVirtualDisk creates a virtual harddisk and returns a handle to the disk.
|
|
||||||
func CreateVirtualDisk(
|
|
||||||
path string,
|
|
||||||
virtualDiskAccessMask VirtualDiskAccessMask,
|
|
||||||
createVirtualDiskFlags CreateVirtualDiskFlag,
|
|
||||||
parameters *CreateVirtualDiskParameters,
|
|
||||||
) (syscall.Handle, error) {
|
|
||||||
var (
|
|
||||||
handle syscall.Handle
|
|
||||||
defaultType VirtualStorageType
|
|
||||||
)
|
|
||||||
if parameters.Version != 2 {
|
|
||||||
return handle, fmt.Errorf("only version 2 VHDs are supported, found version: %d", parameters.Version)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := createVirtualDisk(
|
|
||||||
&defaultType,
|
|
||||||
path,
|
|
||||||
uint32(virtualDiskAccessMask),
|
|
||||||
nil,
|
|
||||||
uint32(createVirtualDiskFlags),
|
|
||||||
0,
|
|
||||||
parameters,
|
|
||||||
nil,
|
|
||||||
&handle,
|
|
||||||
); err != nil {
|
|
||||||
return handle, fmt.Errorf("failed to create virtual disk: %w", err)
|
|
||||||
}
|
|
||||||
return handle, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetVirtualDiskPhysicalPath takes a handle to a virtual hard disk and returns the physical
|
|
||||||
// path of the disk on the machine. This path is in the form \\.\PhysicalDriveX where X is an integer
|
|
||||||
// that represents the particular enumeration of the physical disk on the caller's system.
|
|
||||||
func GetVirtualDiskPhysicalPath(handle syscall.Handle) (_ string, err error) {
|
|
||||||
var (
|
|
||||||
diskPathSizeInBytes uint32 = 256 * 2 // max path length 256 wide chars
|
|
||||||
diskPhysicalPathBuf [256]uint16
|
|
||||||
)
|
|
||||||
if err := getVirtualDiskPhysicalPath(
|
|
||||||
handle,
|
|
||||||
&diskPathSizeInBytes,
|
|
||||||
&diskPhysicalPathBuf[0],
|
|
||||||
); err != nil {
|
|
||||||
return "", fmt.Errorf("failed to get disk physical path: %w", err)
|
|
||||||
}
|
|
||||||
return windows.UTF16ToString(diskPhysicalPathBuf[:]), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateDiffVhd is a helper function to create a differencing virtual disk.
|
|
||||||
//
|
|
||||||
//revive:disable-next-line:var-naming VHD, not Vhd
|
|
||||||
func CreateDiffVhd(diffVhdPath, baseVhdPath string, blockSizeInMB uint32) error {
|
|
||||||
// Setting `ParentPath` is how to signal to create a differencing disk.
|
|
||||||
createParams := &CreateVirtualDiskParameters{
|
|
||||||
Version: 2,
|
|
||||||
Version2: CreateVersion2{
|
|
||||||
ParentPath: windows.StringToUTF16Ptr(baseVhdPath),
|
|
||||||
BlockSizeInBytes: blockSizeInMB * 1024 * 1024,
|
|
||||||
OpenFlags: uint32(OpenVirtualDiskFlagCachedIO),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
vhdHandle, err := CreateVirtualDisk(
|
|
||||||
diffVhdPath,
|
|
||||||
VirtualDiskAccessNone,
|
|
||||||
CreateVirtualDiskFlagNone,
|
|
||||||
createParams,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to create differencing vhd: %w", err)
|
|
||||||
}
|
|
||||||
if err := syscall.CloseHandle(vhdHandle); err != nil {
|
|
||||||
return fmt.Errorf("failed to close differencing vhd handle: %w", err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
@ -1,108 +0,0 @@
|
|||||||
//go:build windows
|
|
||||||
|
|
||||||
// Code generated by 'go generate' using "github.com/Microsoft/go-winio/tools/mkwinsyscall"; DO NOT EDIT.
|
|
||||||
|
|
||||||
package vhd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"syscall"
|
|
||||||
"unsafe"
|
|
||||||
|
|
||||||
"golang.org/x/sys/windows"
|
|
||||||
)
|
|
||||||
|
|
||||||
var _ unsafe.Pointer
|
|
||||||
|
|
||||||
// Do the interface allocations only once for common
|
|
||||||
// Errno values.
|
|
||||||
const (
|
|
||||||
errnoERROR_IO_PENDING = 997
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
|
|
||||||
errERROR_EINVAL error = syscall.EINVAL
|
|
||||||
)
|
|
||||||
|
|
||||||
// errnoErr returns common boxed Errno values, to prevent
|
|
||||||
// allocations at runtime.
|
|
||||||
func errnoErr(e syscall.Errno) error {
|
|
||||||
switch e {
|
|
||||||
case 0:
|
|
||||||
return errERROR_EINVAL
|
|
||||||
case errnoERROR_IO_PENDING:
|
|
||||||
return errERROR_IO_PENDING
|
|
||||||
}
|
|
||||||
// TODO: add more here, after collecting data on the common
|
|
||||||
// error values see on Windows. (perhaps when running
|
|
||||||
// all.bat?)
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
modvirtdisk = windows.NewLazySystemDLL("virtdisk.dll")
|
|
||||||
|
|
||||||
procAttachVirtualDisk = modvirtdisk.NewProc("AttachVirtualDisk")
|
|
||||||
procCreateVirtualDisk = modvirtdisk.NewProc("CreateVirtualDisk")
|
|
||||||
procDetachVirtualDisk = modvirtdisk.NewProc("DetachVirtualDisk")
|
|
||||||
procGetVirtualDiskPhysicalPath = modvirtdisk.NewProc("GetVirtualDiskPhysicalPath")
|
|
||||||
procOpenVirtualDisk = modvirtdisk.NewProc("OpenVirtualDisk")
|
|
||||||
)
|
|
||||||
|
|
||||||
func attachVirtualDisk(handle syscall.Handle, securityDescriptor *uintptr, attachVirtualDiskFlag uint32, providerSpecificFlags uint32, parameters *AttachVirtualDiskParameters, overlapped *syscall.Overlapped) (win32err error) {
|
|
||||||
r0, _, _ := syscall.Syscall6(procAttachVirtualDisk.Addr(), 6, uintptr(handle), uintptr(unsafe.Pointer(securityDescriptor)), uintptr(attachVirtualDiskFlag), uintptr(providerSpecificFlags), uintptr(unsafe.Pointer(parameters)), uintptr(unsafe.Pointer(overlapped)))
|
|
||||||
if r0 != 0 {
|
|
||||||
win32err = syscall.Errno(r0)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func createVirtualDisk(virtualStorageType *VirtualStorageType, path string, virtualDiskAccessMask uint32, securityDescriptor *uintptr, createVirtualDiskFlags uint32, providerSpecificFlags uint32, parameters *CreateVirtualDiskParameters, overlapped *syscall.Overlapped, handle *syscall.Handle) (win32err error) {
|
|
||||||
var _p0 *uint16
|
|
||||||
_p0, win32err = syscall.UTF16PtrFromString(path)
|
|
||||||
if win32err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return _createVirtualDisk(virtualStorageType, _p0, virtualDiskAccessMask, securityDescriptor, createVirtualDiskFlags, providerSpecificFlags, parameters, overlapped, handle)
|
|
||||||
}
|
|
||||||
|
|
||||||
func _createVirtualDisk(virtualStorageType *VirtualStorageType, path *uint16, virtualDiskAccessMask uint32, securityDescriptor *uintptr, createVirtualDiskFlags uint32, providerSpecificFlags uint32, parameters *CreateVirtualDiskParameters, overlapped *syscall.Overlapped, handle *syscall.Handle) (win32err error) {
|
|
||||||
r0, _, _ := syscall.Syscall9(procCreateVirtualDisk.Addr(), 9, uintptr(unsafe.Pointer(virtualStorageType)), uintptr(unsafe.Pointer(path)), uintptr(virtualDiskAccessMask), uintptr(unsafe.Pointer(securityDescriptor)), uintptr(createVirtualDiskFlags), uintptr(providerSpecificFlags), uintptr(unsafe.Pointer(parameters)), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(handle)))
|
|
||||||
if r0 != 0 {
|
|
||||||
win32err = syscall.Errno(r0)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func detachVirtualDisk(handle syscall.Handle, detachVirtualDiskFlags uint32, providerSpecificFlags uint32) (win32err error) {
|
|
||||||
r0, _, _ := syscall.Syscall(procDetachVirtualDisk.Addr(), 3, uintptr(handle), uintptr(detachVirtualDiskFlags), uintptr(providerSpecificFlags))
|
|
||||||
if r0 != 0 {
|
|
||||||
win32err = syscall.Errno(r0)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func getVirtualDiskPhysicalPath(handle syscall.Handle, diskPathSizeInBytes *uint32, buffer *uint16) (win32err error) {
|
|
||||||
r0, _, _ := syscall.Syscall(procGetVirtualDiskPhysicalPath.Addr(), 3, uintptr(handle), uintptr(unsafe.Pointer(diskPathSizeInBytes)), uintptr(unsafe.Pointer(buffer)))
|
|
||||||
if r0 != 0 {
|
|
||||||
win32err = syscall.Errno(r0)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func openVirtualDisk(virtualStorageType *VirtualStorageType, path string, virtualDiskAccessMask uint32, openVirtualDiskFlags uint32, parameters *openVirtualDiskParameters, handle *syscall.Handle) (win32err error) {
|
|
||||||
var _p0 *uint16
|
|
||||||
_p0, win32err = syscall.UTF16PtrFromString(path)
|
|
||||||
if win32err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return _openVirtualDisk(virtualStorageType, _p0, virtualDiskAccessMask, openVirtualDiskFlags, parameters, handle)
|
|
||||||
}
|
|
||||||
|
|
||||||
func _openVirtualDisk(virtualStorageType *VirtualStorageType, path *uint16, virtualDiskAccessMask uint32, openVirtualDiskFlags uint32, parameters *openVirtualDiskParameters, handle *syscall.Handle) (win32err error) {
|
|
||||||
r0, _, _ := syscall.Syscall6(procOpenVirtualDisk.Addr(), 6, uintptr(unsafe.Pointer(virtualStorageType)), uintptr(unsafe.Pointer(path)), uintptr(virtualDiskAccessMask), uintptr(openVirtualDiskFlags), uintptr(unsafe.Pointer(parameters)), uintptr(unsafe.Pointer(handle)))
|
|
||||||
if r0 != 0 {
|
|
||||||
win32err = syscall.Errno(r0)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
@ -1,3 +0,0 @@
|
|||||||
* text=auto eol=lf
|
|
||||||
vendor/** -text
|
|
||||||
test/vendor/** -text
|
|
@ -1,49 +0,0 @@
|
|||||||
# Binaries for programs and plugins
|
|
||||||
*.exe
|
|
||||||
*.dll
|
|
||||||
*.so
|
|
||||||
*.dylib
|
|
||||||
|
|
||||||
# Ignore vscode setting files
|
|
||||||
.vscode/
|
|
||||||
.idea/
|
|
||||||
|
|
||||||
# Test binary, build with `go test -c`
|
|
||||||
*.test
|
|
||||||
|
|
||||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
|
||||||
*.out
|
|
||||||
|
|
||||||
# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736
|
|
||||||
.glide/
|
|
||||||
|
|
||||||
# Ignore gcs bin directory
|
|
||||||
service/bin/
|
|
||||||
service/pkg/
|
|
||||||
|
|
||||||
*.img
|
|
||||||
*.vhd
|
|
||||||
*.tar.gz
|
|
||||||
*.tar
|
|
||||||
|
|
||||||
# Make stuff
|
|
||||||
.rootfs-done
|
|
||||||
bin/*
|
|
||||||
rootfs/*
|
|
||||||
rootfs-conv/*
|
|
||||||
*.o
|
|
||||||
/build/
|
|
||||||
|
|
||||||
deps/*
|
|
||||||
out/*
|
|
||||||
|
|
||||||
# test results
|
|
||||||
test/results
|
|
||||||
|
|
||||||
# go workspace files
|
|
||||||
go.work
|
|
||||||
go.work.sum
|
|
||||||
|
|
||||||
# keys and related artifacts
|
|
||||||
*.pem
|
|
||||||
*.cose
|
|
@ -1,137 +0,0 @@
|
|||||||
run:
|
|
||||||
timeout: 8m
|
|
||||||
tests: true
|
|
||||||
build-tags:
|
|
||||||
- admin
|
|
||||||
- functional
|
|
||||||
- integration
|
|
||||||
skip-dirs:
|
|
||||||
# paths are relative to module root
|
|
||||||
- cri-containerd/test-images
|
|
||||||
|
|
||||||
linters:
|
|
||||||
enable:
|
|
||||||
# defaults:
|
|
||||||
# - errcheck
|
|
||||||
# - gosimple
|
|
||||||
# - govet
|
|
||||||
# - ineffassign
|
|
||||||
# - staticcheck
|
|
||||||
# - typecheck
|
|
||||||
# - unused
|
|
||||||
|
|
||||||
- gofmt # whether code was gofmt-ed
|
|
||||||
- nolintlint # ill-formed or insufficient nolint directives
|
|
||||||
- stylecheck # golint replacement
|
|
||||||
- thelper # test helpers without t.Helper()
|
|
||||||
|
|
||||||
linters-settings:
|
|
||||||
stylecheck:
|
|
||||||
# https://staticcheck.io/docs/checks
|
|
||||||
checks: ["all"]
|
|
||||||
|
|
||||||
issues:
|
|
||||||
exclude-rules:
|
|
||||||
# path is relative to module root, which is ./test/
|
|
||||||
- path: cri-containerd
|
|
||||||
linters:
|
|
||||||
- stylecheck
|
|
||||||
text: "^ST1003: should not use underscores in package names$"
|
|
||||||
source: "^package cri_containerd$"
|
|
||||||
|
|
||||||
# This repo has a LOT of generated schema files, operating system bindings, and other
|
|
||||||
# things that ST1003 from stylecheck won't like (screaming case Windows api constants for example).
|
|
||||||
# There's also some structs that we *could* change the initialisms to be Go friendly
|
|
||||||
# (Id -> ID) but they're exported and it would be a breaking change.
|
|
||||||
# This makes it so that most new code, code that isn't supposed to be a pretty faithful
|
|
||||||
# mapping to an OS call/constants, or non-generated code still checks if we're following idioms,
|
|
||||||
# while ignoring the things that are just noise or would be more of a hassle than it'd be worth to change.
|
|
||||||
- path: layer.go
|
|
||||||
linters:
|
|
||||||
- stylecheck
|
|
||||||
Text: "ST1003:"
|
|
||||||
|
|
||||||
- path: hcsshim.go
|
|
||||||
linters:
|
|
||||||
- stylecheck
|
|
||||||
Text: "ST1003:"
|
|
||||||
|
|
||||||
- path: cmd\\ncproxy\\nodenetsvc\\
|
|
||||||
linters:
|
|
||||||
- stylecheck
|
|
||||||
Text: "ST1003:"
|
|
||||||
|
|
||||||
- path: cmd\\ncproxy_mock\\
|
|
||||||
linters:
|
|
||||||
- stylecheck
|
|
||||||
Text: "ST1003:"
|
|
||||||
|
|
||||||
- path: internal\\hcs\\schema2\\
|
|
||||||
linters:
|
|
||||||
- stylecheck
|
|
||||||
- gofmt
|
|
||||||
|
|
||||||
- path: internal\\wclayer\\
|
|
||||||
linters:
|
|
||||||
- stylecheck
|
|
||||||
Text: "ST1003:"
|
|
||||||
|
|
||||||
- path: hcn\\
|
|
||||||
linters:
|
|
||||||
- stylecheck
|
|
||||||
Text: "ST1003:"
|
|
||||||
|
|
||||||
- path: internal\\hcs\\schema1\\
|
|
||||||
linters:
|
|
||||||
- stylecheck
|
|
||||||
Text: "ST1003:"
|
|
||||||
|
|
||||||
- path: internal\\hns\\
|
|
||||||
linters:
|
|
||||||
- stylecheck
|
|
||||||
Text: "ST1003:"
|
|
||||||
|
|
||||||
- path: ext4\\internal\\compactext4\\
|
|
||||||
linters:
|
|
||||||
- stylecheck
|
|
||||||
Text: "ST1003:"
|
|
||||||
|
|
||||||
- path: ext4\\internal\\format\\
|
|
||||||
linters:
|
|
||||||
- stylecheck
|
|
||||||
Text: "ST1003:"
|
|
||||||
|
|
||||||
- path: internal\\guestrequest\\
|
|
||||||
linters:
|
|
||||||
- stylecheck
|
|
||||||
Text: "ST1003:"
|
|
||||||
|
|
||||||
- path: internal\\guest\\prot\\
|
|
||||||
linters:
|
|
||||||
- stylecheck
|
|
||||||
Text: "ST1003:"
|
|
||||||
|
|
||||||
- path: internal\\windevice\\
|
|
||||||
linters:
|
|
||||||
- stylecheck
|
|
||||||
Text: "ST1003:"
|
|
||||||
|
|
||||||
- path: internal\\winapi\\
|
|
||||||
linters:
|
|
||||||
- stylecheck
|
|
||||||
Text: "ST1003:"
|
|
||||||
|
|
||||||
- path: internal\\vmcompute\\
|
|
||||||
linters:
|
|
||||||
- stylecheck
|
|
||||||
Text: "ST1003:"
|
|
||||||
|
|
||||||
- path: internal\\regstate\\
|
|
||||||
linters:
|
|
||||||
- stylecheck
|
|
||||||
Text: "ST1003:"
|
|
||||||
|
|
||||||
- path: internal\\hcserror\\
|
|
||||||
linters:
|
|
||||||
- stylecheck
|
|
||||||
Text: "ST1003:"
|
|
@ -1 +0,0 @@
|
|||||||
* @microsoft/containerplat
|
|
@ -1,21 +0,0 @@
|
|||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (c) 2015 Microsoft
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
@ -1,111 +0,0 @@
|
|||||||
BASE:=base.tar.gz
|
|
||||||
DEV_BUILD:=0
|
|
||||||
|
|
||||||
GO:=go
|
|
||||||
GO_FLAGS:=-ldflags "-s -w" # strip Go binaries
|
|
||||||
CGO_ENABLED:=0
|
|
||||||
GOMODVENDOR:=
|
|
||||||
|
|
||||||
CFLAGS:=-O2 -Wall
|
|
||||||
LDFLAGS:=-static -s # strip C binaries
|
|
||||||
|
|
||||||
GO_FLAGS_EXTRA:=
|
|
||||||
ifeq "$(GOMODVENDOR)" "1"
|
|
||||||
GO_FLAGS_EXTRA += -mod=vendor
|
|
||||||
endif
|
|
||||||
GO_BUILD_TAGS:=
|
|
||||||
ifneq ($(strip $(GO_BUILD_TAGS)),)
|
|
||||||
GO_FLAGS_EXTRA += -tags="$(GO_BUILD_TAGS)"
|
|
||||||
endif
|
|
||||||
GO_BUILD:=CGO_ENABLED=$(CGO_ENABLED) $(GO) build $(GO_FLAGS) $(GO_FLAGS_EXTRA)
|
|
||||||
|
|
||||||
SRCROOT=$(dir $(abspath $(firstword $(MAKEFILE_LIST))))
|
|
||||||
# additional directories to search for rule prerequisites and targets
|
|
||||||
VPATH=$(SRCROOT)
|
|
||||||
|
|
||||||
DELTA_TARGET=out/delta.tar.gz
|
|
||||||
|
|
||||||
ifeq "$(DEV_BUILD)" "1"
|
|
||||||
DELTA_TARGET=out/delta-dev.tar.gz
|
|
||||||
endif
|
|
||||||
|
|
||||||
# The link aliases for gcstools
|
|
||||||
GCS_TOOLS=\
|
|
||||||
generichook \
|
|
||||||
install-drivers
|
|
||||||
|
|
||||||
.PHONY: all always rootfs test
|
|
||||||
|
|
||||||
.DEFAULT_GOAL := all
|
|
||||||
|
|
||||||
all: out/initrd.img out/rootfs.tar.gz
|
|
||||||
|
|
||||||
clean:
|
|
||||||
find -name '*.o' -print0 | xargs -0 -r rm
|
|
||||||
rm -rf bin deps rootfs out
|
|
||||||
|
|
||||||
test:
|
|
||||||
cd $(SRCROOT) && $(GO) test -v ./internal/guest/...
|
|
||||||
|
|
||||||
rootfs: out/rootfs.vhd
|
|
||||||
|
|
||||||
out/rootfs.vhd: out/rootfs.tar.gz bin/cmd/tar2ext4
|
|
||||||
gzip -f -d ./out/rootfs.tar.gz
|
|
||||||
bin/cmd/tar2ext4 -vhd -i ./out/rootfs.tar -o $@
|
|
||||||
|
|
||||||
out/rootfs.tar.gz: out/initrd.img
|
|
||||||
rm -rf rootfs-conv
|
|
||||||
mkdir rootfs-conv
|
|
||||||
gunzip -c out/initrd.img | (cd rootfs-conv && cpio -imd)
|
|
||||||
tar -zcf $@ -C rootfs-conv .
|
|
||||||
rm -rf rootfs-conv
|
|
||||||
|
|
||||||
out/initrd.img: $(BASE) $(DELTA_TARGET) $(SRCROOT)/hack/catcpio.sh
|
|
||||||
$(SRCROOT)/hack/catcpio.sh "$(BASE)" $(DELTA_TARGET) > out/initrd.img.uncompressed
|
|
||||||
gzip -c out/initrd.img.uncompressed > $@
|
|
||||||
rm out/initrd.img.uncompressed
|
|
||||||
|
|
||||||
# This target includes utilities which may be useful for testing purposes.
|
|
||||||
out/delta-dev.tar.gz: out/delta.tar.gz bin/internal/tools/snp-report
|
|
||||||
rm -rf rootfs-dev
|
|
||||||
mkdir rootfs-dev
|
|
||||||
tar -xzf out/delta.tar.gz -C rootfs-dev
|
|
||||||
cp bin/internal/tools/snp-report rootfs-dev/bin/
|
|
||||||
tar -zcf $@ -C rootfs-dev .
|
|
||||||
rm -rf rootfs-dev
|
|
||||||
|
|
||||||
out/delta.tar.gz: bin/init bin/vsockexec bin/cmd/gcs bin/cmd/gcstools bin/cmd/hooks/wait-paths Makefile
|
|
||||||
@mkdir -p out
|
|
||||||
rm -rf rootfs
|
|
||||||
mkdir -p rootfs/bin/
|
|
||||||
mkdir -p rootfs/info/
|
|
||||||
cp bin/init rootfs/
|
|
||||||
cp bin/vsockexec rootfs/bin/
|
|
||||||
cp bin/cmd/gcs rootfs/bin/
|
|
||||||
cp bin/cmd/gcstools rootfs/bin/
|
|
||||||
cp bin/cmd/hooks/wait-paths rootfs/bin/
|
|
||||||
for tool in $(GCS_TOOLS); do ln -s gcstools rootfs/bin/$$tool; done
|
|
||||||
git -C $(SRCROOT) rev-parse HEAD > rootfs/info/gcs.commit && \
|
|
||||||
git -C $(SRCROOT) rev-parse --abbrev-ref HEAD > rootfs/info/gcs.branch && \
|
|
||||||
date --iso-8601=minute --utc > rootfs/info/tar.date
|
|
||||||
$(if $(and $(realpath $(subst .tar,.testdata.json,$(BASE))), $(shell which jq)), \
|
|
||||||
jq -r '.IMAGE_NAME' $(subst .tar,.testdata.json,$(BASE)) 2>/dev/null > rootfs/info/image.name && \
|
|
||||||
jq -r '.DATETIME' $(subst .tar,.testdata.json,$(BASE)) 2>/dev/null > rootfs/info/build.date)
|
|
||||||
tar -zcf $@ -C rootfs .
|
|
||||||
rm -rf rootfs
|
|
||||||
|
|
||||||
bin/cmd/gcs bin/cmd/gcstools bin/cmd/hooks/wait-paths bin/cmd/tar2ext4 bin/internal/tools/snp-report:
|
|
||||||
@mkdir -p $(dir $@)
|
|
||||||
GOOS=linux $(GO_BUILD) -o $@ $(SRCROOT)/$(@:bin/%=%)
|
|
||||||
|
|
||||||
bin/vsockexec: vsockexec/vsockexec.o vsockexec/vsock.o
|
|
||||||
@mkdir -p bin
|
|
||||||
$(CC) $(LDFLAGS) -o $@ $^
|
|
||||||
|
|
||||||
bin/init: init/init.o vsockexec/vsock.o
|
|
||||||
@mkdir -p bin
|
|
||||||
$(CC) $(LDFLAGS) -o $@ $^
|
|
||||||
|
|
||||||
%.o: %.c
|
|
||||||
@mkdir -p $(dir $@)
|
|
||||||
$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
|
|
@ -1,48 +0,0 @@
|
|||||||
version = "1"
|
|
||||||
generator = "gogoctrd"
|
|
||||||
plugins = ["grpc", "fieldpath"]
|
|
||||||
|
|
||||||
# Control protoc include paths. Below are usually some good defaults, but feel
|
|
||||||
# free to try it without them if it works for your project.
|
|
||||||
[includes]
|
|
||||||
# Include paths that will be added before all others. Typically, you want to
|
|
||||||
# treat the root of the project as an include, but this may not be necessary.
|
|
||||||
before = ["./protobuf"]
|
|
||||||
|
|
||||||
# Paths that should be treated as include roots in relation to the vendor
|
|
||||||
# directory. These will be calculated with the vendor directory nearest the
|
|
||||||
# target package.
|
|
||||||
packages = ["github.com/gogo/protobuf"]
|
|
||||||
|
|
||||||
# This section maps protobuf imports to Go packages. These will become
|
|
||||||
# `-M` directives in the call to the go protobuf generator.
|
|
||||||
[packages]
|
|
||||||
"gogoproto/gogo.proto" = "github.com/gogo/protobuf/gogoproto"
|
|
||||||
"google/protobuf/any.proto" = "github.com/gogo/protobuf/types"
|
|
||||||
"google/protobuf/empty.proto" = "github.com/gogo/protobuf/types"
|
|
||||||
"google/protobuf/struct.proto" = "github.com/gogo/protobuf/types"
|
|
||||||
"google/protobuf/descriptor.proto" = "github.com/gogo/protobuf/protoc-gen-gogo/descriptor"
|
|
||||||
"google/protobuf/field_mask.proto" = "github.com/gogo/protobuf/types"
|
|
||||||
"google/protobuf/timestamp.proto" = "github.com/gogo/protobuf/types"
|
|
||||||
"google/protobuf/duration.proto" = "github.com/gogo/protobuf/types"
|
|
||||||
"github/containerd/cgroups/stats/v1/metrics.proto" = "github.com/containerd/cgroups/stats/v1"
|
|
||||||
|
|
||||||
[[overrides]]
|
|
||||||
prefixes = ["github.com/Microsoft/hcsshim/internal/shimdiag"]
|
|
||||||
plugins = ["ttrpc"]
|
|
||||||
|
|
||||||
[[overrides]]
|
|
||||||
prefixes = ["github.com/Microsoft/hcsshim/internal/extendedtask"]
|
|
||||||
plugins = ["ttrpc"]
|
|
||||||
|
|
||||||
[[overrides]]
|
|
||||||
prefixes = ["github.com/Microsoft/hcsshim/internal/computeagent"]
|
|
||||||
plugins = ["ttrpc"]
|
|
||||||
|
|
||||||
[[overrides]]
|
|
||||||
prefixes = ["github.com/Microsoft/hcsshim/internal/ncproxyttrpc"]
|
|
||||||
plugins = ["ttrpc"]
|
|
||||||
|
|
||||||
[[overrides]]
|
|
||||||
prefixes = ["github.com/Microsoft/hcsshim/internal/vmservice"]
|
|
||||||
plugins = ["ttrpc"]
|
|
@ -1,102 +0,0 @@
|
|||||||
# hcsshim
|
|
||||||
|
|
||||||
[](https://github.com/microsoft/hcsshim/actions?query=branch%3Amaster)
|
|
||||||
|
|
||||||
This package contains the Golang interface for using the Windows [Host Compute Service](https://techcommunity.microsoft.com/t5/containers/introducing-the-host-compute-service-hcs/ba-p/382332) (HCS) to launch and manage [Windows Containers](https://docs.microsoft.com/en-us/virtualization/windowscontainers/about/). It also contains other helpers and functions for managing Windows Containers such as the Golang interface for the Host Network Service (HNS), as well as code for the [guest agent](./internal/guest/README.md) (commonly referred to as the GCS or Guest Compute Service in the codebase) used to support running Linux Hyper-V containers.
|
|
||||||
|
|
||||||
It is primarily used in the [Moby](https://github.com/moby/moby) and [Containerd](https://github.com/containerd/containerd) projects, but it can be freely used by other projects as well.
|
|
||||||
|
|
||||||
## Building
|
|
||||||
|
|
||||||
While this repository can be used as a library of sorts to call the HCS apis, there are a couple binaries built out of the repository as well. The main ones being the Linux guest agent, and an implementation of the [runtime v2 containerd shim api](https://github.com/containerd/containerd/blob/master/runtime/v2/README.md).
|
|
||||||
### Linux Hyper-V Container Guest Agent
|
|
||||||
|
|
||||||
To build the Linux guest agent itself all that's needed is to set your GOOS to "Linux" and build out of ./cmd/gcs.
|
|
||||||
```powershell
|
|
||||||
C:\> $env:GOOS="linux"
|
|
||||||
C:\> go build .\cmd\gcs\
|
|
||||||
```
|
|
||||||
|
|
||||||
or on a Linux machine
|
|
||||||
```sh
|
|
||||||
> go build ./cmd/gcs
|
|
||||||
```
|
|
||||||
|
|
||||||
If you want it to be packaged inside of a rootfs to boot with alongside all of the other tools then you'll need to provide a rootfs that it can be packaged inside of. An easy way is to export the rootfs of a container.
|
|
||||||
|
|
||||||
```sh
|
|
||||||
docker pull busybox
|
|
||||||
docker run --name base_image_container busybox
|
|
||||||
docker export base_image_container | gzip > base.tar.gz
|
|
||||||
BASE=./base.tar.gz
|
|
||||||
make all
|
|
||||||
```
|
|
||||||
|
|
||||||
If the build is successful, in the `./out` folder you should see:
|
|
||||||
```sh
|
|
||||||
> ls ./out/
|
|
||||||
delta.tar.gz initrd.img rootfs.tar.gz
|
|
||||||
```
|
|
||||||
|
|
||||||
### Containerd Shim
|
|
||||||
For info on the Runtime V2 API: https://github.com/containerd/containerd/blob/master/runtime/v2/README.md.
|
|
||||||
|
|
||||||
Contrary to the typical Linux architecture of shim -> runc, the runhcs shim is used both to launch and manage the lifetime of containers.
|
|
||||||
|
|
||||||
```powershell
|
|
||||||
C:\> $env:GOOS="windows"
|
|
||||||
C:\> go build .\cmd\containerd-shim-runhcs-v1
|
|
||||||
```
|
|
||||||
|
|
||||||
Then place the binary in the same directory that Containerd is located at in your environment. A default Containerd configuration file can be generated by running:
|
|
||||||
```powershell
|
|
||||||
.\containerd.exe config default | Out-File "C:\Program Files\containerd\config.toml" -Encoding ascii
|
|
||||||
```
|
|
||||||
|
|
||||||
This config file will already have the shim set as the default runtime for cri interactions.
|
|
||||||
|
|
||||||
To trial using the shim out with ctr.exe:
|
|
||||||
```powershell
|
|
||||||
C:\> ctr.exe run --runtime io.containerd.runhcs.v1 --rm mcr.microsoft.com/windows/nanoserver:2004 windows-test cmd /c "echo Hello World!"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Contributing
|
|
||||||
|
|
||||||
This project welcomes contributions and suggestions. Most contributions require you to agree to a
|
|
||||||
Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
|
|
||||||
the rights to use your contribution. For details, visit https://cla.microsoft.com.
|
|
||||||
|
|
||||||
When you submit a pull request, a CLA-bot will automatically determine whether you need to provide
|
|
||||||
a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions
|
|
||||||
provided by the bot. You will only need to do this once across all repos using our CLA.
|
|
||||||
|
|
||||||
We also require that contributors [sign their commits](https://git-scm.com/docs/git-commit) using `git commit -s` or `git commit --signoff` to
|
|
||||||
certify they either authored the work themselves or otherwise have permission to use it in this project. Please see https://developercertificate.org/ for
|
|
||||||
more info, as well as to make sure that you can attest to the rules listed. Our CI uses the [DCO Github app](https://github.com/apps/dco) to ensure
|
|
||||||
that all commits in a given PR are signed-off.
|
|
||||||
|
|
||||||
## Code of Conduct
|
|
||||||
|
|
||||||
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
|
|
||||||
For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
|
|
||||||
contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
|
|
||||||
|
|
||||||
## Dependencies
|
|
||||||
|
|
||||||
This project requires Golang 1.17 or newer to build.
|
|
||||||
|
|
||||||
For system requirements to run this project, see the Microsoft docs on [Windows Container requirements](https://docs.microsoft.com/en-us/virtualization/windowscontainers/deploy-containers/system-requirements).
|
|
||||||
|
|
||||||
## Reporting Security Issues
|
|
||||||
|
|
||||||
Security issues and bugs should be reported privately, via email, to the Microsoft Security
|
|
||||||
Response Center (MSRC) at [secure@microsoft.com](mailto:secure@microsoft.com). You should
|
|
||||||
receive a response within 24 hours. If for some reason you do not, please follow up via
|
|
||||||
email to ensure we received your original message. Further information, including the
|
|
||||||
[MSRC PGP](https://technet.microsoft.com/en-us/security/dn606155) key, can be found in
|
|
||||||
the [Security TechCenter](https://technet.microsoft.com/en-us/security/default).
|
|
||||||
|
|
||||||
For additional details, see [Report a Computer Security Vulnerability](https://technet.microsoft.com/en-us/security/ff852094.aspx) on Technet
|
|
||||||
|
|
||||||
---------------
|
|
||||||
Copyright (c) 2018 Microsoft Corp. All rights reserved.
|
|
@ -1,41 +0,0 @@
|
|||||||
<!-- BEGIN MICROSOFT SECURITY.MD V0.0.7 BLOCK -->
|
|
||||||
|
|
||||||
## Security
|
|
||||||
|
|
||||||
Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/).
|
|
||||||
|
|
||||||
If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below.
|
|
||||||
|
|
||||||
## Reporting Security Issues
|
|
||||||
|
|
||||||
**Please do not report security vulnerabilities through public GitHub issues.**
|
|
||||||
|
|
||||||
Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report).
|
|
||||||
|
|
||||||
If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey).
|
|
||||||
|
|
||||||
You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc).
|
|
||||||
|
|
||||||
Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
|
|
||||||
|
|
||||||
* Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
|
|
||||||
* Full paths of source file(s) related to the manifestation of the issue
|
|
||||||
* The location of the affected source code (tag/branch/commit or direct URL)
|
|
||||||
* Any special configuration required to reproduce the issue
|
|
||||||
* Step-by-step instructions to reproduce the issue
|
|
||||||
* Proof-of-concept or exploit code (if possible)
|
|
||||||
* Impact of the issue, including how an attacker might exploit the issue
|
|
||||||
|
|
||||||
This information will help us triage your report more quickly.
|
|
||||||
|
|
||||||
If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs.
|
|
||||||
|
|
||||||
## Preferred Languages
|
|
||||||
|
|
||||||
We prefer all communications to be in English.
|
|
||||||
|
|
||||||
## Policy
|
|
||||||
|
|
||||||
Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd).
|
|
||||||
|
|
||||||
<!-- END MICROSOFT SECURITY.MD BLOCK -->
|
|
@ -1,40 +0,0 @@
|
|||||||
//go:build windows
|
|
||||||
|
|
||||||
package computestorage
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
|
|
||||||
"github.com/Microsoft/hcsshim/internal/oc"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"go.opencensus.io/trace"
|
|
||||||
)
|
|
||||||
|
|
||||||
// AttachLayerStorageFilter sets up the layer storage filter on a writable
|
|
||||||
// container layer.
|
|
||||||
//
|
|
||||||
// `layerPath` is a path to a directory the writable layer is mounted. If the
|
|
||||||
// path does not end in a `\` the platform will append it automatically.
|
|
||||||
//
|
|
||||||
// `layerData` is the parent read-only layer data.
|
|
||||||
func AttachLayerStorageFilter(ctx context.Context, layerPath string, layerData LayerData) (err error) {
|
|
||||||
title := "hcsshim::AttachLayerStorageFilter"
|
|
||||||
ctx, span := oc.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
|
|
||||||
defer span.End()
|
|
||||||
defer func() { oc.SetSpanStatus(span, err) }()
|
|
||||||
span.AddAttributes(
|
|
||||||
trace.StringAttribute("layerPath", layerPath),
|
|
||||||
)
|
|
||||||
|
|
||||||
bytes, err := json.Marshal(layerData)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = hcsAttachLayerStorageFilter(layerPath, string(bytes))
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "failed to attach layer storage filter")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
@ -1,28 +0,0 @@
|
|||||||
//go:build windows
|
|
||||||
|
|
||||||
package computestorage
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/Microsoft/hcsshim/internal/oc"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"go.opencensus.io/trace"
|
|
||||||
)
|
|
||||||
|
|
||||||
// DestroyLayer deletes a container layer.
|
|
||||||
//
|
|
||||||
// `layerPath` is a path to a directory containing the layer to export.
|
|
||||||
func DestroyLayer(ctx context.Context, layerPath string) (err error) {
|
|
||||||
title := "hcsshim::DestroyLayer"
|
|
||||||
ctx, span := oc.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
|
|
||||||
defer span.End()
|
|
||||||
defer func() { oc.SetSpanStatus(span, err) }()
|
|
||||||
span.AddAttributes(trace.StringAttribute("layerPath", layerPath))
|
|
||||||
|
|
||||||
err = hcsDestroyLayer(layerPath)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "failed to destroy layer")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
@ -1,28 +0,0 @@
|
|||||||
//go:build windows
|
|
||||||
|
|
||||||
package computestorage
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/Microsoft/hcsshim/internal/oc"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"go.opencensus.io/trace"
|
|
||||||
)
|
|
||||||
|
|
||||||
// DetachLayerStorageFilter detaches the layer storage filter on a writable container layer.
|
|
||||||
//
|
|
||||||
// `layerPath` is a path to a directory containing the layer to export.
|
|
||||||
func DetachLayerStorageFilter(ctx context.Context, layerPath string) (err error) {
|
|
||||||
title := "hcsshim::DetachLayerStorageFilter"
|
|
||||||
ctx, span := oc.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
|
|
||||||
defer span.End()
|
|
||||||
defer func() { oc.SetSpanStatus(span, err) }()
|
|
||||||
span.AddAttributes(trace.StringAttribute("layerPath", layerPath))
|
|
||||||
|
|
||||||
err = hcsDetachLayerStorageFilter(layerPath)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "failed to detach layer storage filter")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
@ -1,48 +0,0 @@
|
|||||||
//go:build windows
|
|
||||||
|
|
||||||
package computestorage
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
|
|
||||||
"github.com/Microsoft/hcsshim/internal/oc"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"go.opencensus.io/trace"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ExportLayer exports a container layer.
|
|
||||||
//
|
|
||||||
// `layerPath` is a path to a directory containing the layer to export.
|
|
||||||
//
|
|
||||||
// `exportFolderPath` is a pre-existing folder to export the layer to.
|
|
||||||
//
|
|
||||||
// `layerData` is the parent layer data.
|
|
||||||
//
|
|
||||||
// `options` are the export options applied to the exported layer.
|
|
||||||
func ExportLayer(ctx context.Context, layerPath, exportFolderPath string, layerData LayerData, options ExportLayerOptions) (err error) {
|
|
||||||
title := "hcsshim::ExportLayer"
|
|
||||||
ctx, span := oc.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
|
|
||||||
defer span.End()
|
|
||||||
defer func() { oc.SetSpanStatus(span, err) }()
|
|
||||||
span.AddAttributes(
|
|
||||||
trace.StringAttribute("layerPath", layerPath),
|
|
||||||
trace.StringAttribute("exportFolderPath", exportFolderPath),
|
|
||||||
)
|
|
||||||
|
|
||||||
ldBytes, err := json.Marshal(layerData)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
oBytes, err := json.Marshal(options)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = hcsExportLayer(layerPath, exportFolderPath, string(ldBytes), string(oBytes))
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "failed to export layer")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
@ -1,32 +0,0 @@
|
|||||||
//go:build windows
|
|
||||||
|
|
||||||
package computestorage
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/Microsoft/hcsshim/internal/oc"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"golang.org/x/sys/windows"
|
|
||||||
)
|
|
||||||
|
|
||||||
// FormatWritableLayerVhd formats a virtual disk for use as a writable container layer.
|
|
||||||
//
|
|
||||||
// If the VHD is not mounted it will be temporarily mounted.
|
|
||||||
//
|
|
||||||
// NOTE: This API had a breaking change in the operating system after Windows Server 2019.
|
|
||||||
// On ws2019 the API expects to get passed a file handle from CreateFile for the vhd that
|
|
||||||
// the caller wants to format. On > ws2019, its expected that the caller passes a vhd handle
|
|
||||||
// that can be obtained from the virtdisk APIs.
|
|
||||||
func FormatWritableLayerVhd(ctx context.Context, vhdHandle windows.Handle) (err error) {
|
|
||||||
title := "hcsshim::FormatWritableLayerVhd"
|
|
||||||
ctx, span := oc.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
|
|
||||||
defer span.End()
|
|
||||||
defer func() { oc.SetSpanStatus(span, err) }()
|
|
||||||
|
|
||||||
err = hcsFormatWritableLayerVhd(vhdHandle)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "failed to format writable layer vhd")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
@ -1,197 +0,0 @@
|
|||||||
//go:build windows
|
|
||||||
|
|
||||||
package computestorage
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"github.com/Microsoft/go-winio/vhd"
|
|
||||||
"github.com/Microsoft/hcsshim/internal/memory"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"golang.org/x/sys/windows"
|
|
||||||
|
|
||||||
"github.com/Microsoft/hcsshim/internal/security"
|
|
||||||
)
|
|
||||||
|
|
||||||
const defaultVHDXBlockSizeInMB = 1
|
|
||||||
|
|
||||||
// SetupContainerBaseLayer is a helper to setup a containers scratch. It
|
|
||||||
// will create and format the vhdx's inside and the size is configurable with the sizeInGB
|
|
||||||
// parameter.
|
|
||||||
//
|
|
||||||
// `layerPath` is the path to the base container layer on disk.
|
|
||||||
//
|
|
||||||
// `baseVhdPath` is the path to where the base vhdx for the base layer should be created.
|
|
||||||
//
|
|
||||||
// `diffVhdPath` is the path where the differencing disk for the base layer should be created.
|
|
||||||
//
|
|
||||||
// `sizeInGB` is the size in gigabytes to make the base vhdx.
|
|
||||||
func SetupContainerBaseLayer(ctx context.Context, layerPath, baseVhdPath, diffVhdPath string, sizeInGB uint64) (err error) {
|
|
||||||
var (
|
|
||||||
hivesPath = filepath.Join(layerPath, "Hives")
|
|
||||||
layoutPath = filepath.Join(layerPath, "Layout")
|
|
||||||
)
|
|
||||||
|
|
||||||
// We need to remove the hives directory and layout file as `SetupBaseOSLayer` fails if these files
|
|
||||||
// already exist. `SetupBaseOSLayer` will create these files internally. We also remove the base and
|
|
||||||
// differencing disks if they exist in case we're asking for a different size.
|
|
||||||
if _, err := os.Stat(hivesPath); err == nil {
|
|
||||||
if err := os.RemoveAll(hivesPath); err != nil {
|
|
||||||
return errors.Wrap(err, "failed to remove prexisting hives directory")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if _, err := os.Stat(layoutPath); err == nil {
|
|
||||||
if err := os.RemoveAll(layoutPath); err != nil {
|
|
||||||
return errors.Wrap(err, "failed to remove prexisting layout file")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := os.Stat(baseVhdPath); err == nil {
|
|
||||||
if err := os.RemoveAll(baseVhdPath); err != nil {
|
|
||||||
return errors.Wrap(err, "failed to remove base vhdx path")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if _, err := os.Stat(diffVhdPath); err == nil {
|
|
||||||
if err := os.RemoveAll(diffVhdPath); err != nil {
|
|
||||||
return errors.Wrap(err, "failed to remove differencing vhdx")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
createParams := &vhd.CreateVirtualDiskParameters{
|
|
||||||
Version: 2,
|
|
||||||
Version2: vhd.CreateVersion2{
|
|
||||||
MaximumSize: sizeInGB * memory.GiB,
|
|
||||||
BlockSizeInBytes: defaultVHDXBlockSizeInMB * memory.MiB,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
handle, err := vhd.CreateVirtualDisk(baseVhdPath, vhd.VirtualDiskAccessNone, vhd.CreateVirtualDiskFlagNone, createParams)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "failed to create vhdx")
|
|
||||||
}
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
if err != nil {
|
|
||||||
_ = syscall.CloseHandle(handle)
|
|
||||||
os.RemoveAll(baseVhdPath)
|
|
||||||
os.RemoveAll(diffVhdPath)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
if err = FormatWritableLayerVhd(ctx, windows.Handle(handle)); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// Base vhd handle must be closed before calling SetupBaseLayer in case of Container layer
|
|
||||||
if err = syscall.CloseHandle(handle); err != nil {
|
|
||||||
return errors.Wrap(err, "failed to close vhdx handle")
|
|
||||||
}
|
|
||||||
|
|
||||||
options := OsLayerOptions{
|
|
||||||
Type: OsLayerTypeContainer,
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetupBaseOSLayer expects an empty vhd handle for a container layer and will
|
|
||||||
// error out otherwise.
|
|
||||||
if err = SetupBaseOSLayer(ctx, layerPath, 0, options); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// Create the differencing disk that will be what's copied for the final rw layer
|
|
||||||
// for a container.
|
|
||||||
if err = vhd.CreateDiffVhd(diffVhdPath, baseVhdPath, defaultVHDXBlockSizeInMB); err != nil {
|
|
||||||
return errors.Wrap(err, "failed to create differencing disk")
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = security.GrantVmGroupAccess(baseVhdPath); err != nil {
|
|
||||||
return errors.Wrapf(err, "failed to grant vm group access to %s", baseVhdPath)
|
|
||||||
}
|
|
||||||
if err = security.GrantVmGroupAccess(diffVhdPath); err != nil {
|
|
||||||
return errors.Wrapf(err, "failed to grant vm group access to %s", diffVhdPath)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetupUtilityVMBaseLayer is a helper to setup a UVMs scratch space. It will create and format
|
|
||||||
// the vhdx inside and the size is configurable by the sizeInGB parameter.
|
|
||||||
//
|
|
||||||
// `uvmPath` is the path to the UtilityVM filesystem.
|
|
||||||
//
|
|
||||||
// `baseVhdPath` is the path to where the base vhdx for the UVM should be created.
|
|
||||||
//
|
|
||||||
// `diffVhdPath` is the path where the differencing disk for the UVM should be created.
|
|
||||||
//
|
|
||||||
// `sizeInGB` specifies the size in gigabytes to make the base vhdx.
|
|
||||||
func SetupUtilityVMBaseLayer(ctx context.Context, uvmPath, baseVhdPath, diffVhdPath string, sizeInGB uint64) (err error) {
|
|
||||||
// Remove the base and differencing disks if they exist in case we're asking for a different size.
|
|
||||||
if _, err := os.Stat(baseVhdPath); err == nil {
|
|
||||||
if err := os.RemoveAll(baseVhdPath); err != nil {
|
|
||||||
return errors.Wrap(err, "failed to remove base vhdx")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if _, err := os.Stat(diffVhdPath); err == nil {
|
|
||||||
if err := os.RemoveAll(diffVhdPath); err != nil {
|
|
||||||
return errors.Wrap(err, "failed to remove differencing vhdx")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Just create the vhdx for utilityVM layer, no need to format it.
|
|
||||||
createParams := &vhd.CreateVirtualDiskParameters{
|
|
||||||
Version: 2,
|
|
||||||
Version2: vhd.CreateVersion2{
|
|
||||||
MaximumSize: sizeInGB * memory.GiB,
|
|
||||||
BlockSizeInBytes: defaultVHDXBlockSizeInMB * memory.MiB,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
handle, err := vhd.CreateVirtualDisk(baseVhdPath, vhd.VirtualDiskAccessNone, vhd.CreateVirtualDiskFlagNone, createParams)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "failed to create vhdx")
|
|
||||||
}
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
if err != nil {
|
|
||||||
_ = syscall.CloseHandle(handle)
|
|
||||||
os.RemoveAll(baseVhdPath)
|
|
||||||
os.RemoveAll(diffVhdPath)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
// If it is a UtilityVM layer then the base vhdx must be attached when calling
|
|
||||||
// `SetupBaseOSLayer`
|
|
||||||
attachParams := &vhd.AttachVirtualDiskParameters{
|
|
||||||
Version: 2,
|
|
||||||
}
|
|
||||||
if err := vhd.AttachVirtualDisk(handle, vhd.AttachVirtualDiskFlagNone, attachParams); err != nil {
|
|
||||||
return errors.Wrapf(err, "failed to attach virtual disk")
|
|
||||||
}
|
|
||||||
|
|
||||||
options := OsLayerOptions{
|
|
||||||
Type: OsLayerTypeVM,
|
|
||||||
}
|
|
||||||
if err := SetupBaseOSLayer(ctx, uvmPath, windows.Handle(handle), options); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Detach and close the handle after setting up the layer as we don't need the handle
|
|
||||||
// for anything else and we no longer need to be attached either.
|
|
||||||
if err = vhd.DetachVirtualDisk(handle); err != nil {
|
|
||||||
return errors.Wrap(err, "failed to detach vhdx")
|
|
||||||
}
|
|
||||||
if err = syscall.CloseHandle(handle); err != nil {
|
|
||||||
return errors.Wrap(err, "failed to close vhdx handle")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the differencing disk that will be what's copied for the final rw layer
|
|
||||||
// for a container.
|
|
||||||
if err = vhd.CreateDiffVhd(diffVhdPath, baseVhdPath, defaultVHDXBlockSizeInMB); err != nil {
|
|
||||||
return errors.Wrap(err, "failed to create differencing disk")
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := security.GrantVmGroupAccess(baseVhdPath); err != nil {
|
|
||||||
return errors.Wrapf(err, "failed to grant vm group access to %s", baseVhdPath)
|
|
||||||
}
|
|
||||||
if err := security.GrantVmGroupAccess(diffVhdPath); err != nil {
|
|
||||||
return errors.Wrapf(err, "failed to grant vm group access to %s", diffVhdPath)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
@ -1,43 +0,0 @@
|
|||||||
//go:build windows
|
|
||||||
|
|
||||||
package computestorage
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
|
|
||||||
"github.com/Microsoft/hcsshim/internal/oc"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"go.opencensus.io/trace"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ImportLayer imports a container layer.
|
|
||||||
//
|
|
||||||
// `layerPath` is a path to a directory to import the layer to. If the directory
|
|
||||||
// does not exist it will be automatically created.
|
|
||||||
//
|
|
||||||
// `sourceFolderpath` is a pre-existing folder that contains the layer to
|
|
||||||
// import.
|
|
||||||
//
|
|
||||||
// `layerData` is the parent layer data.
|
|
||||||
func ImportLayer(ctx context.Context, layerPath, sourceFolderPath string, layerData LayerData) (err error) {
|
|
||||||
title := "hcsshim::ImportLayer"
|
|
||||||
ctx, span := oc.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
|
|
||||||
defer span.End()
|
|
||||||
defer func() { oc.SetSpanStatus(span, err) }()
|
|
||||||
span.AddAttributes(
|
|
||||||
trace.StringAttribute("layerPath", layerPath),
|
|
||||||
trace.StringAttribute("sourceFolderPath", sourceFolderPath),
|
|
||||||
)
|
|
||||||
|
|
||||||
bytes, err := json.Marshal(layerData)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = hcsImportLayer(layerPath, sourceFolderPath, string(bytes))
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "failed to import layer")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
@ -1,40 +0,0 @@
|
|||||||
//go:build windows
|
|
||||||
|
|
||||||
package computestorage
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
|
|
||||||
"github.com/Microsoft/hcsshim/internal/oc"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"go.opencensus.io/trace"
|
|
||||||
)
|
|
||||||
|
|
||||||
// InitializeWritableLayer initializes a writable layer for a container.
|
|
||||||
//
|
|
||||||
// `layerPath` is a path to a directory the layer is mounted. If the
|
|
||||||
// path does not end in a `\` the platform will append it automatically.
|
|
||||||
//
|
|
||||||
// `layerData` is the parent read-only layer data.
|
|
||||||
func InitializeWritableLayer(ctx context.Context, layerPath string, layerData LayerData) (err error) {
|
|
||||||
title := "hcsshim::InitializeWritableLayer"
|
|
||||||
ctx, span := oc.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
|
|
||||||
defer span.End()
|
|
||||||
defer func() { oc.SetSpanStatus(span, err) }()
|
|
||||||
span.AddAttributes(
|
|
||||||
trace.StringAttribute("layerPath", layerPath),
|
|
||||||
)
|
|
||||||
|
|
||||||
bytes, err := json.Marshal(layerData)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Options are not used in the platform as of RS5
|
|
||||||
err = hcsInitializeWritableLayer(layerPath, string(bytes), "")
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "failed to intitialize container layer")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
@ -1,28 +0,0 @@
|
|||||||
//go:build windows
|
|
||||||
|
|
||||||
package computestorage
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/Microsoft/hcsshim/internal/interop"
|
|
||||||
"github.com/Microsoft/hcsshim/internal/oc"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"golang.org/x/sys/windows"
|
|
||||||
)
|
|
||||||
|
|
||||||
// GetLayerVhdMountPath returns the volume path for a virtual disk of a writable container layer.
|
|
||||||
func GetLayerVhdMountPath(ctx context.Context, vhdHandle windows.Handle) (path string, err error) {
|
|
||||||
title := "hcsshim::GetLayerVhdMountPath"
|
|
||||||
ctx, span := oc.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
|
|
||||||
defer span.End()
|
|
||||||
defer func() { oc.SetSpanStatus(span, err) }()
|
|
||||||
|
|
||||||
var mountPath *uint16
|
|
||||||
err = hcsGetLayerVhdMountPath(vhdHandle, &mountPath)
|
|
||||||
if err != nil {
|
|
||||||
return "", errors.Wrap(err, "failed to get vhd mount path")
|
|
||||||
}
|
|
||||||
path = interop.ConvertAndFreeCoTaskMemString(mountPath)
|
|
||||||
return path, nil
|
|
||||||
}
|
|
@ -1,80 +0,0 @@
|
|||||||
//go:build windows
|
|
||||||
|
|
||||||
package computestorage
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
|
|
||||||
"github.com/Microsoft/hcsshim/internal/oc"
|
|
||||||
"github.com/Microsoft/hcsshim/osversion"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"go.opencensus.io/trace"
|
|
||||||
"golang.org/x/sys/windows"
|
|
||||||
)
|
|
||||||
|
|
||||||
// SetupBaseOSLayer sets up a layer that contains a base OS for a container.
|
|
||||||
//
|
|
||||||
// `layerPath` is a path to a directory containing the layer.
|
|
||||||
//
|
|
||||||
// `vhdHandle` is an empty file handle of `options.Type == OsLayerTypeContainer`
|
|
||||||
// or else it is a file handle to the 'SystemTemplateBase.vhdx' if `options.Type
|
|
||||||
// == OsLayerTypeVm`.
|
|
||||||
//
|
|
||||||
// `options` are the options applied while processing the layer.
|
|
||||||
func SetupBaseOSLayer(ctx context.Context, layerPath string, vhdHandle windows.Handle, options OsLayerOptions) (err error) {
|
|
||||||
title := "hcsshim::SetupBaseOSLayer"
|
|
||||||
ctx, span := oc.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
|
|
||||||
defer span.End()
|
|
||||||
defer func() { oc.SetSpanStatus(span, err) }()
|
|
||||||
span.AddAttributes(
|
|
||||||
trace.StringAttribute("layerPath", layerPath),
|
|
||||||
)
|
|
||||||
|
|
||||||
bytes, err := json.Marshal(options)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = hcsSetupBaseOSLayer(layerPath, vhdHandle, string(bytes))
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "failed to setup base OS layer")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetupBaseOSVolume sets up a volume that contains a base OS for a container.
|
|
||||||
//
|
|
||||||
// `layerPath` is a path to a directory containing the layer.
|
|
||||||
//
|
|
||||||
// `volumePath` is the path to the volume to be used for setup.
|
|
||||||
//
|
|
||||||
// `options` are the options applied while processing the layer.
|
|
||||||
//
|
|
||||||
// NOTE: This API is only available on builds of Windows greater than 19645. Inside we
|
|
||||||
// check if the hosts build has the API available by using 'GetVersion' which requires
|
|
||||||
// the calling application to be manifested. https://docs.microsoft.com/en-us/windows/win32/sbscs/manifests
|
|
||||||
func SetupBaseOSVolume(ctx context.Context, layerPath, volumePath string, options OsLayerOptions) (err error) {
|
|
||||||
if osversion.Build() < 19645 {
|
|
||||||
return errors.New("SetupBaseOSVolume is not present on builds older than 19645")
|
|
||||||
}
|
|
||||||
title := "hcsshim::SetupBaseOSVolume"
|
|
||||||
ctx, span := oc.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
|
|
||||||
defer span.End()
|
|
||||||
defer func() { oc.SetSpanStatus(span, err) }()
|
|
||||||
span.AddAttributes(
|
|
||||||
trace.StringAttribute("layerPath", layerPath),
|
|
||||||
trace.StringAttribute("volumePath", volumePath),
|
|
||||||
)
|
|
||||||
|
|
||||||
bytes, err := json.Marshal(options)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = hcsSetupBaseOSVolume(layerPath, volumePath, string(bytes))
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "failed to setup base OS layer")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
@ -1,53 +0,0 @@
|
|||||||
// Package computestorage is a wrapper around the HCS storage APIs. These are new storage APIs introduced
|
|
||||||
// separate from the original graphdriver calls intended to give more freedom around creating
|
|
||||||
// and managing container layers and scratch spaces.
|
|
||||||
package computestorage
|
|
||||||
|
|
||||||
import (
|
|
||||||
hcsschema "github.com/Microsoft/hcsshim/internal/hcs/schema2"
|
|
||||||
)
|
|
||||||
|
|
||||||
//go:generate go run github.com/Microsoft/go-winio/tools/mkwinsyscall -output zsyscall_windows.go storage.go
|
|
||||||
|
|
||||||
//sys hcsImportLayer(layerPath string, sourceFolderPath string, layerData string) (hr error) = computestorage.HcsImportLayer?
|
|
||||||
//sys hcsExportLayer(layerPath string, exportFolderPath string, layerData string, options string) (hr error) = computestorage.HcsExportLayer?
|
|
||||||
//sys hcsDestroyLayer(layerPath string) (hr error) = computestorage.HcsDestoryLayer?
|
|
||||||
//sys hcsSetupBaseOSLayer(layerPath string, handle windows.Handle, options string) (hr error) = computestorage.HcsSetupBaseOSLayer?
|
|
||||||
//sys hcsInitializeWritableLayer(writableLayerPath string, layerData string, options string) (hr error) = computestorage.HcsInitializeWritableLayer?
|
|
||||||
//sys hcsAttachLayerStorageFilter(layerPath string, layerData string) (hr error) = computestorage.HcsAttachLayerStorageFilter?
|
|
||||||
//sys hcsDetachLayerStorageFilter(layerPath string) (hr error) = computestorage.HcsDetachLayerStorageFilter?
|
|
||||||
//sys hcsFormatWritableLayerVhd(handle windows.Handle) (hr error) = computestorage.HcsFormatWritableLayerVhd?
|
|
||||||
//sys hcsGetLayerVhdMountPath(vhdHandle windows.Handle, mountPath **uint16) (hr error) = computestorage.HcsGetLayerVhdMountPath?
|
|
||||||
//sys hcsSetupBaseOSVolume(layerPath string, volumePath string, options string) (hr error) = computestorage.HcsSetupBaseOSVolume?
|
|
||||||
|
|
||||||
type Version = hcsschema.Version
|
|
||||||
type Layer = hcsschema.Layer
|
|
||||||
|
|
||||||
// LayerData is the data used to describe parent layer information.
|
|
||||||
type LayerData struct {
|
|
||||||
SchemaVersion Version `json:"SchemaVersion,omitempty"`
|
|
||||||
Layers []Layer `json:"Layers,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExportLayerOptions are the set of options that are used with the `computestorage.HcsExportLayer` syscall.
|
|
||||||
type ExportLayerOptions struct {
|
|
||||||
IsWritableLayer bool `json:"IsWritableLayer,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// OsLayerType is the type of layer being operated on.
|
|
||||||
type OsLayerType string
|
|
||||||
|
|
||||||
const (
|
|
||||||
// OsLayerTypeContainer is a container layer.
|
|
||||||
OsLayerTypeContainer OsLayerType = "Container"
|
|
||||||
// OsLayerTypeVM is a virtual machine layer.
|
|
||||||
OsLayerTypeVM OsLayerType = "Vm"
|
|
||||||
)
|
|
||||||
|
|
||||||
// OsLayerOptions are the set of options that are used with the `SetupBaseOSLayer` and
|
|
||||||
// `SetupBaseOSVolume` calls.
|
|
||||||
type OsLayerOptions struct {
|
|
||||||
Type OsLayerType `json:"Type,omitempty"`
|
|
||||||
DisableCiCacheOptimization bool `json:"DisableCiCacheOptimization,omitempty"`
|
|
||||||
SkipUpdateBcdForBoot bool `json:"SkipUpdateBcdForBoot,omitempty"`
|
|
||||||
}
|
|
@ -1,332 +0,0 @@
|
|||||||
//go:build windows
|
|
||||||
|
|
||||||
// Code generated by 'go generate' using "github.com/Microsoft/go-winio/tools/mkwinsyscall"; DO NOT EDIT.
|
|
||||||
|
|
||||||
package computestorage
|
|
||||||
|
|
||||||
import (
|
|
||||||
"syscall"
|
|
||||||
"unsafe"
|
|
||||||
|
|
||||||
"golang.org/x/sys/windows"
|
|
||||||
)
|
|
||||||
|
|
||||||
var _ unsafe.Pointer
|
|
||||||
|
|
||||||
// Do the interface allocations only once for common
|
|
||||||
// Errno values.
|
|
||||||
const (
|
|
||||||
errnoERROR_IO_PENDING = 997
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
|
|
||||||
errERROR_EINVAL error = syscall.EINVAL
|
|
||||||
)
|
|
||||||
|
|
||||||
// errnoErr returns common boxed Errno values, to prevent
|
|
||||||
// allocations at runtime.
|
|
||||||
func errnoErr(e syscall.Errno) error {
|
|
||||||
switch e {
|
|
||||||
case 0:
|
|
||||||
return errERROR_EINVAL
|
|
||||||
case errnoERROR_IO_PENDING:
|
|
||||||
return errERROR_IO_PENDING
|
|
||||||
}
|
|
||||||
// TODO: add more here, after collecting data on the common
|
|
||||||
// error values see on Windows. (perhaps when running
|
|
||||||
// all.bat?)
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
modcomputestorage = windows.NewLazySystemDLL("computestorage.dll")
|
|
||||||
|
|
||||||
procHcsAttachLayerStorageFilter = modcomputestorage.NewProc("HcsAttachLayerStorageFilter")
|
|
||||||
procHcsDestoryLayer = modcomputestorage.NewProc("HcsDestoryLayer")
|
|
||||||
procHcsDetachLayerStorageFilter = modcomputestorage.NewProc("HcsDetachLayerStorageFilter")
|
|
||||||
procHcsExportLayer = modcomputestorage.NewProc("HcsExportLayer")
|
|
||||||
procHcsFormatWritableLayerVhd = modcomputestorage.NewProc("HcsFormatWritableLayerVhd")
|
|
||||||
procHcsGetLayerVhdMountPath = modcomputestorage.NewProc("HcsGetLayerVhdMountPath")
|
|
||||||
procHcsImportLayer = modcomputestorage.NewProc("HcsImportLayer")
|
|
||||||
procHcsInitializeWritableLayer = modcomputestorage.NewProc("HcsInitializeWritableLayer")
|
|
||||||
procHcsSetupBaseOSLayer = modcomputestorage.NewProc("HcsSetupBaseOSLayer")
|
|
||||||
procHcsSetupBaseOSVolume = modcomputestorage.NewProc("HcsSetupBaseOSVolume")
|
|
||||||
)
|
|
||||||
|
|
||||||
func hcsAttachLayerStorageFilter(layerPath string, layerData string) (hr error) {
|
|
||||||
var _p0 *uint16
|
|
||||||
_p0, hr = syscall.UTF16PtrFromString(layerPath)
|
|
||||||
if hr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var _p1 *uint16
|
|
||||||
_p1, hr = syscall.UTF16PtrFromString(layerData)
|
|
||||||
if hr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return _hcsAttachLayerStorageFilter(_p0, _p1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func _hcsAttachLayerStorageFilter(layerPath *uint16, layerData *uint16) (hr error) {
|
|
||||||
hr = procHcsAttachLayerStorageFilter.Find()
|
|
||||||
if hr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
r0, _, _ := syscall.Syscall(procHcsAttachLayerStorageFilter.Addr(), 2, uintptr(unsafe.Pointer(layerPath)), uintptr(unsafe.Pointer(layerData)), 0)
|
|
||||||
if int32(r0) < 0 {
|
|
||||||
if r0&0x1fff0000 == 0x00070000 {
|
|
||||||
r0 &= 0xffff
|
|
||||||
}
|
|
||||||
hr = syscall.Errno(r0)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func hcsDestroyLayer(layerPath string) (hr error) {
|
|
||||||
var _p0 *uint16
|
|
||||||
_p0, hr = syscall.UTF16PtrFromString(layerPath)
|
|
||||||
if hr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return _hcsDestroyLayer(_p0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func _hcsDestroyLayer(layerPath *uint16) (hr error) {
|
|
||||||
hr = procHcsDestoryLayer.Find()
|
|
||||||
if hr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
r0, _, _ := syscall.Syscall(procHcsDestoryLayer.Addr(), 1, uintptr(unsafe.Pointer(layerPath)), 0, 0)
|
|
||||||
if int32(r0) < 0 {
|
|
||||||
if r0&0x1fff0000 == 0x00070000 {
|
|
||||||
r0 &= 0xffff
|
|
||||||
}
|
|
||||||
hr = syscall.Errno(r0)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func hcsDetachLayerStorageFilter(layerPath string) (hr error) {
|
|
||||||
var _p0 *uint16
|
|
||||||
_p0, hr = syscall.UTF16PtrFromString(layerPath)
|
|
||||||
if hr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return _hcsDetachLayerStorageFilter(_p0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func _hcsDetachLayerStorageFilter(layerPath *uint16) (hr error) {
|
|
||||||
hr = procHcsDetachLayerStorageFilter.Find()
|
|
||||||
if hr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
r0, _, _ := syscall.Syscall(procHcsDetachLayerStorageFilter.Addr(), 1, uintptr(unsafe.Pointer(layerPath)), 0, 0)
|
|
||||||
if int32(r0) < 0 {
|
|
||||||
if r0&0x1fff0000 == 0x00070000 {
|
|
||||||
r0 &= 0xffff
|
|
||||||
}
|
|
||||||
hr = syscall.Errno(r0)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func hcsExportLayer(layerPath string, exportFolderPath string, layerData string, options string) (hr error) {
|
|
||||||
var _p0 *uint16
|
|
||||||
_p0, hr = syscall.UTF16PtrFromString(layerPath)
|
|
||||||
if hr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var _p1 *uint16
|
|
||||||
_p1, hr = syscall.UTF16PtrFromString(exportFolderPath)
|
|
||||||
if hr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var _p2 *uint16
|
|
||||||
_p2, hr = syscall.UTF16PtrFromString(layerData)
|
|
||||||
if hr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var _p3 *uint16
|
|
||||||
_p3, hr = syscall.UTF16PtrFromString(options)
|
|
||||||
if hr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return _hcsExportLayer(_p0, _p1, _p2, _p3)
|
|
||||||
}
|
|
||||||
|
|
||||||
func _hcsExportLayer(layerPath *uint16, exportFolderPath *uint16, layerData *uint16, options *uint16) (hr error) {
|
|
||||||
hr = procHcsExportLayer.Find()
|
|
||||||
if hr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
r0, _, _ := syscall.Syscall6(procHcsExportLayer.Addr(), 4, uintptr(unsafe.Pointer(layerPath)), uintptr(unsafe.Pointer(exportFolderPath)), uintptr(unsafe.Pointer(layerData)), uintptr(unsafe.Pointer(options)), 0, 0)
|
|
||||||
if int32(r0) < 0 {
|
|
||||||
if r0&0x1fff0000 == 0x00070000 {
|
|
||||||
r0 &= 0xffff
|
|
||||||
}
|
|
||||||
hr = syscall.Errno(r0)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func hcsFormatWritableLayerVhd(handle windows.Handle) (hr error) {
|
|
||||||
hr = procHcsFormatWritableLayerVhd.Find()
|
|
||||||
if hr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
r0, _, _ := syscall.Syscall(procHcsFormatWritableLayerVhd.Addr(), 1, uintptr(handle), 0, 0)
|
|
||||||
if int32(r0) < 0 {
|
|
||||||
if r0&0x1fff0000 == 0x00070000 {
|
|
||||||
r0 &= 0xffff
|
|
||||||
}
|
|
||||||
hr = syscall.Errno(r0)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func hcsGetLayerVhdMountPath(vhdHandle windows.Handle, mountPath **uint16) (hr error) {
|
|
||||||
hr = procHcsGetLayerVhdMountPath.Find()
|
|
||||||
if hr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
r0, _, _ := syscall.Syscall(procHcsGetLayerVhdMountPath.Addr(), 2, uintptr(vhdHandle), uintptr(unsafe.Pointer(mountPath)), 0)
|
|
||||||
if int32(r0) < 0 {
|
|
||||||
if r0&0x1fff0000 == 0x00070000 {
|
|
||||||
r0 &= 0xffff
|
|
||||||
}
|
|
||||||
hr = syscall.Errno(r0)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func hcsImportLayer(layerPath string, sourceFolderPath string, layerData string) (hr error) {
|
|
||||||
var _p0 *uint16
|
|
||||||
_p0, hr = syscall.UTF16PtrFromString(layerPath)
|
|
||||||
if hr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var _p1 *uint16
|
|
||||||
_p1, hr = syscall.UTF16PtrFromString(sourceFolderPath)
|
|
||||||
if hr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var _p2 *uint16
|
|
||||||
_p2, hr = syscall.UTF16PtrFromString(layerData)
|
|
||||||
if hr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return _hcsImportLayer(_p0, _p1, _p2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func _hcsImportLayer(layerPath *uint16, sourceFolderPath *uint16, layerData *uint16) (hr error) {
|
|
||||||
hr = procHcsImportLayer.Find()
|
|
||||||
if hr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
r0, _, _ := syscall.Syscall(procHcsImportLayer.Addr(), 3, uintptr(unsafe.Pointer(layerPath)), uintptr(unsafe.Pointer(sourceFolderPath)), uintptr(unsafe.Pointer(layerData)))
|
|
||||||
if int32(r0) < 0 {
|
|
||||||
if r0&0x1fff0000 == 0x00070000 {
|
|
||||||
r0 &= 0xffff
|
|
||||||
}
|
|
||||||
hr = syscall.Errno(r0)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func hcsInitializeWritableLayer(writableLayerPath string, layerData string, options string) (hr error) {
|
|
||||||
var _p0 *uint16
|
|
||||||
_p0, hr = syscall.UTF16PtrFromString(writableLayerPath)
|
|
||||||
if hr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var _p1 *uint16
|
|
||||||
_p1, hr = syscall.UTF16PtrFromString(layerData)
|
|
||||||
if hr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var _p2 *uint16
|
|
||||||
_p2, hr = syscall.UTF16PtrFromString(options)
|
|
||||||
if hr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return _hcsInitializeWritableLayer(_p0, _p1, _p2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func _hcsInitializeWritableLayer(writableLayerPath *uint16, layerData *uint16, options *uint16) (hr error) {
|
|
||||||
hr = procHcsInitializeWritableLayer.Find()
|
|
||||||
if hr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
r0, _, _ := syscall.Syscall(procHcsInitializeWritableLayer.Addr(), 3, uintptr(unsafe.Pointer(writableLayerPath)), uintptr(unsafe.Pointer(layerData)), uintptr(unsafe.Pointer(options)))
|
|
||||||
if int32(r0) < 0 {
|
|
||||||
if r0&0x1fff0000 == 0x00070000 {
|
|
||||||
r0 &= 0xffff
|
|
||||||
}
|
|
||||||
hr = syscall.Errno(r0)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func hcsSetupBaseOSLayer(layerPath string, handle windows.Handle, options string) (hr error) {
|
|
||||||
var _p0 *uint16
|
|
||||||
_p0, hr = syscall.UTF16PtrFromString(layerPath)
|
|
||||||
if hr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var _p1 *uint16
|
|
||||||
_p1, hr = syscall.UTF16PtrFromString(options)
|
|
||||||
if hr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return _hcsSetupBaseOSLayer(_p0, handle, _p1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func _hcsSetupBaseOSLayer(layerPath *uint16, handle windows.Handle, options *uint16) (hr error) {
|
|
||||||
hr = procHcsSetupBaseOSLayer.Find()
|
|
||||||
if hr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
r0, _, _ := syscall.Syscall(procHcsSetupBaseOSLayer.Addr(), 3, uintptr(unsafe.Pointer(layerPath)), uintptr(handle), uintptr(unsafe.Pointer(options)))
|
|
||||||
if int32(r0) < 0 {
|
|
||||||
if r0&0x1fff0000 == 0x00070000 {
|
|
||||||
r0 &= 0xffff
|
|
||||||
}
|
|
||||||
hr = syscall.Errno(r0)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func hcsSetupBaseOSVolume(layerPath string, volumePath string, options string) (hr error) {
|
|
||||||
var _p0 *uint16
|
|
||||||
_p0, hr = syscall.UTF16PtrFromString(layerPath)
|
|
||||||
if hr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var _p1 *uint16
|
|
||||||
_p1, hr = syscall.UTF16PtrFromString(volumePath)
|
|
||||||
if hr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var _p2 *uint16
|
|
||||||
_p2, hr = syscall.UTF16PtrFromString(options)
|
|
||||||
if hr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return _hcsSetupBaseOSVolume(_p0, _p1, _p2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func _hcsSetupBaseOSVolume(layerPath *uint16, volumePath *uint16, options *uint16) (hr error) {
|
|
||||||
hr = procHcsSetupBaseOSVolume.Find()
|
|
||||||
if hr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
r0, _, _ := syscall.Syscall(procHcsSetupBaseOSVolume.Addr(), 3, uintptr(unsafe.Pointer(layerPath)), uintptr(unsafe.Pointer(volumePath)), uintptr(unsafe.Pointer(options)))
|
|
||||||
if int32(r0) < 0 {
|
|
||||||
if r0&0x1fff0000 == 0x00070000 {
|
|
||||||
r0 &= 0xffff
|
|
||||||
}
|
|
||||||
hr = syscall.Errno(r0)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
@ -1,225 +0,0 @@
|
|||||||
//go:build windows
|
|
||||||
|
|
||||||
package hcsshim
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/Microsoft/hcsshim/internal/hcs"
|
|
||||||
"github.com/Microsoft/hcsshim/internal/hcs/schema1"
|
|
||||||
"github.com/Microsoft/hcsshim/internal/mergemaps"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ContainerProperties holds the properties for a container and the processes running in that container
|
|
||||||
type ContainerProperties = schema1.ContainerProperties
|
|
||||||
|
|
||||||
// MemoryStats holds the memory statistics for a container
|
|
||||||
type MemoryStats = schema1.MemoryStats
|
|
||||||
|
|
||||||
// ProcessorStats holds the processor statistics for a container
|
|
||||||
type ProcessorStats = schema1.ProcessorStats
|
|
||||||
|
|
||||||
// StorageStats holds the storage statistics for a container
|
|
||||||
type StorageStats = schema1.StorageStats
|
|
||||||
|
|
||||||
// NetworkStats holds the network statistics for a container
|
|
||||||
type NetworkStats = schema1.NetworkStats
|
|
||||||
|
|
||||||
// Statistics is the structure returned by a statistics call on a container
|
|
||||||
type Statistics = schema1.Statistics
|
|
||||||
|
|
||||||
// ProcessList is the structure of an item returned by a ProcessList call on a container
|
|
||||||
type ProcessListItem = schema1.ProcessListItem
|
|
||||||
|
|
||||||
// MappedVirtualDiskController is the structure of an item returned by a MappedVirtualDiskList call on a container
|
|
||||||
type MappedVirtualDiskController = schema1.MappedVirtualDiskController
|
|
||||||
|
|
||||||
// Type of Request Support in ModifySystem
|
|
||||||
type RequestType = schema1.RequestType
|
|
||||||
|
|
||||||
// Type of Resource Support in ModifySystem
|
|
||||||
type ResourceType = schema1.ResourceType
|
|
||||||
|
|
||||||
// RequestType const
|
|
||||||
const (
|
|
||||||
Add = schema1.Add
|
|
||||||
Remove = schema1.Remove
|
|
||||||
Network = schema1.Network
|
|
||||||
)
|
|
||||||
|
|
||||||
// ResourceModificationRequestResponse is the structure used to send request to the container to modify the system
|
|
||||||
// Supported resource types are Network and Request Types are Add/Remove
|
|
||||||
type ResourceModificationRequestResponse = schema1.ResourceModificationRequestResponse
|
|
||||||
|
|
||||||
type container struct {
|
|
||||||
system *hcs.System
|
|
||||||
waitOnce sync.Once
|
|
||||||
waitErr error
|
|
||||||
waitCh chan struct{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// createContainerAdditionalJSON is read from the environment at initialization
|
|
||||||
// time. It allows an environment variable to define additional JSON which
|
|
||||||
// is merged in the CreateComputeSystem call to HCS.
|
|
||||||
var createContainerAdditionalJSON []byte
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
createContainerAdditionalJSON = ([]byte)(os.Getenv("HCSSHIM_CREATECONTAINER_ADDITIONALJSON"))
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateContainer creates a new container with the given configuration but does not start it.
|
|
||||||
func CreateContainer(id string, c *ContainerConfig) (Container, error) {
|
|
||||||
fullConfig, err := mergemaps.MergeJSON(c, createContainerAdditionalJSON)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to merge additional JSON '%s': %s", createContainerAdditionalJSON, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
system, err := hcs.CreateComputeSystem(context.Background(), id, fullConfig)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &container{system: system}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// OpenContainer opens an existing container by ID.
|
|
||||||
func OpenContainer(id string) (Container, error) {
|
|
||||||
system, err := hcs.OpenComputeSystem(context.Background(), id)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &container{system: system}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetContainers gets a list of the containers on the system that match the query
|
|
||||||
func GetContainers(q ComputeSystemQuery) ([]ContainerProperties, error) {
|
|
||||||
return hcs.GetComputeSystems(context.Background(), q)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start synchronously starts the container.
|
|
||||||
func (container *container) Start() error {
|
|
||||||
return convertSystemError(container.system.Start(context.Background()), container)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Shutdown requests a container shutdown, but it may not actually be shutdown until Wait() succeeds.
|
|
||||||
func (container *container) Shutdown() error {
|
|
||||||
err := container.system.Shutdown(context.Background())
|
|
||||||
if err != nil {
|
|
||||||
return convertSystemError(err, container)
|
|
||||||
}
|
|
||||||
return &ContainerError{Container: container, Err: ErrVmcomputeOperationPending, Operation: "hcsshim::ComputeSystem::Shutdown"}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Terminate requests a container terminate, but it may not actually be terminated until Wait() succeeds.
|
|
||||||
func (container *container) Terminate() error {
|
|
||||||
err := container.system.Terminate(context.Background())
|
|
||||||
if err != nil {
|
|
||||||
return convertSystemError(err, container)
|
|
||||||
}
|
|
||||||
return &ContainerError{Container: container, Err: ErrVmcomputeOperationPending, Operation: "hcsshim::ComputeSystem::Terminate"}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Waits synchronously waits for the container to shutdown or terminate.
|
|
||||||
func (container *container) Wait() error {
|
|
||||||
err := container.system.Wait()
|
|
||||||
if err == nil {
|
|
||||||
err = container.system.ExitError()
|
|
||||||
}
|
|
||||||
return convertSystemError(err, container)
|
|
||||||
}
|
|
||||||
|
|
||||||
// WaitTimeout synchronously waits for the container to terminate or the duration to elapse. It
|
|
||||||
// returns false if timeout occurs.
|
|
||||||
func (container *container) WaitTimeout(timeout time.Duration) error {
|
|
||||||
container.waitOnce.Do(func() {
|
|
||||||
container.waitCh = make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
container.waitErr = container.Wait()
|
|
||||||
close(container.waitCh)
|
|
||||||
}()
|
|
||||||
})
|
|
||||||
t := time.NewTimer(timeout)
|
|
||||||
defer t.Stop()
|
|
||||||
select {
|
|
||||||
case <-t.C:
|
|
||||||
return &ContainerError{Container: container, Err: ErrTimeout, Operation: "hcsshim::ComputeSystem::Wait"}
|
|
||||||
case <-container.waitCh:
|
|
||||||
return container.waitErr
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pause pauses the execution of a container.
|
|
||||||
func (container *container) Pause() error {
|
|
||||||
return convertSystemError(container.system.Pause(context.Background()), container)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Resume resumes the execution of a container.
|
|
||||||
func (container *container) Resume() error {
|
|
||||||
return convertSystemError(container.system.Resume(context.Background()), container)
|
|
||||||
}
|
|
||||||
|
|
||||||
// HasPendingUpdates returns true if the container has updates pending to install
|
|
||||||
func (container *container) HasPendingUpdates() (bool, error) {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Statistics returns statistics for the container. This is a legacy v1 call
|
|
||||||
func (container *container) Statistics() (Statistics, error) {
|
|
||||||
properties, err := container.system.Properties(context.Background(), schema1.PropertyTypeStatistics)
|
|
||||||
if err != nil {
|
|
||||||
return Statistics{}, convertSystemError(err, container)
|
|
||||||
}
|
|
||||||
|
|
||||||
return properties.Statistics, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ProcessList returns an array of ProcessListItems for the container. This is a legacy v1 call
|
|
||||||
func (container *container) ProcessList() ([]ProcessListItem, error) {
|
|
||||||
properties, err := container.system.Properties(context.Background(), schema1.PropertyTypeProcessList)
|
|
||||||
if err != nil {
|
|
||||||
return nil, convertSystemError(err, container)
|
|
||||||
}
|
|
||||||
|
|
||||||
return properties.ProcessList, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is a legacy v1 call
|
|
||||||
func (container *container) MappedVirtualDisks() (map[int]MappedVirtualDiskController, error) {
|
|
||||||
properties, err := container.system.Properties(context.Background(), schema1.PropertyTypeMappedVirtualDisk)
|
|
||||||
if err != nil {
|
|
||||||
return nil, convertSystemError(err, container)
|
|
||||||
}
|
|
||||||
|
|
||||||
return properties.MappedVirtualDiskControllers, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateProcess launches a new process within the container.
|
|
||||||
func (container *container) CreateProcess(c *ProcessConfig) (Process, error) {
|
|
||||||
p, err := container.system.CreateProcess(context.Background(), c)
|
|
||||||
if err != nil {
|
|
||||||
return nil, convertSystemError(err, container)
|
|
||||||
}
|
|
||||||
return &process{p: p.(*hcs.Process)}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// OpenProcess gets an interface to an existing process within the container.
|
|
||||||
func (container *container) OpenProcess(pid int) (Process, error) {
|
|
||||||
p, err := container.system.OpenProcess(context.Background(), pid)
|
|
||||||
if err != nil {
|
|
||||||
return nil, convertSystemError(err, container)
|
|
||||||
}
|
|
||||||
return &process{p: p}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close cleans up any state associated with the container but does not terminate or wait for it.
|
|
||||||
func (container *container) Close() error {
|
|
||||||
return convertSystemError(container.system.Close(), container)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Modify the System
|
|
||||||
func (container *container) Modify(config *ResourceModificationRequestResponse) error {
|
|
||||||
return convertSystemError(container.system.Modify(context.Background(), config), container)
|
|
||||||
}
|
|
@ -1,250 +0,0 @@
|
|||||||
//go:build windows
|
|
||||||
|
|
||||||
package hcsshim
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"github.com/Microsoft/hcsshim/internal/hns"
|
|
||||||
|
|
||||||
"github.com/Microsoft/hcsshim/internal/hcs"
|
|
||||||
"github.com/Microsoft/hcsshim/internal/hcserror"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// ErrComputeSystemDoesNotExist is an error encountered when the container being operated on no longer exists = hcs.exist
|
|
||||||
ErrComputeSystemDoesNotExist = hcs.ErrComputeSystemDoesNotExist
|
|
||||||
|
|
||||||
// ErrElementNotFound is an error encountered when the object being referenced does not exist
|
|
||||||
ErrElementNotFound = hcs.ErrElementNotFound
|
|
||||||
|
|
||||||
// ErrElementNotFound is an error encountered when the object being referenced does not exist
|
|
||||||
ErrNotSupported = hcs.ErrNotSupported
|
|
||||||
|
|
||||||
// ErrInvalidData is an error encountered when the request being sent to hcs is invalid/unsupported
|
|
||||||
// decimal -2147024883 / hex 0x8007000d
|
|
||||||
ErrInvalidData = hcs.ErrInvalidData
|
|
||||||
|
|
||||||
// ErrHandleClose is an error encountered when the handle generating the notification being waited on has been closed
|
|
||||||
ErrHandleClose = hcs.ErrHandleClose
|
|
||||||
|
|
||||||
// ErrAlreadyClosed is an error encountered when using a handle that has been closed by the Close method
|
|
||||||
ErrAlreadyClosed = hcs.ErrAlreadyClosed
|
|
||||||
|
|
||||||
// ErrInvalidNotificationType is an error encountered when an invalid notification type is used
|
|
||||||
ErrInvalidNotificationType = hcs.ErrInvalidNotificationType
|
|
||||||
|
|
||||||
// ErrInvalidProcessState is an error encountered when the process is not in a valid state for the requested operation
|
|
||||||
ErrInvalidProcessState = hcs.ErrInvalidProcessState
|
|
||||||
|
|
||||||
// ErrTimeout is an error encountered when waiting on a notification times out
|
|
||||||
ErrTimeout = hcs.ErrTimeout
|
|
||||||
|
|
||||||
// ErrUnexpectedContainerExit is the error encountered when a container exits while waiting for
|
|
||||||
// a different expected notification
|
|
||||||
ErrUnexpectedContainerExit = hcs.ErrUnexpectedContainerExit
|
|
||||||
|
|
||||||
// ErrUnexpectedProcessAbort is the error encountered when communication with the compute service
|
|
||||||
// is lost while waiting for a notification
|
|
||||||
ErrUnexpectedProcessAbort = hcs.ErrUnexpectedProcessAbort
|
|
||||||
|
|
||||||
// ErrUnexpectedValue is an error encountered when hcs returns an invalid value
|
|
||||||
ErrUnexpectedValue = hcs.ErrUnexpectedValue
|
|
||||||
|
|
||||||
// ErrOperationDenied is an error when hcs attempts an operation that is explicitly denied
|
|
||||||
ErrOperationDenied = hcs.ErrOperationDenied
|
|
||||||
|
|
||||||
// ErrVmcomputeAlreadyStopped is an error encountered when a shutdown or terminate request is made on a stopped container
|
|
||||||
ErrVmcomputeAlreadyStopped = hcs.ErrVmcomputeAlreadyStopped
|
|
||||||
|
|
||||||
// ErrVmcomputeOperationPending is an error encountered when the operation is being completed asynchronously
|
|
||||||
ErrVmcomputeOperationPending = hcs.ErrVmcomputeOperationPending
|
|
||||||
|
|
||||||
// ErrVmcomputeOperationInvalidState is an error encountered when the compute system is not in a valid state for the requested operation
|
|
||||||
ErrVmcomputeOperationInvalidState = hcs.ErrVmcomputeOperationInvalidState
|
|
||||||
|
|
||||||
// ErrProcNotFound is an error encountered when a procedure look up fails.
|
|
||||||
ErrProcNotFound = hcs.ErrProcNotFound
|
|
||||||
|
|
||||||
// ErrVmcomputeOperationAccessIsDenied is an error which can be encountered when enumerating compute systems in RS1/RS2
|
|
||||||
// builds when the underlying silo might be in the process of terminating. HCS was fixed in RS3.
|
|
||||||
ErrVmcomputeOperationAccessIsDenied = hcs.ErrVmcomputeOperationAccessIsDenied
|
|
||||||
|
|
||||||
// ErrVmcomputeInvalidJSON is an error encountered when the compute system does not support/understand the messages sent by management
|
|
||||||
ErrVmcomputeInvalidJSON = hcs.ErrVmcomputeInvalidJSON
|
|
||||||
|
|
||||||
// ErrVmcomputeUnknownMessage is an error encountered guest compute system doesn't support the message
|
|
||||||
ErrVmcomputeUnknownMessage = hcs.ErrVmcomputeUnknownMessage
|
|
||||||
|
|
||||||
// ErrNotSupported is an error encountered when hcs doesn't support the request
|
|
||||||
ErrPlatformNotSupported = hcs.ErrPlatformNotSupported
|
|
||||||
)
|
|
||||||
|
|
||||||
type EndpointNotFoundError = hns.EndpointNotFoundError
|
|
||||||
type NetworkNotFoundError = hns.NetworkNotFoundError
|
|
||||||
|
|
||||||
// ProcessError is an error encountered in HCS during an operation on a Process object
|
|
||||||
type ProcessError struct {
|
|
||||||
Process *process
|
|
||||||
Operation string
|
|
||||||
Err error
|
|
||||||
Events []hcs.ErrorEvent
|
|
||||||
}
|
|
||||||
|
|
||||||
// ContainerError is an error encountered in HCS during an operation on a Container object
|
|
||||||
type ContainerError struct {
|
|
||||||
Container *container
|
|
||||||
Operation string
|
|
||||||
Err error
|
|
||||||
Events []hcs.ErrorEvent
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *ContainerError) Error() string {
|
|
||||||
if e == nil {
|
|
||||||
return "<nil>"
|
|
||||||
}
|
|
||||||
|
|
||||||
if e.Container == nil {
|
|
||||||
return "unexpected nil container for error: " + e.Err.Error()
|
|
||||||
}
|
|
||||||
|
|
||||||
s := "container " + e.Container.system.ID()
|
|
||||||
|
|
||||||
if e.Operation != "" {
|
|
||||||
s += " encountered an error during " + e.Operation
|
|
||||||
}
|
|
||||||
|
|
||||||
switch e.Err.(type) {
|
|
||||||
case nil:
|
|
||||||
break
|
|
||||||
case syscall.Errno:
|
|
||||||
s += fmt.Sprintf(": failure in a Windows system call: %s (0x%x)", e.Err, hcserror.Win32FromError(e.Err))
|
|
||||||
default:
|
|
||||||
s += fmt.Sprintf(": %s", e.Err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, ev := range e.Events {
|
|
||||||
s += "\n" + ev.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *ProcessError) Error() string {
|
|
||||||
if e == nil {
|
|
||||||
return "<nil>"
|
|
||||||
}
|
|
||||||
|
|
||||||
if e.Process == nil {
|
|
||||||
return "Unexpected nil process for error: " + e.Err.Error()
|
|
||||||
}
|
|
||||||
|
|
||||||
s := fmt.Sprintf("process %d in container %s", e.Process.p.Pid(), e.Process.p.SystemID())
|
|
||||||
if e.Operation != "" {
|
|
||||||
s += " encountered an error during " + e.Operation
|
|
||||||
}
|
|
||||||
|
|
||||||
switch e.Err.(type) {
|
|
||||||
case nil:
|
|
||||||
break
|
|
||||||
case syscall.Errno:
|
|
||||||
s += fmt.Sprintf(": failure in a Windows system call: %s (0x%x)", e.Err, hcserror.Win32FromError(e.Err))
|
|
||||||
default:
|
|
||||||
s += fmt.Sprintf(": %s", e.Err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, ev := range e.Events {
|
|
||||||
s += "\n" + ev.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsNotExist checks if an error is caused by the Container or Process not existing.
|
|
||||||
// Note: Currently, ErrElementNotFound can mean that a Process has either
|
|
||||||
// already exited, or does not exist. Both IsAlreadyStopped and IsNotExist
|
|
||||||
// will currently return true when the error is ErrElementNotFound.
|
|
||||||
func IsNotExist(err error) bool {
|
|
||||||
if _, ok := err.(EndpointNotFoundError); ok {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if _, ok := err.(NetworkNotFoundError); ok {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return hcs.IsNotExist(getInnerError(err))
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsAlreadyClosed checks if an error is caused by the Container or Process having been
|
|
||||||
// already closed by a call to the Close() method.
|
|
||||||
func IsAlreadyClosed(err error) bool {
|
|
||||||
return hcs.IsAlreadyClosed(getInnerError(err))
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsPending returns a boolean indicating whether the error is that
|
|
||||||
// the requested operation is being completed in the background.
|
|
||||||
func IsPending(err error) bool {
|
|
||||||
return hcs.IsPending(getInnerError(err))
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsTimeout returns a boolean indicating whether the error is caused by
|
|
||||||
// a timeout waiting for the operation to complete.
|
|
||||||
func IsTimeout(err error) bool {
|
|
||||||
return hcs.IsTimeout(getInnerError(err))
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsAlreadyStopped returns a boolean indicating whether the error is caused by
|
|
||||||
// a Container or Process being already stopped.
|
|
||||||
// Note: Currently, ErrElementNotFound can mean that a Process has either
|
|
||||||
// already exited, or does not exist. Both IsAlreadyStopped and IsNotExist
|
|
||||||
// will currently return true when the error is ErrElementNotFound.
|
|
||||||
func IsAlreadyStopped(err error) bool {
|
|
||||||
return hcs.IsAlreadyStopped(getInnerError(err))
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsNotSupported returns a boolean indicating whether the error is caused by
|
|
||||||
// unsupported platform requests
|
|
||||||
// Note: Currently Unsupported platform requests can be mean either
|
|
||||||
// ErrVmcomputeInvalidJSON, ErrInvalidData, ErrNotSupported or ErrVmcomputeUnknownMessage
|
|
||||||
// is thrown from the Platform
|
|
||||||
func IsNotSupported(err error) bool {
|
|
||||||
return hcs.IsNotSupported(getInnerError(err))
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsOperationInvalidState returns true when err is caused by
|
|
||||||
// `ErrVmcomputeOperationInvalidState`.
|
|
||||||
func IsOperationInvalidState(err error) bool {
|
|
||||||
return hcs.IsOperationInvalidState(getInnerError(err))
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsAccessIsDenied returns true when err is caused by
|
|
||||||
// `ErrVmcomputeOperationAccessIsDenied`.
|
|
||||||
func IsAccessIsDenied(err error) bool {
|
|
||||||
return hcs.IsAccessIsDenied(getInnerError(err))
|
|
||||||
}
|
|
||||||
|
|
||||||
func getInnerError(err error) error {
|
|
||||||
switch pe := err.(type) {
|
|
||||||
case nil:
|
|
||||||
return nil
|
|
||||||
case *ContainerError:
|
|
||||||
err = pe.Err
|
|
||||||
case *ProcessError:
|
|
||||||
err = pe.Err
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func convertSystemError(err error, c *container) error {
|
|
||||||
if serr, ok := err.(*hcs.SystemError); ok {
|
|
||||||
return &ContainerError{Container: c, Operation: serr.Op, Err: serr.Err, Events: serr.Events}
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func convertProcessError(err error, p *process) error {
|
|
||||||
if perr, ok := err.(*hcs.ProcessError); ok {
|
|
||||||
return &ProcessError{Process: p, Operation: perr.Op, Err: perr.Err, Events: perr.Events}
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
@ -1,30 +0,0 @@
|
|||||||
//go:build windows
|
|
||||||
|
|
||||||
// Shim for the Host Compute Service (HCS) to manage Windows Server
|
|
||||||
// containers and Hyper-V containers.
|
|
||||||
|
|
||||||
package hcsshim
|
|
||||||
|
|
||||||
import (
|
|
||||||
"golang.org/x/sys/windows"
|
|
||||||
|
|
||||||
"github.com/Microsoft/hcsshim/internal/hcserror"
|
|
||||||
)
|
|
||||||
|
|
||||||
//go:generate go run github.com/Microsoft/go-winio/tools/mkwinsyscall -output zsyscall_windows.go hcsshim.go
|
|
||||||
|
|
||||||
//sys SetCurrentThreadCompartmentId(compartmentId uint32) (hr error) = iphlpapi.SetCurrentThreadCompartmentId
|
|
||||||
|
|
||||||
const (
|
|
||||||
// Specific user-visible exit codes
|
|
||||||
WaitErrExecFailed = 32767
|
|
||||||
|
|
||||||
ERROR_GEN_FAILURE = windows.ERROR_GEN_FAILURE
|
|
||||||
ERROR_SHUTDOWN_IN_PROGRESS = windows.ERROR_SHUTDOWN_IN_PROGRESS
|
|
||||||
WSAEINVAL = windows.WSAEINVAL
|
|
||||||
|
|
||||||
// Timeout on wait calls
|
|
||||||
TimeoutInfinite = 0xFFFFFFFF
|
|
||||||
)
|
|
||||||
|
|
||||||
type HcsError = hcserror.HcsError
|
|
@ -1,120 +0,0 @@
|
|||||||
//go:build windows
|
|
||||||
|
|
||||||
package hcsshim
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/Microsoft/hcsshim/internal/hns"
|
|
||||||
)
|
|
||||||
|
|
||||||
// HNSEndpoint represents a network endpoint in HNS
|
|
||||||
type HNSEndpoint = hns.HNSEndpoint
|
|
||||||
|
|
||||||
// HNSEndpointStats represent the stats for an networkendpoint in HNS
|
|
||||||
type HNSEndpointStats = hns.EndpointStats
|
|
||||||
|
|
||||||
// Namespace represents a Compartment.
|
|
||||||
type Namespace = hns.Namespace
|
|
||||||
|
|
||||||
// SystemType represents the type of the system on which actions are done
|
|
||||||
type SystemType string
|
|
||||||
|
|
||||||
// SystemType const
|
|
||||||
const (
|
|
||||||
ContainerType SystemType = "Container"
|
|
||||||
VirtualMachineType SystemType = "VirtualMachine"
|
|
||||||
HostType SystemType = "Host"
|
|
||||||
)
|
|
||||||
|
|
||||||
// EndpointAttachDetachRequest is the structure used to send request to the container to modify the system
|
|
||||||
// Supported resource types are Network and Request Types are Add/Remove
|
|
||||||
type EndpointAttachDetachRequest = hns.EndpointAttachDetachRequest
|
|
||||||
|
|
||||||
// EndpointResquestResponse is object to get the endpoint request response
|
|
||||||
type EndpointResquestResponse = hns.EndpointResquestResponse
|
|
||||||
|
|
||||||
// HNSEndpointRequest makes a HNS call to modify/query a network endpoint
|
|
||||||
func HNSEndpointRequest(method, path, request string) (*HNSEndpoint, error) {
|
|
||||||
return hns.HNSEndpointRequest(method, path, request)
|
|
||||||
}
|
|
||||||
|
|
||||||
// HNSListEndpointRequest makes a HNS call to query the list of available endpoints
|
|
||||||
func HNSListEndpointRequest() ([]HNSEndpoint, error) {
|
|
||||||
return hns.HNSListEndpointRequest()
|
|
||||||
}
|
|
||||||
|
|
||||||
// HotAttachEndpoint makes a HCS Call to attach the endpoint to the container
|
|
||||||
func HotAttachEndpoint(containerID string, endpointID string) error {
|
|
||||||
endpoint, err := GetHNSEndpointByID(endpointID)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
isAttached, err := endpoint.IsAttached(containerID)
|
|
||||||
if isAttached {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return modifyNetworkEndpoint(containerID, endpointID, Add)
|
|
||||||
}
|
|
||||||
|
|
||||||
// HotDetachEndpoint makes a HCS Call to detach the endpoint from the container
|
|
||||||
func HotDetachEndpoint(containerID string, endpointID string) error {
|
|
||||||
endpoint, err := GetHNSEndpointByID(endpointID)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
isAttached, err := endpoint.IsAttached(containerID)
|
|
||||||
if !isAttached {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return modifyNetworkEndpoint(containerID, endpointID, Remove)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ModifyContainer corresponding to the container id, by sending a request
|
|
||||||
func modifyContainer(id string, request *ResourceModificationRequestResponse) error {
|
|
||||||
container, err := OpenContainer(id)
|
|
||||||
if err != nil {
|
|
||||||
if IsNotExist(err) {
|
|
||||||
return ErrComputeSystemDoesNotExist
|
|
||||||
}
|
|
||||||
return getInnerError(err)
|
|
||||||
}
|
|
||||||
defer container.Close()
|
|
||||||
err = container.Modify(request)
|
|
||||||
if err != nil {
|
|
||||||
if IsNotSupported(err) {
|
|
||||||
return ErrPlatformNotSupported
|
|
||||||
}
|
|
||||||
return getInnerError(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func modifyNetworkEndpoint(containerID string, endpointID string, request RequestType) error {
|
|
||||||
requestMessage := &ResourceModificationRequestResponse{
|
|
||||||
Resource: Network,
|
|
||||||
Request: request,
|
|
||||||
Data: endpointID,
|
|
||||||
}
|
|
||||||
err := modifyContainer(containerID, requestMessage)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetHNSEndpointByID get the Endpoint by ID
|
|
||||||
func GetHNSEndpointByID(endpointID string) (*HNSEndpoint, error) {
|
|
||||||
return hns.GetHNSEndpointByID(endpointID)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetHNSEndpointByName gets the endpoint filtered by Name
|
|
||||||
func GetHNSEndpointByName(endpointName string) (*HNSEndpoint, error) {
|
|
||||||
return hns.GetHNSEndpointByName(endpointName)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetHNSEndpointStats gets the endpoint stats by ID
|
|
||||||
func GetHNSEndpointStats(endpointName string) (*HNSEndpointStats, error) {
|
|
||||||
return hns.GetHNSEndpointStats(endpointName)
|
|
||||||
}
|
|
@ -1,18 +0,0 @@
|
|||||||
//go:build windows
|
|
||||||
|
|
||||||
package hcsshim
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/Microsoft/hcsshim/internal/hns"
|
|
||||||
)
|
|
||||||
|
|
||||||
type HNSGlobals = hns.HNSGlobals
|
|
||||||
type HNSVersion = hns.HNSVersion
|
|
||||||
|
|
||||||
var (
|
|
||||||
HNSVersion1803 = hns.HNSVersion1803
|
|
||||||
)
|
|
||||||
|
|
||||||
func GetHNSGlobals() (*HNSGlobals, error) {
|
|
||||||
return hns.GetHNSGlobals()
|
|
||||||
}
|
|
@ -1,38 +0,0 @@
|
|||||||
//go:build windows
|
|
||||||
|
|
||||||
package hcsshim
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/Microsoft/hcsshim/internal/hns"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Subnet is associated with a network and represents a list
|
|
||||||
// of subnets available to the network
|
|
||||||
type Subnet = hns.Subnet
|
|
||||||
|
|
||||||
// MacPool is associated with a network and represents a list
|
|
||||||
// of macaddresses available to the network
|
|
||||||
type MacPool = hns.MacPool
|
|
||||||
|
|
||||||
// HNSNetwork represents a network in HNS
|
|
||||||
type HNSNetwork = hns.HNSNetwork
|
|
||||||
|
|
||||||
// HNSNetworkRequest makes a call into HNS to update/query a single network
|
|
||||||
func HNSNetworkRequest(method, path, request string) (*HNSNetwork, error) {
|
|
||||||
return hns.HNSNetworkRequest(method, path, request)
|
|
||||||
}
|
|
||||||
|
|
||||||
// HNSListNetworkRequest makes a HNS call to query the list of available networks
|
|
||||||
func HNSListNetworkRequest(method, path, request string) ([]HNSNetwork, error) {
|
|
||||||
return hns.HNSListNetworkRequest(method, path, request)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetHNSNetworkByID
|
|
||||||
func GetHNSNetworkByID(networkID string) (*HNSNetwork, error) {
|
|
||||||
return hns.GetHNSNetworkByID(networkID)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetHNSNetworkName filtered by Name
|
|
||||||
func GetHNSNetworkByName(networkName string) (*HNSNetwork, error) {
|
|
||||||
return hns.GetHNSNetworkByName(networkName)
|
|
||||||
}
|
|
@ -1,60 +0,0 @@
|
|||||||
package hcsshim
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/Microsoft/hcsshim/internal/hns"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Type of Request Support in ModifySystem
|
|
||||||
type PolicyType = hns.PolicyType
|
|
||||||
|
|
||||||
// RequestType const
|
|
||||||
const (
|
|
||||||
Nat = hns.Nat
|
|
||||||
ACL = hns.ACL
|
|
||||||
PA = hns.PA
|
|
||||||
VLAN = hns.VLAN
|
|
||||||
VSID = hns.VSID
|
|
||||||
VNet = hns.VNet
|
|
||||||
L2Driver = hns.L2Driver
|
|
||||||
Isolation = hns.Isolation
|
|
||||||
QOS = hns.QOS
|
|
||||||
OutboundNat = hns.OutboundNat
|
|
||||||
ExternalLoadBalancer = hns.ExternalLoadBalancer
|
|
||||||
Route = hns.Route
|
|
||||||
Proxy = hns.Proxy
|
|
||||||
)
|
|
||||||
|
|
||||||
type ProxyPolicy = hns.ProxyPolicy
|
|
||||||
|
|
||||||
type NatPolicy = hns.NatPolicy
|
|
||||||
|
|
||||||
type QosPolicy = hns.QosPolicy
|
|
||||||
|
|
||||||
type IsolationPolicy = hns.IsolationPolicy
|
|
||||||
|
|
||||||
type VlanPolicy = hns.VlanPolicy
|
|
||||||
|
|
||||||
type VsidPolicy = hns.VsidPolicy
|
|
||||||
|
|
||||||
type PaPolicy = hns.PaPolicy
|
|
||||||
|
|
||||||
type OutboundNatPolicy = hns.OutboundNatPolicy
|
|
||||||
|
|
||||||
type ActionType = hns.ActionType
|
|
||||||
type DirectionType = hns.DirectionType
|
|
||||||
type RuleType = hns.RuleType
|
|
||||||
|
|
||||||
const (
|
|
||||||
Allow = hns.Allow
|
|
||||||
Block = hns.Block
|
|
||||||
|
|
||||||
In = hns.In
|
|
||||||
Out = hns.Out
|
|
||||||
|
|
||||||
Host = hns.Host
|
|
||||||
Switch = hns.Switch
|
|
||||||
)
|
|
||||||
|
|
||||||
type ACLPolicy = hns.ACLPolicy
|
|
||||||
|
|
||||||
type Policy = hns.Policy
|
|
@ -1,49 +0,0 @@
|
|||||||
//go:build windows
|
|
||||||
|
|
||||||
package hcsshim
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/Microsoft/hcsshim/internal/hns"
|
|
||||||
)
|
|
||||||
|
|
||||||
// RoutePolicy is a structure defining schema for Route based Policy
|
|
||||||
type RoutePolicy = hns.RoutePolicy
|
|
||||||
|
|
||||||
// ELBPolicy is a structure defining schema for ELB LoadBalancing based Policy
|
|
||||||
type ELBPolicy = hns.ELBPolicy
|
|
||||||
|
|
||||||
// LBPolicy is a structure defining schema for LoadBalancing based Policy
|
|
||||||
type LBPolicy = hns.LBPolicy
|
|
||||||
|
|
||||||
// PolicyList is a structure defining schema for Policy list request
|
|
||||||
type PolicyList = hns.PolicyList
|
|
||||||
|
|
||||||
// HNSPolicyListRequest makes a call into HNS to update/query a single network
|
|
||||||
func HNSPolicyListRequest(method, path, request string) (*PolicyList, error) {
|
|
||||||
return hns.HNSPolicyListRequest(method, path, request)
|
|
||||||
}
|
|
||||||
|
|
||||||
// HNSListPolicyListRequest gets all the policy list
|
|
||||||
func HNSListPolicyListRequest() ([]PolicyList, error) {
|
|
||||||
return hns.HNSListPolicyListRequest()
|
|
||||||
}
|
|
||||||
|
|
||||||
// PolicyListRequest makes a HNS call to modify/query a network policy list
|
|
||||||
func PolicyListRequest(method, path, request string) (*PolicyList, error) {
|
|
||||||
return hns.PolicyListRequest(method, path, request)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetPolicyListByID get the policy list by ID
|
|
||||||
func GetPolicyListByID(policyListID string) (*PolicyList, error) {
|
|
||||||
return hns.GetPolicyListByID(policyListID)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddLoadBalancer policy list for the specified endpoints
|
|
||||||
func AddLoadBalancer(endpoints []HNSEndpoint, isILB bool, sourceVIP, vip string, protocol uint16, internalPort uint16, externalPort uint16) (*PolicyList, error) {
|
|
||||||
return hns.AddLoadBalancer(endpoints, isILB, sourceVIP, vip, protocol, internalPort, externalPort)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddRoute adds route policy list for the specified endpoints
|
|
||||||
func AddRoute(endpoints []HNSEndpoint, destinationPrefix string, nextHop string, encapEnabled bool) (*PolicyList, error) {
|
|
||||||
return hns.AddRoute(endpoints, destinationPrefix, nextHop, encapEnabled)
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
//go:build windows
|
|
||||||
|
|
||||||
package hcsshim
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/Microsoft/hcsshim/internal/hns"
|
|
||||||
)
|
|
||||||
|
|
||||||
type HNSSupportedFeatures = hns.HNSSupportedFeatures
|
|
||||||
|
|
||||||
type HNSAclFeatures = hns.HNSAclFeatures
|
|
||||||
|
|
||||||
func GetHNSSupportedFeatures() HNSSupportedFeatures {
|
|
||||||
return hns.GetHNSSupportedFeatures()
|
|
||||||
}
|
|
@ -1,116 +0,0 @@
|
|||||||
//go:build windows
|
|
||||||
|
|
||||||
package hcsshim
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/Microsoft/hcsshim/internal/hcs/schema1"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ProcessConfig is used as both the input of Container.CreateProcess
|
|
||||||
// and to convert the parameters to JSON for passing onto the HCS
|
|
||||||
type ProcessConfig = schema1.ProcessConfig
|
|
||||||
|
|
||||||
type Layer = schema1.Layer
|
|
||||||
type MappedDir = schema1.MappedDir
|
|
||||||
type MappedPipe = schema1.MappedPipe
|
|
||||||
type HvRuntime = schema1.HvRuntime
|
|
||||||
type MappedVirtualDisk = schema1.MappedVirtualDisk
|
|
||||||
|
|
||||||
// AssignedDevice represents a device that has been directly assigned to a container
|
|
||||||
//
|
|
||||||
// NOTE: Support added in RS5
|
|
||||||
type AssignedDevice = schema1.AssignedDevice
|
|
||||||
|
|
||||||
// ContainerConfig is used as both the input of CreateContainer
|
|
||||||
// and to convert the parameters to JSON for passing onto the HCS
|
|
||||||
type ContainerConfig = schema1.ContainerConfig
|
|
||||||
|
|
||||||
type ComputeSystemQuery = schema1.ComputeSystemQuery
|
|
||||||
|
|
||||||
// Container represents a created (but not necessarily running) container.
|
|
||||||
type Container interface {
|
|
||||||
// Start synchronously starts the container.
|
|
||||||
Start() error
|
|
||||||
|
|
||||||
// Shutdown requests a container shutdown, but it may not actually be shutdown until Wait() succeeds.
|
|
||||||
Shutdown() error
|
|
||||||
|
|
||||||
// Terminate requests a container terminate, but it may not actually be terminated until Wait() succeeds.
|
|
||||||
Terminate() error
|
|
||||||
|
|
||||||
// Waits synchronously waits for the container to shutdown or terminate.
|
|
||||||
Wait() error
|
|
||||||
|
|
||||||
// WaitTimeout synchronously waits for the container to terminate or the duration to elapse. It
|
|
||||||
// returns false if timeout occurs.
|
|
||||||
WaitTimeout(time.Duration) error
|
|
||||||
|
|
||||||
// Pause pauses the execution of a container.
|
|
||||||
Pause() error
|
|
||||||
|
|
||||||
// Resume resumes the execution of a container.
|
|
||||||
Resume() error
|
|
||||||
|
|
||||||
// HasPendingUpdates returns true if the container has updates pending to install.
|
|
||||||
HasPendingUpdates() (bool, error)
|
|
||||||
|
|
||||||
// Statistics returns statistics for a container.
|
|
||||||
Statistics() (Statistics, error)
|
|
||||||
|
|
||||||
// ProcessList returns details for the processes in a container.
|
|
||||||
ProcessList() ([]ProcessListItem, error)
|
|
||||||
|
|
||||||
// MappedVirtualDisks returns virtual disks mapped to a utility VM, indexed by controller
|
|
||||||
MappedVirtualDisks() (map[int]MappedVirtualDiskController, error)
|
|
||||||
|
|
||||||
// CreateProcess launches a new process within the container.
|
|
||||||
CreateProcess(c *ProcessConfig) (Process, error)
|
|
||||||
|
|
||||||
// OpenProcess gets an interface to an existing process within the container.
|
|
||||||
OpenProcess(pid int) (Process, error)
|
|
||||||
|
|
||||||
// Close cleans up any state associated with the container but does not terminate or wait for it.
|
|
||||||
Close() error
|
|
||||||
|
|
||||||
// Modify the System
|
|
||||||
Modify(config *ResourceModificationRequestResponse) error
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process represents a running or exited process.
|
|
||||||
type Process interface {
|
|
||||||
// Pid returns the process ID of the process within the container.
|
|
||||||
Pid() int
|
|
||||||
|
|
||||||
// Kill signals the process to terminate but does not wait for it to finish terminating.
|
|
||||||
Kill() error
|
|
||||||
|
|
||||||
// Wait waits for the process to exit.
|
|
||||||
Wait() error
|
|
||||||
|
|
||||||
// WaitTimeout waits for the process to exit or the duration to elapse. It returns
|
|
||||||
// false if timeout occurs.
|
|
||||||
WaitTimeout(time.Duration) error
|
|
||||||
|
|
||||||
// ExitCode returns the exit code of the process. The process must have
|
|
||||||
// already terminated.
|
|
||||||
ExitCode() (int, error)
|
|
||||||
|
|
||||||
// ResizeConsole resizes the console of the process.
|
|
||||||
ResizeConsole(width, height uint16) error
|
|
||||||
|
|
||||||
// Stdio returns the stdin, stdout, and stderr pipes, respectively. Closing
|
|
||||||
// these pipes does not close the underlying pipes; it should be possible to
|
|
||||||
// call this multiple times to get multiple interfaces.
|
|
||||||
Stdio() (io.WriteCloser, io.ReadCloser, io.ReadCloser, error)
|
|
||||||
|
|
||||||
// CloseStdin closes the write side of the stdin pipe so that the process is
|
|
||||||
// notified on the read side that there is no more data in stdin.
|
|
||||||
CloseStdin() error
|
|
||||||
|
|
||||||
// Close cleans up any state associated with the process but does not kill
|
|
||||||
// or wait on it.
|
|
||||||
Close() error
|
|
||||||
}
|
|
@ -1,99 +0,0 @@
|
|||||||
//go:build windows
|
|
||||||
|
|
||||||
package cow
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"io"
|
|
||||||
|
|
||||||
"github.com/Microsoft/hcsshim/internal/hcs/schema1"
|
|
||||||
hcsschema "github.com/Microsoft/hcsshim/internal/hcs/schema2"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Process is the interface for an OS process running in a container or utility VM.
|
|
||||||
type Process interface {
|
|
||||||
// Close releases resources associated with the process and closes the
|
|
||||||
// writer and readers returned by Stdio. Depending on the implementation,
|
|
||||||
// this may also terminate the process.
|
|
||||||
Close() error
|
|
||||||
// CloseStdin causes the process's stdin handle to receive EOF/EPIPE/whatever
|
|
||||||
// is appropriate to indicate that no more data is available.
|
|
||||||
CloseStdin(ctx context.Context) error
|
|
||||||
// CloseStdout closes the stdout connection to the process. It is used to indicate
|
|
||||||
// that we are done receiving output on the shim side.
|
|
||||||
CloseStdout(ctx context.Context) error
|
|
||||||
// CloseStderr closes the stderr connection to the process. It is used to indicate
|
|
||||||
// that we are done receiving output on the shim side.
|
|
||||||
CloseStderr(ctx context.Context) error
|
|
||||||
// Pid returns the process ID.
|
|
||||||
Pid() int
|
|
||||||
// Stdio returns the stdio streams for a process. These may be nil if a stream
|
|
||||||
// was not requested during CreateProcess.
|
|
||||||
Stdio() (_ io.Writer, _ io.Reader, _ io.Reader)
|
|
||||||
// ResizeConsole resizes the virtual terminal associated with the process.
|
|
||||||
ResizeConsole(ctx context.Context, width, height uint16) error
|
|
||||||
// Kill sends a SIGKILL or equivalent signal to the process and returns whether
|
|
||||||
// the signal was delivered. It does not wait for the process to terminate.
|
|
||||||
Kill(ctx context.Context) (bool, error)
|
|
||||||
// Signal sends a signal to the process and returns whether the signal was
|
|
||||||
// delivered. The input is OS specific (either
|
|
||||||
// guestrequest.SignalProcessOptionsWCOW or
|
|
||||||
// guestrequest.SignalProcessOptionsLCOW). It does not wait for the process
|
|
||||||
// to terminate.
|
|
||||||
Signal(ctx context.Context, options interface{}) (bool, error)
|
|
||||||
// Wait waits for the process to complete, or for a connection to the process to be
|
|
||||||
// terminated by some error condition (including calling Close).
|
|
||||||
Wait() error
|
|
||||||
// ExitCode returns the exit code of the process. Returns an error if the process is
|
|
||||||
// not running.
|
|
||||||
ExitCode() (int, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ProcessHost is the interface for creating processes.
|
|
||||||
type ProcessHost interface {
|
|
||||||
// CreateProcess creates a process. The configuration is host specific
|
|
||||||
// (either hcsschema.ProcessParameters or lcow.ProcessParameters).
|
|
||||||
CreateProcess(ctx context.Context, config interface{}) (Process, error)
|
|
||||||
// OS returns the host's operating system, "linux" or "windows".
|
|
||||||
OS() string
|
|
||||||
// IsOCI specifies whether this is an OCI-compliant process host. If true,
|
|
||||||
// then the configuration passed to CreateProcess should have an OCI process
|
|
||||||
// spec (or nil if this is the initial process in an OCI container).
|
|
||||||
// Otherwise, it should have the HCS-specific process parameters.
|
|
||||||
IsOCI() bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// Container is the interface for container objects, either running on the host or
|
|
||||||
// in a utility VM.
|
|
||||||
type Container interface {
|
|
||||||
ProcessHost
|
|
||||||
// Close releases the resources associated with the container. Depending on
|
|
||||||
// the implementation, this may also terminate the container.
|
|
||||||
Close() error
|
|
||||||
// ID returns the container ID.
|
|
||||||
ID() string
|
|
||||||
// Properties returns the requested container properties targeting a V1 schema container.
|
|
||||||
Properties(ctx context.Context, types ...schema1.PropertyType) (*schema1.ContainerProperties, error)
|
|
||||||
// PropertiesV2 returns the requested container properties targeting a V2 schema container.
|
|
||||||
PropertiesV2(ctx context.Context, types ...hcsschema.PropertyType) (*hcsschema.Properties, error)
|
|
||||||
// Start starts a container.
|
|
||||||
Start(ctx context.Context) error
|
|
||||||
// Shutdown sends a shutdown request to the container (but does not wait for
|
|
||||||
// the shutdown to complete).
|
|
||||||
Shutdown(ctx context.Context) error
|
|
||||||
// Terminate sends a terminate request to the container (but does not wait
|
|
||||||
// for the terminate to complete).
|
|
||||||
Terminate(ctx context.Context) error
|
|
||||||
// Wait waits for the container to terminate, or for the connection to the
|
|
||||||
// container to be terminated by some error condition (including calling
|
|
||||||
// Close).
|
|
||||||
Wait() error
|
|
||||||
// WaitChannel returns the wait channel of the container
|
|
||||||
WaitChannel() <-chan struct{}
|
|
||||||
// WaitError returns the container termination error.
|
|
||||||
// This function should only be called after the channel in WaitChannel()
|
|
||||||
// is closed. Otherwise it is not thread safe.
|
|
||||||
WaitError() error
|
|
||||||
// Modify sends a request to modify container resources
|
|
||||||
Modify(ctx context.Context, config interface{}) error
|
|
||||||
}
|
|
@ -1,163 +0,0 @@
|
|||||||
//go:build windows
|
|
||||||
|
|
||||||
package hcs
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"sync"
|
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"github.com/Microsoft/hcsshim/internal/interop"
|
|
||||||
"github.com/Microsoft/hcsshim/internal/logfields"
|
|
||||||
"github.com/Microsoft/hcsshim/internal/vmcompute"
|
|
||||||
"github.com/sirupsen/logrus"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
nextCallback uintptr
|
|
||||||
callbackMap = map[uintptr]*notificationWatcherContext{}
|
|
||||||
callbackMapLock = sync.RWMutex{}
|
|
||||||
|
|
||||||
notificationWatcherCallback = syscall.NewCallback(notificationWatcher)
|
|
||||||
|
|
||||||
// Notifications for HCS_SYSTEM handles
|
|
||||||
hcsNotificationSystemExited hcsNotification = 0x00000001
|
|
||||||
hcsNotificationSystemCreateCompleted hcsNotification = 0x00000002
|
|
||||||
hcsNotificationSystemStartCompleted hcsNotification = 0x00000003
|
|
||||||
hcsNotificationSystemPauseCompleted hcsNotification = 0x00000004
|
|
||||||
hcsNotificationSystemResumeCompleted hcsNotification = 0x00000005
|
|
||||||
hcsNotificationSystemCrashReport hcsNotification = 0x00000006
|
|
||||||
hcsNotificationSystemSiloJobCreated hcsNotification = 0x00000007
|
|
||||||
hcsNotificationSystemSaveCompleted hcsNotification = 0x00000008
|
|
||||||
hcsNotificationSystemRdpEnhancedModeStateChanged hcsNotification = 0x00000009
|
|
||||||
hcsNotificationSystemShutdownFailed hcsNotification = 0x0000000A
|
|
||||||
hcsNotificationSystemGetPropertiesCompleted hcsNotification = 0x0000000B
|
|
||||||
hcsNotificationSystemModifyCompleted hcsNotification = 0x0000000C
|
|
||||||
hcsNotificationSystemCrashInitiated hcsNotification = 0x0000000D
|
|
||||||
hcsNotificationSystemGuestConnectionClosed hcsNotification = 0x0000000E
|
|
||||||
|
|
||||||
// Notifications for HCS_PROCESS handles
|
|
||||||
hcsNotificationProcessExited hcsNotification = 0x00010000
|
|
||||||
|
|
||||||
// Common notifications
|
|
||||||
hcsNotificationInvalid hcsNotification = 0x00000000
|
|
||||||
hcsNotificationServiceDisconnect hcsNotification = 0x01000000
|
|
||||||
)
|
|
||||||
|
|
||||||
type hcsNotification uint32
|
|
||||||
|
|
||||||
func (hn hcsNotification) String() string {
|
|
||||||
switch hn {
|
|
||||||
case hcsNotificationSystemExited:
|
|
||||||
return "SystemExited"
|
|
||||||
case hcsNotificationSystemCreateCompleted:
|
|
||||||
return "SystemCreateCompleted"
|
|
||||||
case hcsNotificationSystemStartCompleted:
|
|
||||||
return "SystemStartCompleted"
|
|
||||||
case hcsNotificationSystemPauseCompleted:
|
|
||||||
return "SystemPauseCompleted"
|
|
||||||
case hcsNotificationSystemResumeCompleted:
|
|
||||||
return "SystemResumeCompleted"
|
|
||||||
case hcsNotificationSystemCrashReport:
|
|
||||||
return "SystemCrashReport"
|
|
||||||
case hcsNotificationSystemSiloJobCreated:
|
|
||||||
return "SystemSiloJobCreated"
|
|
||||||
case hcsNotificationSystemSaveCompleted:
|
|
||||||
return "SystemSaveCompleted"
|
|
||||||
case hcsNotificationSystemRdpEnhancedModeStateChanged:
|
|
||||||
return "SystemRdpEnhancedModeStateChanged"
|
|
||||||
case hcsNotificationSystemShutdownFailed:
|
|
||||||
return "SystemShutdownFailed"
|
|
||||||
case hcsNotificationSystemGetPropertiesCompleted:
|
|
||||||
return "SystemGetPropertiesCompleted"
|
|
||||||
case hcsNotificationSystemModifyCompleted:
|
|
||||||
return "SystemModifyCompleted"
|
|
||||||
case hcsNotificationSystemCrashInitiated:
|
|
||||||
return "SystemCrashInitiated"
|
|
||||||
case hcsNotificationSystemGuestConnectionClosed:
|
|
||||||
return "SystemGuestConnectionClosed"
|
|
||||||
case hcsNotificationProcessExited:
|
|
||||||
return "ProcessExited"
|
|
||||||
case hcsNotificationInvalid:
|
|
||||||
return "Invalid"
|
|
||||||
case hcsNotificationServiceDisconnect:
|
|
||||||
return "ServiceDisconnect"
|
|
||||||
default:
|
|
||||||
return fmt.Sprintf("Unknown: %d", hn)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type notificationChannel chan error
|
|
||||||
|
|
||||||
type notificationWatcherContext struct {
|
|
||||||
channels notificationChannels
|
|
||||||
handle vmcompute.HcsCallback
|
|
||||||
|
|
||||||
systemID string
|
|
||||||
processID int
|
|
||||||
}
|
|
||||||
|
|
||||||
type notificationChannels map[hcsNotification]notificationChannel
|
|
||||||
|
|
||||||
func newSystemChannels() notificationChannels {
|
|
||||||
channels := make(notificationChannels)
|
|
||||||
for _, notif := range []hcsNotification{
|
|
||||||
hcsNotificationServiceDisconnect,
|
|
||||||
hcsNotificationSystemExited,
|
|
||||||
hcsNotificationSystemCreateCompleted,
|
|
||||||
hcsNotificationSystemStartCompleted,
|
|
||||||
hcsNotificationSystemPauseCompleted,
|
|
||||||
hcsNotificationSystemResumeCompleted,
|
|
||||||
hcsNotificationSystemSaveCompleted,
|
|
||||||
} {
|
|
||||||
channels[notif] = make(notificationChannel, 1)
|
|
||||||
}
|
|
||||||
return channels
|
|
||||||
}
|
|
||||||
|
|
||||||
func newProcessChannels() notificationChannels {
|
|
||||||
channels := make(notificationChannels)
|
|
||||||
for _, notif := range []hcsNotification{
|
|
||||||
hcsNotificationServiceDisconnect,
|
|
||||||
hcsNotificationProcessExited,
|
|
||||||
} {
|
|
||||||
channels[notif] = make(notificationChannel, 1)
|
|
||||||
}
|
|
||||||
return channels
|
|
||||||
}
|
|
||||||
|
|
||||||
func closeChannels(channels notificationChannels) {
|
|
||||||
for _, c := range channels {
|
|
||||||
close(c)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func notificationWatcher(notificationType hcsNotification, callbackNumber uintptr, notificationStatus uintptr, notificationData *uint16) uintptr {
|
|
||||||
var result error
|
|
||||||
if int32(notificationStatus) < 0 {
|
|
||||||
result = interop.Win32FromHresult(notificationStatus)
|
|
||||||
}
|
|
||||||
|
|
||||||
callbackMapLock.RLock()
|
|
||||||
context := callbackMap[callbackNumber]
|
|
||||||
callbackMapLock.RUnlock()
|
|
||||||
|
|
||||||
if context == nil {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
log := logrus.WithFields(logrus.Fields{
|
|
||||||
"notification-type": notificationType.String(),
|
|
||||||
"system-id": context.systemID,
|
|
||||||
})
|
|
||||||
if context.processID != 0 {
|
|
||||||
log.Data[logfields.ProcessID] = context.processID
|
|
||||||
}
|
|
||||||
log.Debug("HCS notification")
|
|
||||||
|
|
||||||
if channel, ok := context.channels[notificationType]; ok {
|
|
||||||
channel <- result
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0
|
|
||||||
}
|
|
@ -1 +0,0 @@
|
|||||||
package hcs
|
|
@ -1,336 +0,0 @@
|
|||||||
//go:build windows
|
|
||||||
|
|
||||||
package hcs
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"net"
|
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"github.com/Microsoft/hcsshim/internal/log"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// ErrComputeSystemDoesNotExist is an error encountered when the container being operated on no longer exists
|
|
||||||
ErrComputeSystemDoesNotExist = syscall.Errno(0xc037010e)
|
|
||||||
|
|
||||||
// ErrElementNotFound is an error encountered when the object being referenced does not exist
|
|
||||||
ErrElementNotFound = syscall.Errno(0x490)
|
|
||||||
|
|
||||||
// ErrElementNotFound is an error encountered when the object being referenced does not exist
|
|
||||||
ErrNotSupported = syscall.Errno(0x32)
|
|
||||||
|
|
||||||
// ErrInvalidData is an error encountered when the request being sent to hcs is invalid/unsupported
|
|
||||||
// decimal -2147024883 / hex 0x8007000d
|
|
||||||
ErrInvalidData = syscall.Errno(0xd)
|
|
||||||
|
|
||||||
// ErrHandleClose is an error encountered when the handle generating the notification being waited on has been closed
|
|
||||||
ErrHandleClose = errors.New("hcsshim: the handle generating this notification has been closed")
|
|
||||||
|
|
||||||
// ErrAlreadyClosed is an error encountered when using a handle that has been closed by the Close method
|
|
||||||
ErrAlreadyClosed = errors.New("hcsshim: the handle has already been closed")
|
|
||||||
|
|
||||||
// ErrInvalidNotificationType is an error encountered when an invalid notification type is used
|
|
||||||
ErrInvalidNotificationType = errors.New("hcsshim: invalid notification type")
|
|
||||||
|
|
||||||
// ErrInvalidProcessState is an error encountered when the process is not in a valid state for the requested operation
|
|
||||||
ErrInvalidProcessState = errors.New("the process is in an invalid state for the attempted operation")
|
|
||||||
|
|
||||||
// ErrTimeout is an error encountered when waiting on a notification times out
|
|
||||||
ErrTimeout = errors.New("hcsshim: timeout waiting for notification")
|
|
||||||
|
|
||||||
// ErrUnexpectedContainerExit is the error encountered when a container exits while waiting for
|
|
||||||
// a different expected notification
|
|
||||||
ErrUnexpectedContainerExit = errors.New("unexpected container exit")
|
|
||||||
|
|
||||||
// ErrUnexpectedProcessAbort is the error encountered when communication with the compute service
|
|
||||||
// is lost while waiting for a notification
|
|
||||||
ErrUnexpectedProcessAbort = errors.New("lost communication with compute service")
|
|
||||||
|
|
||||||
// ErrUnexpectedValue is an error encountered when hcs returns an invalid value
|
|
||||||
ErrUnexpectedValue = errors.New("unexpected value returned from hcs")
|
|
||||||
|
|
||||||
// ErrOperationDenied is an error when hcs attempts an operation that is explicitly denied
|
|
||||||
ErrOperationDenied = errors.New("operation denied")
|
|
||||||
|
|
||||||
// ErrVmcomputeAlreadyStopped is an error encountered when a shutdown or terminate request is made on a stopped container
|
|
||||||
ErrVmcomputeAlreadyStopped = syscall.Errno(0xc0370110)
|
|
||||||
|
|
||||||
// ErrVmcomputeOperationPending is an error encountered when the operation is being completed asynchronously
|
|
||||||
ErrVmcomputeOperationPending = syscall.Errno(0xC0370103)
|
|
||||||
|
|
||||||
// ErrVmcomputeOperationInvalidState is an error encountered when the compute system is not in a valid state for the requested operation
|
|
||||||
ErrVmcomputeOperationInvalidState = syscall.Errno(0xc0370105)
|
|
||||||
|
|
||||||
// ErrProcNotFound is an error encountered when a procedure look up fails.
|
|
||||||
ErrProcNotFound = syscall.Errno(0x7f)
|
|
||||||
|
|
||||||
// ErrVmcomputeOperationAccessIsDenied is an error which can be encountered when enumerating compute systems in RS1/RS2
|
|
||||||
// builds when the underlying silo might be in the process of terminating. HCS was fixed in RS3.
|
|
||||||
ErrVmcomputeOperationAccessIsDenied = syscall.Errno(0x5)
|
|
||||||
|
|
||||||
// ErrVmcomputeInvalidJSON is an error encountered when the compute system does not support/understand the messages sent by management
|
|
||||||
ErrVmcomputeInvalidJSON = syscall.Errno(0xc037010d)
|
|
||||||
|
|
||||||
// ErrVmcomputeUnknownMessage is an error encountered guest compute system doesn't support the message
|
|
||||||
ErrVmcomputeUnknownMessage = syscall.Errno(0xc037010b)
|
|
||||||
|
|
||||||
// ErrVmcomputeUnexpectedExit is an error encountered when the compute system terminates unexpectedly
|
|
||||||
ErrVmcomputeUnexpectedExit = syscall.Errno(0xC0370106)
|
|
||||||
|
|
||||||
// ErrNotSupported is an error encountered when hcs doesn't support the request
|
|
||||||
ErrPlatformNotSupported = errors.New("unsupported platform request")
|
|
||||||
|
|
||||||
// ErrProcessAlreadyStopped is returned by hcs if the process we're trying to kill has already been stopped.
|
|
||||||
ErrProcessAlreadyStopped = syscall.Errno(0x8037011f)
|
|
||||||
|
|
||||||
// ErrInvalidHandle is an error that can be encountered when querying the properties of a compute system when the handle to that
|
|
||||||
// compute system has already been closed.
|
|
||||||
ErrInvalidHandle = syscall.Errno(0x6)
|
|
||||||
)
|
|
||||||
|
|
||||||
type ErrorEvent struct {
|
|
||||||
Message string `json:"Message,omitempty"` // Fully formated error message
|
|
||||||
StackTrace string `json:"StackTrace,omitempty"` // Stack trace in string form
|
|
||||||
Provider string `json:"Provider,omitempty"`
|
|
||||||
EventID uint16 `json:"EventId,omitempty"`
|
|
||||||
Flags uint32 `json:"Flags,omitempty"`
|
|
||||||
Source string `json:"Source,omitempty"`
|
|
||||||
//Data []EventData `json:"Data,omitempty"` // Omit this as HCS doesn't encode this well. It's more confusing to include. It is however logged in debug mode (see processHcsResult function)
|
|
||||||
}
|
|
||||||
|
|
||||||
type hcsResult struct {
|
|
||||||
Error int32
|
|
||||||
ErrorMessage string
|
|
||||||
ErrorEvents []ErrorEvent `json:"ErrorEvents,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ev *ErrorEvent) String() string {
|
|
||||||
evs := "[Event Detail: " + ev.Message
|
|
||||||
if ev.StackTrace != "" {
|
|
||||||
evs += " Stack Trace: " + ev.StackTrace
|
|
||||||
}
|
|
||||||
if ev.Provider != "" {
|
|
||||||
evs += " Provider: " + ev.Provider
|
|
||||||
}
|
|
||||||
if ev.EventID != 0 {
|
|
||||||
evs = fmt.Sprintf("%s EventID: %d", evs, ev.EventID)
|
|
||||||
}
|
|
||||||
if ev.Flags != 0 {
|
|
||||||
evs = fmt.Sprintf("%s flags: %d", evs, ev.Flags)
|
|
||||||
}
|
|
||||||
if ev.Source != "" {
|
|
||||||
evs += " Source: " + ev.Source
|
|
||||||
}
|
|
||||||
evs += "]"
|
|
||||||
return evs
|
|
||||||
}
|
|
||||||
|
|
||||||
func processHcsResult(ctx context.Context, resultJSON string) []ErrorEvent {
|
|
||||||
if resultJSON != "" {
|
|
||||||
result := &hcsResult{}
|
|
||||||
if err := json.Unmarshal([]byte(resultJSON), result); err != nil {
|
|
||||||
log.G(ctx).WithError(err).Warning("Could not unmarshal HCS result")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return result.ErrorEvents
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type HcsError struct {
|
|
||||||
Op string
|
|
||||||
Err error
|
|
||||||
Events []ErrorEvent
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ net.Error = &HcsError{}
|
|
||||||
|
|
||||||
func (e *HcsError) Error() string {
|
|
||||||
s := e.Op + ": " + e.Err.Error()
|
|
||||||
for _, ev := range e.Events {
|
|
||||||
s += "\n" + ev.String()
|
|
||||||
}
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *HcsError) Is(target error) bool {
|
|
||||||
return errors.Is(e.Err, target)
|
|
||||||
}
|
|
||||||
|
|
||||||
// unwrap isnt really needed, but helpful convince function
|
|
||||||
|
|
||||||
func (e *HcsError) Unwrap() error {
|
|
||||||
return e.Err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: net.Error.Temporary is deprecated.
|
|
||||||
func (e *HcsError) Temporary() bool {
|
|
||||||
err := e.netError()
|
|
||||||
return (err != nil) && err.Temporary()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *HcsError) Timeout() bool {
|
|
||||||
err := e.netError()
|
|
||||||
return (err != nil) && err.Timeout()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *HcsError) netError() (err net.Error) {
|
|
||||||
if errors.As(e.Unwrap(), &err) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SystemError is an error encountered in HCS during an operation on a Container object
|
|
||||||
type SystemError struct {
|
|
||||||
HcsError
|
|
||||||
ID string
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ net.Error = &SystemError{}
|
|
||||||
|
|
||||||
func (e *SystemError) Error() string {
|
|
||||||
s := e.Op + " " + e.ID + ": " + e.Err.Error()
|
|
||||||
for _, ev := range e.Events {
|
|
||||||
s += "\n" + ev.String()
|
|
||||||
}
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
func makeSystemError(system *System, op string, err error, events []ErrorEvent) error {
|
|
||||||
// Don't double wrap errors
|
|
||||||
var e *SystemError
|
|
||||||
if errors.As(err, &e) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &SystemError{
|
|
||||||
ID: system.ID(),
|
|
||||||
HcsError: HcsError{
|
|
||||||
Op: op,
|
|
||||||
Err: err,
|
|
||||||
Events: events,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ProcessError is an error encountered in HCS during an operation on a Process object
|
|
||||||
type ProcessError struct {
|
|
||||||
HcsError
|
|
||||||
SystemID string
|
|
||||||
Pid int
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ net.Error = &ProcessError{}
|
|
||||||
|
|
||||||
func (e *ProcessError) Error() string {
|
|
||||||
s := fmt.Sprintf("%s %s:%d: %s", e.Op, e.SystemID, e.Pid, e.Err.Error())
|
|
||||||
for _, ev := range e.Events {
|
|
||||||
s += "\n" + ev.String()
|
|
||||||
}
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
func makeProcessError(process *Process, op string, err error, events []ErrorEvent) error {
|
|
||||||
// Don't double wrap errors
|
|
||||||
var e *ProcessError
|
|
||||||
if errors.As(err, &e) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return &ProcessError{
|
|
||||||
Pid: process.Pid(),
|
|
||||||
SystemID: process.SystemID(),
|
|
||||||
HcsError: HcsError{
|
|
||||||
Op: op,
|
|
||||||
Err: err,
|
|
||||||
Events: events,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsNotExist checks if an error is caused by the Container or Process not existing.
|
|
||||||
// Note: Currently, ErrElementNotFound can mean that a Process has either
|
|
||||||
// already exited, or does not exist. Both IsAlreadyStopped and IsNotExist
|
|
||||||
// will currently return true when the error is ErrElementNotFound.
|
|
||||||
func IsNotExist(err error) bool {
|
|
||||||
return IsAny(err, ErrComputeSystemDoesNotExist, ErrElementNotFound)
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsErrorInvalidHandle checks whether the error is the result of an operation carried
|
|
||||||
// out on a handle that is invalid/closed. This error popped up while trying to query
|
|
||||||
// stats on a container in the process of being stopped.
|
|
||||||
func IsErrorInvalidHandle(err error) bool {
|
|
||||||
return errors.Is(err, ErrInvalidHandle)
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsAlreadyClosed checks if an error is caused by the Container or Process having been
|
|
||||||
// already closed by a call to the Close() method.
|
|
||||||
func IsAlreadyClosed(err error) bool {
|
|
||||||
return errors.Is(err, ErrAlreadyClosed)
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsPending returns a boolean indicating whether the error is that
|
|
||||||
// the requested operation is being completed in the background.
|
|
||||||
func IsPending(err error) bool {
|
|
||||||
return errors.Is(err, ErrVmcomputeOperationPending)
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsTimeout returns a boolean indicating whether the error is caused by
|
|
||||||
// a timeout waiting for the operation to complete.
|
|
||||||
func IsTimeout(err error) bool {
|
|
||||||
// HcsError and co. implement Timeout regardless of whether the errors they wrap do,
|
|
||||||
// so `errors.As(err, net.Error)`` will always be true.
|
|
||||||
// Using `errors.As(err.Unwrap(), net.Err)` wont work for general errors.
|
|
||||||
// So first check if there an `ErrTimeout` in the chain, then convert to a net error.
|
|
||||||
if errors.Is(err, ErrTimeout) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
var nerr net.Error
|
|
||||||
return errors.As(err, &nerr) && nerr.Timeout()
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsAlreadyStopped returns a boolean indicating whether the error is caused by
|
|
||||||
// a Container or Process being already stopped.
|
|
||||||
// Note: Currently, ErrElementNotFound can mean that a Process has either
|
|
||||||
// already exited, or does not exist. Both IsAlreadyStopped and IsNotExist
|
|
||||||
// will currently return true when the error is ErrElementNotFound.
|
|
||||||
func IsAlreadyStopped(err error) bool {
|
|
||||||
return IsAny(err, ErrVmcomputeAlreadyStopped, ErrProcessAlreadyStopped, ErrElementNotFound)
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsNotSupported returns a boolean indicating whether the error is caused by
|
|
||||||
// unsupported platform requests
|
|
||||||
// Note: Currently Unsupported platform requests can be mean either
|
|
||||||
// ErrVmcomputeInvalidJSON, ErrInvalidData, ErrNotSupported or ErrVmcomputeUnknownMessage
|
|
||||||
// is thrown from the Platform
|
|
||||||
func IsNotSupported(err error) bool {
|
|
||||||
// If Platform doesn't recognize or support the request sent, below errors are seen
|
|
||||||
return IsAny(err, ErrVmcomputeInvalidJSON, ErrInvalidData, ErrNotSupported, ErrVmcomputeUnknownMessage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsOperationInvalidState returns true when err is caused by
|
|
||||||
// `ErrVmcomputeOperationInvalidState`.
|
|
||||||
func IsOperationInvalidState(err error) bool {
|
|
||||||
return errors.Is(err, ErrVmcomputeOperationInvalidState)
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsAccessIsDenied returns true when err is caused by
|
|
||||||
// `ErrVmcomputeOperationAccessIsDenied`.
|
|
||||||
func IsAccessIsDenied(err error) bool {
|
|
||||||
return errors.Is(err, ErrVmcomputeOperationAccessIsDenied)
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsAny is a vectorized version of [errors.Is], it returns true if err is one of targets.
|
|
||||||
func IsAny(err error, targets ...error) bool {
|
|
||||||
for _, e := range targets {
|
|
||||||
if errors.Is(err, e) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
@ -1,613 +0,0 @@
|
|||||||
//go:build windows
|
|
||||||
|
|
||||||
package hcs
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"sync"
|
|
||||||
"syscall"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/Microsoft/hcsshim/internal/cow"
|
|
||||||
"github.com/Microsoft/hcsshim/internal/log"
|
|
||||||
"github.com/Microsoft/hcsshim/internal/oc"
|
|
||||||
"github.com/Microsoft/hcsshim/internal/vmcompute"
|
|
||||||
"go.opencensus.io/trace"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ContainerError is an error encountered in HCS
|
|
||||||
type Process struct {
|
|
||||||
handleLock sync.RWMutex
|
|
||||||
handle vmcompute.HcsProcess
|
|
||||||
processID int
|
|
||||||
system *System
|
|
||||||
hasCachedStdio bool
|
|
||||||
stdioLock sync.Mutex
|
|
||||||
stdin io.WriteCloser
|
|
||||||
stdout io.ReadCloser
|
|
||||||
stderr io.ReadCloser
|
|
||||||
callbackNumber uintptr
|
|
||||||
killSignalDelivered bool
|
|
||||||
|
|
||||||
closedWaitOnce sync.Once
|
|
||||||
waitBlock chan struct{}
|
|
||||||
exitCode int
|
|
||||||
waitError error
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ cow.Process = &Process{}
|
|
||||||
|
|
||||||
func newProcess(process vmcompute.HcsProcess, processID int, computeSystem *System) *Process {
|
|
||||||
return &Process{
|
|
||||||
handle: process,
|
|
||||||
processID: processID,
|
|
||||||
system: computeSystem,
|
|
||||||
waitBlock: make(chan struct{}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type processModifyRequest struct {
|
|
||||||
Operation string
|
|
||||||
ConsoleSize *consoleSize `json:",omitempty"`
|
|
||||||
CloseHandle *closeHandle `json:",omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type consoleSize struct {
|
|
||||||
Height uint16
|
|
||||||
Width uint16
|
|
||||||
}
|
|
||||||
|
|
||||||
type closeHandle struct {
|
|
||||||
Handle string
|
|
||||||
}
|
|
||||||
|
|
||||||
type processStatus struct {
|
|
||||||
ProcessID uint32
|
|
||||||
Exited bool
|
|
||||||
ExitCode uint32
|
|
||||||
LastWaitResult int32
|
|
||||||
}
|
|
||||||
|
|
||||||
const stdIn string = "StdIn"
|
|
||||||
|
|
||||||
const (
|
|
||||||
modifyConsoleSize string = "ConsoleSize"
|
|
||||||
modifyCloseHandle string = "CloseHandle"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Pid returns the process ID of the process within the container.
|
|
||||||
func (process *Process) Pid() int {
|
|
||||||
return process.processID
|
|
||||||
}
|
|
||||||
|
|
||||||
// SystemID returns the ID of the process's compute system.
|
|
||||||
func (process *Process) SystemID() string {
|
|
||||||
return process.system.ID()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (process *Process) processSignalResult(ctx context.Context, err error) (bool, error) {
|
|
||||||
switch err {
|
|
||||||
case nil:
|
|
||||||
return true, nil
|
|
||||||
case ErrVmcomputeOperationInvalidState, ErrComputeSystemDoesNotExist, ErrElementNotFound:
|
|
||||||
if !process.stopped() {
|
|
||||||
// The process should be gone, but we have not received the notification.
|
|
||||||
// After a second, force unblock the process wait to work around a possible
|
|
||||||
// deadlock in the HCS.
|
|
||||||
go func() {
|
|
||||||
time.Sleep(time.Second)
|
|
||||||
process.closedWaitOnce.Do(func() {
|
|
||||||
log.G(ctx).WithError(err).Warn("force unblocking process waits")
|
|
||||||
process.exitCode = -1
|
|
||||||
process.waitError = err
|
|
||||||
close(process.waitBlock)
|
|
||||||
})
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
return false, nil
|
|
||||||
default:
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Signal signals the process with `options`.
|
|
||||||
//
|
|
||||||
// For LCOW `guestresource.SignalProcessOptionsLCOW`.
|
|
||||||
//
|
|
||||||
// For WCOW `guestresource.SignalProcessOptionsWCOW`.
|
|
||||||
func (process *Process) Signal(ctx context.Context, options interface{}) (bool, error) {
|
|
||||||
process.handleLock.RLock()
|
|
||||||
defer process.handleLock.RUnlock()
|
|
||||||
|
|
||||||
operation := "hcs::Process::Signal"
|
|
||||||
|
|
||||||
if process.handle == 0 {
|
|
||||||
return false, makeProcessError(process, operation, ErrAlreadyClosed, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
optionsb, err := json.Marshal(options)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
resultJSON, err := vmcompute.HcsSignalProcess(ctx, process.handle, string(optionsb))
|
|
||||||
events := processHcsResult(ctx, resultJSON)
|
|
||||||
delivered, err := process.processSignalResult(ctx, err)
|
|
||||||
if err != nil {
|
|
||||||
err = makeProcessError(process, operation, err, events)
|
|
||||||
}
|
|
||||||
return delivered, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Kill signals the process to terminate but does not wait for it to finish terminating.
|
|
||||||
func (process *Process) Kill(ctx context.Context) (bool, error) {
|
|
||||||
process.handleLock.RLock()
|
|
||||||
defer process.handleLock.RUnlock()
|
|
||||||
|
|
||||||
operation := "hcs::Process::Kill"
|
|
||||||
|
|
||||||
if process.handle == 0 {
|
|
||||||
return false, makeProcessError(process, operation, ErrAlreadyClosed, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
if process.stopped() {
|
|
||||||
return false, makeProcessError(process, operation, ErrProcessAlreadyStopped, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
if process.killSignalDelivered {
|
|
||||||
// A kill signal has already been sent to this process. Sending a second
|
|
||||||
// one offers no real benefit, as processes cannot stop themselves from
|
|
||||||
// being terminated, once a TerminateProcess has been issued. Sending a
|
|
||||||
// second kill may result in a number of errors (two of which detailed bellow)
|
|
||||||
// and which we can avoid handling.
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// HCS serializes the signals sent to a target pid per compute system handle.
|
|
||||||
// To avoid SIGKILL being serialized behind other signals, we open a new compute
|
|
||||||
// system handle to deliver the kill signal.
|
|
||||||
// If the calls to opening a new compute system handle fail, we forcefully
|
|
||||||
// terminate the container itself so that no container is left behind
|
|
||||||
hcsSystem, err := OpenComputeSystem(ctx, process.system.id)
|
|
||||||
if err != nil {
|
|
||||||
// log error and force termination of container
|
|
||||||
log.G(ctx).WithField("err", err).Error("OpenComputeSystem() call failed")
|
|
||||||
err = process.system.Terminate(ctx)
|
|
||||||
// if the Terminate() call itself ever failed, log and return error
|
|
||||||
if err != nil {
|
|
||||||
log.G(ctx).WithField("err", err).Error("Terminate() call failed")
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
process.system.Close()
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
defer hcsSystem.Close()
|
|
||||||
|
|
||||||
newProcessHandle, err := hcsSystem.OpenProcess(ctx, process.Pid())
|
|
||||||
if err != nil {
|
|
||||||
// Return true only if the target process has either already
|
|
||||||
// exited, or does not exist.
|
|
||||||
if IsAlreadyStopped(err) {
|
|
||||||
return true, nil
|
|
||||||
} else {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
defer newProcessHandle.Close()
|
|
||||||
|
|
||||||
resultJSON, err := vmcompute.HcsTerminateProcess(ctx, newProcessHandle.handle)
|
|
||||||
if err != nil {
|
|
||||||
// We still need to check these two cases, as processes may still be killed by an
|
|
||||||
// external actor (human operator, OOM, random script etc).
|
|
||||||
if errors.Is(err, os.ErrPermission) || IsAlreadyStopped(err) {
|
|
||||||
// There are two cases where it should be safe to ignore an error returned
|
|
||||||
// by HcsTerminateProcess. The first one is cause by the fact that
|
|
||||||
// HcsTerminateProcess ends up calling TerminateProcess in the context
|
|
||||||
// of a container. According to the TerminateProcess documentation:
|
|
||||||
// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-terminateprocess#remarks
|
|
||||||
// After a process has terminated, call to TerminateProcess with open
|
|
||||||
// handles to the process fails with ERROR_ACCESS_DENIED (5) error code.
|
|
||||||
// It's safe to ignore this error here. HCS should always have permissions
|
|
||||||
// to kill processes inside any container. So an ERROR_ACCESS_DENIED
|
|
||||||
// is unlikely to be anything else than what the ending remarks in the
|
|
||||||
// documentation states.
|
|
||||||
//
|
|
||||||
// The second case is generated by hcs itself, if for any reason HcsTerminateProcess
|
|
||||||
// is called twice in a very short amount of time. In such cases, hcs may return
|
|
||||||
// HCS_E_PROCESS_ALREADY_STOPPED.
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
events := processHcsResult(ctx, resultJSON)
|
|
||||||
delivered, err := newProcessHandle.processSignalResult(ctx, err)
|
|
||||||
if err != nil {
|
|
||||||
err = makeProcessError(newProcessHandle, operation, err, events)
|
|
||||||
}
|
|
||||||
|
|
||||||
process.killSignalDelivered = delivered
|
|
||||||
return delivered, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// waitBackground waits for the process exit notification. Once received sets
|
|
||||||
// `process.waitError` (if any) and unblocks all `Wait` calls.
|
|
||||||
//
|
|
||||||
// This MUST be called exactly once per `process.handle` but `Wait` is safe to
|
|
||||||
// call multiple times.
|
|
||||||
func (process *Process) waitBackground() {
|
|
||||||
operation := "hcs::Process::waitBackground"
|
|
||||||
ctx, span := oc.StartSpan(context.Background(), operation)
|
|
||||||
defer span.End()
|
|
||||||
span.AddAttributes(
|
|
||||||
trace.StringAttribute("cid", process.SystemID()),
|
|
||||||
trace.Int64Attribute("pid", int64(process.processID)))
|
|
||||||
|
|
||||||
var (
|
|
||||||
err error
|
|
||||||
exitCode = -1
|
|
||||||
propertiesJSON string
|
|
||||||
resultJSON string
|
|
||||||
)
|
|
||||||
|
|
||||||
err = waitForNotification(ctx, process.callbackNumber, hcsNotificationProcessExited, nil)
|
|
||||||
if err != nil {
|
|
||||||
err = makeProcessError(process, operation, err, nil)
|
|
||||||
log.G(ctx).WithError(err).Error("failed wait")
|
|
||||||
} else {
|
|
||||||
process.handleLock.RLock()
|
|
||||||
defer process.handleLock.RUnlock()
|
|
||||||
|
|
||||||
// Make sure we didnt race with Close() here
|
|
||||||
if process.handle != 0 {
|
|
||||||
propertiesJSON, resultJSON, err = vmcompute.HcsGetProcessProperties(ctx, process.handle)
|
|
||||||
events := processHcsResult(ctx, resultJSON)
|
|
||||||
if err != nil {
|
|
||||||
err = makeProcessError(process, operation, err, events)
|
|
||||||
} else {
|
|
||||||
properties := &processStatus{}
|
|
||||||
err = json.Unmarshal([]byte(propertiesJSON), properties)
|
|
||||||
if err != nil {
|
|
||||||
err = makeProcessError(process, operation, err, nil)
|
|
||||||
} else {
|
|
||||||
if properties.LastWaitResult != 0 {
|
|
||||||
log.G(ctx).WithField("wait-result", properties.LastWaitResult).Warning("non-zero last wait result")
|
|
||||||
} else {
|
|
||||||
exitCode = int(properties.ExitCode)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
log.G(ctx).WithField("exitCode", exitCode).Debug("process exited")
|
|
||||||
|
|
||||||
process.closedWaitOnce.Do(func() {
|
|
||||||
process.exitCode = exitCode
|
|
||||||
process.waitError = err
|
|
||||||
close(process.waitBlock)
|
|
||||||
})
|
|
||||||
oc.SetSpanStatus(span, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait waits for the process to exit. If the process has already exited returns
|
|
||||||
// the previous error (if any).
|
|
||||||
func (process *Process) Wait() error {
|
|
||||||
<-process.waitBlock
|
|
||||||
return process.waitError
|
|
||||||
}
|
|
||||||
|
|
||||||
// Exited returns if the process has stopped
|
|
||||||
func (process *Process) stopped() bool {
|
|
||||||
select {
|
|
||||||
case <-process.waitBlock:
|
|
||||||
return true
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ResizeConsole resizes the console of the process.
|
|
||||||
func (process *Process) ResizeConsole(ctx context.Context, width, height uint16) error {
|
|
||||||
process.handleLock.RLock()
|
|
||||||
defer process.handleLock.RUnlock()
|
|
||||||
|
|
||||||
operation := "hcs::Process::ResizeConsole"
|
|
||||||
|
|
||||||
if process.handle == 0 {
|
|
||||||
return makeProcessError(process, operation, ErrAlreadyClosed, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
modifyRequest := processModifyRequest{
|
|
||||||
Operation: modifyConsoleSize,
|
|
||||||
ConsoleSize: &consoleSize{
|
|
||||||
Height: height,
|
|
||||||
Width: width,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
modifyRequestb, err := json.Marshal(modifyRequest)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
resultJSON, err := vmcompute.HcsModifyProcess(ctx, process.handle, string(modifyRequestb))
|
|
||||||
events := processHcsResult(ctx, resultJSON)
|
|
||||||
if err != nil {
|
|
||||||
return makeProcessError(process, operation, err, events)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExitCode returns the exit code of the process. The process must have
|
|
||||||
// already terminated.
|
|
||||||
func (process *Process) ExitCode() (int, error) {
|
|
||||||
if !process.stopped() {
|
|
||||||
return -1, makeProcessError(process, "hcs::Process::ExitCode", ErrInvalidProcessState, nil)
|
|
||||||
}
|
|
||||||
if process.waitError != nil {
|
|
||||||
return -1, process.waitError
|
|
||||||
}
|
|
||||||
return process.exitCode, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// StdioLegacy returns the stdin, stdout, and stderr pipes, respectively. Closing
|
|
||||||
// these pipes does not close the underlying pipes. Once returned, these pipes
|
|
||||||
// are the responsibility of the caller to close.
|
|
||||||
func (process *Process) StdioLegacy() (_ io.WriteCloser, _ io.ReadCloser, _ io.ReadCloser, err error) {
|
|
||||||
operation := "hcs::Process::StdioLegacy"
|
|
||||||
ctx, span := oc.StartSpan(context.Background(), operation)
|
|
||||||
defer span.End()
|
|
||||||
defer func() { oc.SetSpanStatus(span, err) }()
|
|
||||||
span.AddAttributes(
|
|
||||||
trace.StringAttribute("cid", process.SystemID()),
|
|
||||||
trace.Int64Attribute("pid", int64(process.processID)))
|
|
||||||
|
|
||||||
process.handleLock.RLock()
|
|
||||||
defer process.handleLock.RUnlock()
|
|
||||||
|
|
||||||
if process.handle == 0 {
|
|
||||||
return nil, nil, nil, makeProcessError(process, operation, ErrAlreadyClosed, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
process.stdioLock.Lock()
|
|
||||||
defer process.stdioLock.Unlock()
|
|
||||||
if process.hasCachedStdio {
|
|
||||||
stdin, stdout, stderr := process.stdin, process.stdout, process.stderr
|
|
||||||
process.stdin, process.stdout, process.stderr = nil, nil, nil
|
|
||||||
process.hasCachedStdio = false
|
|
||||||
return stdin, stdout, stderr, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
processInfo, resultJSON, err := vmcompute.HcsGetProcessInfo(ctx, process.handle)
|
|
||||||
events := processHcsResult(ctx, resultJSON)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, nil, makeProcessError(process, operation, err, events)
|
|
||||||
}
|
|
||||||
|
|
||||||
pipes, err := makeOpenFiles([]syscall.Handle{processInfo.StdInput, processInfo.StdOutput, processInfo.StdError})
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, nil, makeProcessError(process, operation, err, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
return pipes[0], pipes[1], pipes[2], nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stdio returns the stdin, stdout, and stderr pipes, respectively.
|
|
||||||
// To close them, close the process handle, or use the `CloseStd*` functions.
|
|
||||||
func (process *Process) Stdio() (stdin io.Writer, stdout, stderr io.Reader) {
|
|
||||||
process.stdioLock.Lock()
|
|
||||||
defer process.stdioLock.Unlock()
|
|
||||||
return process.stdin, process.stdout, process.stderr
|
|
||||||
}
|
|
||||||
|
|
||||||
// CloseStdin closes the write side of the stdin pipe so that the process is
|
|
||||||
// notified on the read side that there is no more data in stdin.
|
|
||||||
func (process *Process) CloseStdin(ctx context.Context) (err error) {
|
|
||||||
operation := "hcs::Process::CloseStdin"
|
|
||||||
ctx, span := trace.StartSpan(ctx, operation)
|
|
||||||
defer span.End()
|
|
||||||
defer func() { oc.SetSpanStatus(span, err) }()
|
|
||||||
span.AddAttributes(
|
|
||||||
trace.StringAttribute("cid", process.SystemID()),
|
|
||||||
trace.Int64Attribute("pid", int64(process.processID)))
|
|
||||||
|
|
||||||
process.handleLock.RLock()
|
|
||||||
defer process.handleLock.RUnlock()
|
|
||||||
|
|
||||||
if process.handle == 0 {
|
|
||||||
return makeProcessError(process, operation, ErrAlreadyClosed, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
process.stdioLock.Lock()
|
|
||||||
defer process.stdioLock.Unlock()
|
|
||||||
if process.stdin == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
//HcsModifyProcess request to close stdin will fail if the process has already exited
|
|
||||||
if !process.stopped() {
|
|
||||||
modifyRequest := processModifyRequest{
|
|
||||||
Operation: modifyCloseHandle,
|
|
||||||
CloseHandle: &closeHandle{
|
|
||||||
Handle: stdIn,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
modifyRequestb, err := json.Marshal(modifyRequest)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
resultJSON, err := vmcompute.HcsModifyProcess(ctx, process.handle, string(modifyRequestb))
|
|
||||||
events := processHcsResult(ctx, resultJSON)
|
|
||||||
if err != nil {
|
|
||||||
return makeProcessError(process, operation, err, events)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
process.stdin.Close()
|
|
||||||
process.stdin = nil
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (process *Process) CloseStdout(ctx context.Context) (err error) {
|
|
||||||
ctx, span := oc.StartSpan(ctx, "hcs::Process::CloseStdout") //nolint:ineffassign,staticcheck
|
|
||||||
defer span.End()
|
|
||||||
defer func() { oc.SetSpanStatus(span, err) }()
|
|
||||||
span.AddAttributes(
|
|
||||||
trace.StringAttribute("cid", process.SystemID()),
|
|
||||||
trace.Int64Attribute("pid", int64(process.processID)))
|
|
||||||
|
|
||||||
process.handleLock.Lock()
|
|
||||||
defer process.handleLock.Unlock()
|
|
||||||
|
|
||||||
if process.handle == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
process.stdioLock.Lock()
|
|
||||||
defer process.stdioLock.Unlock()
|
|
||||||
if process.stdout != nil {
|
|
||||||
process.stdout.Close()
|
|
||||||
process.stdout = nil
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (process *Process) CloseStderr(ctx context.Context) (err error) {
|
|
||||||
ctx, span := oc.StartSpan(ctx, "hcs::Process::CloseStderr") //nolint:ineffassign,staticcheck
|
|
||||||
defer span.End()
|
|
||||||
defer func() { oc.SetSpanStatus(span, err) }()
|
|
||||||
span.AddAttributes(
|
|
||||||
trace.StringAttribute("cid", process.SystemID()),
|
|
||||||
trace.Int64Attribute("pid", int64(process.processID)))
|
|
||||||
|
|
||||||
process.handleLock.Lock()
|
|
||||||
defer process.handleLock.Unlock()
|
|
||||||
|
|
||||||
if process.handle == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
process.stdioLock.Lock()
|
|
||||||
defer process.stdioLock.Unlock()
|
|
||||||
if process.stderr != nil {
|
|
||||||
process.stderr.Close()
|
|
||||||
process.stderr = nil
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close cleans up any state associated with the process but does not kill
|
|
||||||
// or wait on it.
|
|
||||||
func (process *Process) Close() (err error) {
|
|
||||||
operation := "hcs::Process::Close"
|
|
||||||
ctx, span := oc.StartSpan(context.Background(), operation)
|
|
||||||
defer span.End()
|
|
||||||
defer func() { oc.SetSpanStatus(span, err) }()
|
|
||||||
span.AddAttributes(
|
|
||||||
trace.StringAttribute("cid", process.SystemID()),
|
|
||||||
trace.Int64Attribute("pid", int64(process.processID)))
|
|
||||||
|
|
||||||
process.handleLock.Lock()
|
|
||||||
defer process.handleLock.Unlock()
|
|
||||||
|
|
||||||
// Don't double free this
|
|
||||||
if process.handle == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
process.stdioLock.Lock()
|
|
||||||
if process.stdin != nil {
|
|
||||||
process.stdin.Close()
|
|
||||||
process.stdin = nil
|
|
||||||
}
|
|
||||||
if process.stdout != nil {
|
|
||||||
process.stdout.Close()
|
|
||||||
process.stdout = nil
|
|
||||||
}
|
|
||||||
if process.stderr != nil {
|
|
||||||
process.stderr.Close()
|
|
||||||
process.stderr = nil
|
|
||||||
}
|
|
||||||
process.stdioLock.Unlock()
|
|
||||||
|
|
||||||
if err = process.unregisterCallback(ctx); err != nil {
|
|
||||||
return makeProcessError(process, operation, err, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = vmcompute.HcsCloseProcess(ctx, process.handle); err != nil {
|
|
||||||
return makeProcessError(process, operation, err, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
process.handle = 0
|
|
||||||
process.closedWaitOnce.Do(func() {
|
|
||||||
process.exitCode = -1
|
|
||||||
process.waitError = ErrAlreadyClosed
|
|
||||||
close(process.waitBlock)
|
|
||||||
})
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (process *Process) registerCallback(ctx context.Context) error {
|
|
||||||
callbackContext := ¬ificationWatcherContext{
|
|
||||||
channels: newProcessChannels(),
|
|
||||||
systemID: process.SystemID(),
|
|
||||||
processID: process.processID,
|
|
||||||
}
|
|
||||||
|
|
||||||
callbackMapLock.Lock()
|
|
||||||
callbackNumber := nextCallback
|
|
||||||
nextCallback++
|
|
||||||
callbackMap[callbackNumber] = callbackContext
|
|
||||||
callbackMapLock.Unlock()
|
|
||||||
|
|
||||||
callbackHandle, err := vmcompute.HcsRegisterProcessCallback(ctx, process.handle, notificationWatcherCallback, callbackNumber)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
callbackContext.handle = callbackHandle
|
|
||||||
process.callbackNumber = callbackNumber
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (process *Process) unregisterCallback(ctx context.Context) error {
|
|
||||||
callbackNumber := process.callbackNumber
|
|
||||||
|
|
||||||
callbackMapLock.RLock()
|
|
||||||
callbackContext := callbackMap[callbackNumber]
|
|
||||||
callbackMapLock.RUnlock()
|
|
||||||
|
|
||||||
if callbackContext == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
handle := callbackContext.handle
|
|
||||||
|
|
||||||
if handle == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// vmcompute.HcsUnregisterProcessCallback has its own synchronization to
|
|
||||||
// wait for all callbacks to complete. We must NOT hold the callbackMapLock.
|
|
||||||
err := vmcompute.HcsUnregisterProcessCallback(ctx, handle)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
closeChannels(callbackContext.channels)
|
|
||||||
|
|
||||||
callbackMapLock.Lock()
|
|
||||||
delete(callbackMap, callbackNumber)
|
|
||||||
callbackMapLock.Unlock()
|
|
||||||
|
|
||||||
handle = 0 //nolint:ineffassign
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
@ -1,252 +0,0 @@
|
|||||||
//go:build windows
|
|
||||||
|
|
||||||
package schema1
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/Microsoft/go-winio/pkg/guid"
|
|
||||||
hcsschema "github.com/Microsoft/hcsshim/internal/hcs/schema2"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ProcessConfig is used as both the input of Container.CreateProcess
|
|
||||||
// and to convert the parameters to JSON for passing onto the HCS
|
|
||||||
type ProcessConfig struct {
|
|
||||||
ApplicationName string `json:",omitempty"`
|
|
||||||
CommandLine string `json:",omitempty"`
|
|
||||||
CommandArgs []string `json:",omitempty"` // Used by Linux Containers on Windows
|
|
||||||
User string `json:",omitempty"`
|
|
||||||
WorkingDirectory string `json:",omitempty"`
|
|
||||||
Environment map[string]string `json:",omitempty"`
|
|
||||||
EmulateConsole bool `json:",omitempty"`
|
|
||||||
CreateStdInPipe bool `json:",omitempty"`
|
|
||||||
CreateStdOutPipe bool `json:",omitempty"`
|
|
||||||
CreateStdErrPipe bool `json:",omitempty"`
|
|
||||||
ConsoleSize [2]uint `json:",omitempty"`
|
|
||||||
CreateInUtilityVm bool `json:",omitempty"` // Used by Linux Containers on Windows
|
|
||||||
OCISpecification *json.RawMessage `json:",omitempty"` // Used by Linux Containers on Windows
|
|
||||||
}
|
|
||||||
|
|
||||||
type Layer struct {
|
|
||||||
ID string
|
|
||||||
Path string
|
|
||||||
}
|
|
||||||
|
|
||||||
type MappedDir struct {
|
|
||||||
HostPath string
|
|
||||||
ContainerPath string
|
|
||||||
ReadOnly bool
|
|
||||||
BandwidthMaximum uint64
|
|
||||||
IOPSMaximum uint64
|
|
||||||
CreateInUtilityVM bool
|
|
||||||
// LinuxMetadata - Support added in 1803/RS4+.
|
|
||||||
LinuxMetadata bool `json:",omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type MappedPipe struct {
|
|
||||||
HostPath string
|
|
||||||
ContainerPipeName string
|
|
||||||
}
|
|
||||||
|
|
||||||
type HvRuntime struct {
|
|
||||||
ImagePath string `json:",omitempty"`
|
|
||||||
SkipTemplate bool `json:",omitempty"`
|
|
||||||
LinuxInitrdFile string `json:",omitempty"` // File under ImagePath on host containing an initrd image for starting a Linux utility VM
|
|
||||||
LinuxKernelFile string `json:",omitempty"` // File under ImagePath on host containing a kernel for starting a Linux utility VM
|
|
||||||
LinuxBootParameters string `json:",omitempty"` // Additional boot parameters for starting a Linux Utility VM in initrd mode
|
|
||||||
BootSource string `json:",omitempty"` // "Vhd" for Linux Utility VM booting from VHD
|
|
||||||
WritableBootSource bool `json:",omitempty"` // Linux Utility VM booting from VHD
|
|
||||||
}
|
|
||||||
|
|
||||||
type MappedVirtualDisk struct {
|
|
||||||
HostPath string `json:",omitempty"` // Path to VHD on the host
|
|
||||||
ContainerPath string // Platform-specific mount point path in the container
|
|
||||||
CreateInUtilityVM bool `json:",omitempty"`
|
|
||||||
ReadOnly bool `json:",omitempty"`
|
|
||||||
Cache string `json:",omitempty"` // "" (Unspecified); "Disabled"; "Enabled"; "Private"; "PrivateAllowSharing"
|
|
||||||
AttachOnly bool `json:",omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// AssignedDevice represents a device that has been directly assigned to a container
|
|
||||||
//
|
|
||||||
// NOTE: Support added in RS5
|
|
||||||
type AssignedDevice struct {
|
|
||||||
// InterfaceClassGUID of the device to assign to container.
|
|
||||||
InterfaceClassGUID string `json:"InterfaceClassGuid,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ContainerConfig is used as both the input of CreateContainer
|
|
||||||
// and to convert the parameters to JSON for passing onto the HCS
|
|
||||||
type ContainerConfig struct {
|
|
||||||
SystemType string // HCS requires this to be hard-coded to "Container"
|
|
||||||
Name string // Name of the container. We use the docker ID.
|
|
||||||
Owner string `json:",omitempty"` // The management platform that created this container
|
|
||||||
VolumePath string `json:",omitempty"` // Windows volume path for scratch space. Used by Windows Server Containers only. Format \\?\\Volume{GUID}
|
|
||||||
IgnoreFlushesDuringBoot bool `json:",omitempty"` // Optimization hint for container startup in Windows
|
|
||||||
LayerFolderPath string `json:",omitempty"` // Where the layer folders are located. Used by Windows Server Containers only. Format %root%\windowsfilter\containerID
|
|
||||||
Layers []Layer // List of storage layers. Required for Windows Server and Hyper-V Containers. Format ID=GUID;Path=%root%\windowsfilter\layerID
|
|
||||||
Credentials string `json:",omitempty"` // Credentials information
|
|
||||||
ProcessorCount uint32 `json:",omitempty"` // Number of processors to assign to the container.
|
|
||||||
ProcessorWeight uint64 `json:",omitempty"` // CPU shares (relative weight to other containers with cpu shares). Range is from 1 to 10000. A value of 0 results in default shares.
|
|
||||||
ProcessorMaximum int64 `json:",omitempty"` // Specifies the portion of processor cycles that this container can use as a percentage times 100. Range is from 1 to 10000. A value of 0 results in no limit.
|
|
||||||
StorageIOPSMaximum uint64 `json:",omitempty"` // Maximum Storage IOPS
|
|
||||||
StorageBandwidthMaximum uint64 `json:",omitempty"` // Maximum Storage Bandwidth in bytes per second
|
|
||||||
StorageSandboxSize uint64 `json:",omitempty"` // Size in bytes that the container system drive should be expanded to if smaller
|
|
||||||
MemoryMaximumInMB int64 `json:",omitempty"` // Maximum memory available to the container in Megabytes
|
|
||||||
HostName string `json:",omitempty"` // Hostname
|
|
||||||
MappedDirectories []MappedDir `json:",omitempty"` // List of mapped directories (volumes/mounts)
|
|
||||||
MappedPipes []MappedPipe `json:",omitempty"` // List of mapped Windows named pipes
|
|
||||||
HvPartition bool // True if it a Hyper-V Container
|
|
||||||
NetworkSharedContainerName string `json:",omitempty"` // Name (ID) of the container that we will share the network stack with.
|
|
||||||
EndpointList []string `json:",omitempty"` // List of networking endpoints to be attached to container
|
|
||||||
HvRuntime *HvRuntime `json:",omitempty"` // Hyper-V container settings. Used by Hyper-V containers only. Format ImagePath=%root%\BaseLayerID\UtilityVM
|
|
||||||
Servicing bool `json:",omitempty"` // True if this container is for servicing
|
|
||||||
AllowUnqualifiedDNSQuery bool `json:",omitempty"` // True to allow unqualified DNS name resolution
|
|
||||||
DNSSearchList string `json:",omitempty"` // Comma separated list of DNS suffixes to use for name resolution
|
|
||||||
ContainerType string `json:",omitempty"` // "Linux" for Linux containers on Windows. Omitted otherwise.
|
|
||||||
TerminateOnLastHandleClosed bool `json:",omitempty"` // Should HCS terminate the container once all handles have been closed
|
|
||||||
MappedVirtualDisks []MappedVirtualDisk `json:",omitempty"` // Array of virtual disks to mount at start
|
|
||||||
AssignedDevices []AssignedDevice `json:",omitempty"` // Array of devices to assign. NOTE: Support added in RS5
|
|
||||||
}
|
|
||||||
|
|
||||||
type ComputeSystemQuery struct {
|
|
||||||
IDs []string `json:"Ids,omitempty"`
|
|
||||||
Types []string `json:",omitempty"`
|
|
||||||
Names []string `json:",omitempty"`
|
|
||||||
Owners []string `json:",omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type PropertyType string
|
|
||||||
|
|
||||||
const (
|
|
||||||
PropertyTypeStatistics PropertyType = "Statistics" // V1 and V2
|
|
||||||
PropertyTypeProcessList PropertyType = "ProcessList" // V1 and V2
|
|
||||||
PropertyTypeMappedVirtualDisk PropertyType = "MappedVirtualDisk" // Not supported in V2 schema call
|
|
||||||
PropertyTypeGuestConnection PropertyType = "GuestConnection" // V1 and V2. Nil return from HCS before RS5
|
|
||||||
)
|
|
||||||
|
|
||||||
type PropertyQuery struct {
|
|
||||||
PropertyTypes []PropertyType `json:",omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ContainerProperties holds the properties for a container and the processes running in that container
|
|
||||||
type ContainerProperties struct {
|
|
||||||
ID string `json:"Id"`
|
|
||||||
State string
|
|
||||||
Name string
|
|
||||||
SystemType string
|
|
||||||
RuntimeOSType string `json:"RuntimeOsType,omitempty"`
|
|
||||||
Owner string
|
|
||||||
SiloGUID string `json:"SiloGuid,omitempty"`
|
|
||||||
RuntimeID guid.GUID `json:"RuntimeId,omitempty"`
|
|
||||||
IsRuntimeTemplate bool `json:",omitempty"`
|
|
||||||
RuntimeImagePath string `json:",omitempty"`
|
|
||||||
Stopped bool `json:",omitempty"`
|
|
||||||
ExitType string `json:",omitempty"`
|
|
||||||
AreUpdatesPending bool `json:",omitempty"`
|
|
||||||
ObRoot string `json:",omitempty"`
|
|
||||||
Statistics Statistics `json:",omitempty"`
|
|
||||||
ProcessList []ProcessListItem `json:",omitempty"`
|
|
||||||
MappedVirtualDiskControllers map[int]MappedVirtualDiskController `json:",omitempty"`
|
|
||||||
GuestConnectionInfo GuestConnectionInfo `json:",omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// MemoryStats holds the memory statistics for a container
|
|
||||||
type MemoryStats struct {
|
|
||||||
UsageCommitBytes uint64 `json:"MemoryUsageCommitBytes,omitempty"`
|
|
||||||
UsageCommitPeakBytes uint64 `json:"MemoryUsageCommitPeakBytes,omitempty"`
|
|
||||||
UsagePrivateWorkingSetBytes uint64 `json:"MemoryUsagePrivateWorkingSetBytes,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ProcessorStats holds the processor statistics for a container
|
|
||||||
type ProcessorStats struct {
|
|
||||||
TotalRuntime100ns uint64 `json:",omitempty"`
|
|
||||||
RuntimeUser100ns uint64 `json:",omitempty"`
|
|
||||||
RuntimeKernel100ns uint64 `json:",omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// StorageStats holds the storage statistics for a container
|
|
||||||
type StorageStats struct {
|
|
||||||
ReadCountNormalized uint64 `json:",omitempty"`
|
|
||||||
ReadSizeBytes uint64 `json:",omitempty"`
|
|
||||||
WriteCountNormalized uint64 `json:",omitempty"`
|
|
||||||
WriteSizeBytes uint64 `json:",omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// NetworkStats holds the network statistics for a container
|
|
||||||
type NetworkStats struct {
|
|
||||||
BytesReceived uint64 `json:",omitempty"`
|
|
||||||
BytesSent uint64 `json:",omitempty"`
|
|
||||||
PacketsReceived uint64 `json:",omitempty"`
|
|
||||||
PacketsSent uint64 `json:",omitempty"`
|
|
||||||
DroppedPacketsIncoming uint64 `json:",omitempty"`
|
|
||||||
DroppedPacketsOutgoing uint64 `json:",omitempty"`
|
|
||||||
EndpointId string `json:",omitempty"`
|
|
||||||
InstanceId string `json:",omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Statistics is the structure returned by a statistics call on a container
|
|
||||||
type Statistics struct {
|
|
||||||
Timestamp time.Time `json:",omitempty"`
|
|
||||||
ContainerStartTime time.Time `json:",omitempty"`
|
|
||||||
Uptime100ns uint64 `json:",omitempty"`
|
|
||||||
Memory MemoryStats `json:",omitempty"`
|
|
||||||
Processor ProcessorStats `json:",omitempty"`
|
|
||||||
Storage StorageStats `json:",omitempty"`
|
|
||||||
Network []NetworkStats `json:",omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ProcessList is the structure of an item returned by a ProcessList call on a container
|
|
||||||
type ProcessListItem struct {
|
|
||||||
CreateTimestamp time.Time `json:",omitempty"`
|
|
||||||
ImageName string `json:",omitempty"`
|
|
||||||
KernelTime100ns uint64 `json:",omitempty"`
|
|
||||||
MemoryCommitBytes uint64 `json:",omitempty"`
|
|
||||||
MemoryWorkingSetPrivateBytes uint64 `json:",omitempty"`
|
|
||||||
MemoryWorkingSetSharedBytes uint64 `json:",omitempty"`
|
|
||||||
ProcessId uint32 `json:",omitempty"`
|
|
||||||
UserTime100ns uint64 `json:",omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// MappedVirtualDiskController is the structure of an item returned by a MappedVirtualDiskList call on a container
|
|
||||||
type MappedVirtualDiskController struct {
|
|
||||||
MappedVirtualDisks map[int]MappedVirtualDisk `json:",omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// GuestDefinedCapabilities is part of the GuestConnectionInfo returned by a GuestConnection call on a utility VM
|
|
||||||
type GuestDefinedCapabilities struct {
|
|
||||||
NamespaceAddRequestSupported bool `json:",omitempty"`
|
|
||||||
SignalProcessSupported bool `json:",omitempty"`
|
|
||||||
DumpStacksSupported bool `json:",omitempty"`
|
|
||||||
DeleteContainerStateSupported bool `json:",omitempty"`
|
|
||||||
UpdateContainerSupported bool `json:",omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// GuestConnectionInfo is the structure of an iterm return by a GuestConnection call on a utility VM
|
|
||||||
type GuestConnectionInfo struct {
|
|
||||||
SupportedSchemaVersions []hcsschema.Version `json:",omitempty"`
|
|
||||||
ProtocolVersion uint32 `json:",omitempty"`
|
|
||||||
GuestDefinedCapabilities GuestDefinedCapabilities `json:",omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Type of Request Support in ModifySystem
|
|
||||||
type RequestType string
|
|
||||||
|
|
||||||
// Type of Resource Support in ModifySystem
|
|
||||||
type ResourceType string
|
|
||||||
|
|
||||||
// RequestType const
|
|
||||||
const (
|
|
||||||
Add RequestType = "Add"
|
|
||||||
Remove RequestType = "Remove"
|
|
||||||
Network ResourceType = "Network"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ResourceModificationRequestResponse is the structure used to send request to the container to modify the system
|
|
||||||
// Supported resource types are Network and Request Types are Add/Remove
|
|
||||||
type ResourceModificationRequestResponse struct {
|
|
||||||
Resource ResourceType `json:"ResourceType"`
|
|
||||||
Data interface{} `json:"Settings"`
|
|
||||||
Request RequestType `json:"RequestType,omitempty"`
|
|
||||||
}
|
|
@ -1,36 +0,0 @@
|
|||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.1
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type Attachment struct {
|
|
||||||
Type_ string `json:"Type,omitempty"`
|
|
||||||
|
|
||||||
Path string `json:"Path,omitempty"`
|
|
||||||
|
|
||||||
IgnoreFlushes bool `json:"IgnoreFlushes,omitempty"`
|
|
||||||
|
|
||||||
CachingMode string `json:"CachingMode,omitempty"`
|
|
||||||
|
|
||||||
NoWriteHardening bool `json:"NoWriteHardening,omitempty"`
|
|
||||||
|
|
||||||
DisableExpansionOptimization bool `json:"DisableExpansionOptimization,omitempty"`
|
|
||||||
|
|
||||||
IgnoreRelativeLocator bool `json:"IgnoreRelativeLocator,omitempty"`
|
|
||||||
|
|
||||||
CaptureIoAttributionContext bool `json:"CaptureIoAttributionContext,omitempty"`
|
|
||||||
|
|
||||||
ReadOnly bool `json:"ReadOnly,omitempty"`
|
|
||||||
|
|
||||||
SupportCompressedVolumes bool `json:"SupportCompressedVolumes,omitempty"`
|
|
||||||
|
|
||||||
AlwaysAllowSparseFiles bool `json:"AlwaysAllowSparseFiles,omitempty"`
|
|
||||||
|
|
||||||
ExtensibleVirtualDiskType string `json:"ExtensibleVirtualDiskType,omitempty"`
|
|
||||||
}
|
|
@ -1,13 +0,0 @@
|
|||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.1
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type Battery struct {
|
|
||||||
}
|
|
18
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/cache_query_stats_response.go
generated
vendored
18
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/cache_query_stats_response.go
generated
vendored
@ -1,18 +0,0 @@
|
|||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.1
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type CacheQueryStatsResponse struct {
|
|
||||||
L3OccupancyBytes int32 `json:"L3OccupancyBytes,omitempty"`
|
|
||||||
|
|
||||||
L3TotalBwBytes int32 `json:"L3TotalBwBytes,omitempty"`
|
|
||||||
|
|
||||||
L3LocalBwBytes int32 `json:"L3LocalBwBytes,omitempty"`
|
|
||||||
}
|
|
@ -1,27 +0,0 @@
|
|||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.1
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type Chipset struct {
|
|
||||||
Uefi *Uefi `json:"Uefi,omitempty"`
|
|
||||||
|
|
||||||
IsNumLockDisabled bool `json:"IsNumLockDisabled,omitempty"`
|
|
||||||
|
|
||||||
BaseBoardSerialNumber string `json:"BaseBoardSerialNumber,omitempty"`
|
|
||||||
|
|
||||||
ChassisSerialNumber string `json:"ChassisSerialNumber,omitempty"`
|
|
||||||
|
|
||||||
ChassisAssetTag string `json:"ChassisAssetTag,omitempty"`
|
|
||||||
|
|
||||||
UseUtc bool `json:"UseUtc,omitempty"`
|
|
||||||
|
|
||||||
// LinuxKernelDirect - Added in v2.2 Builds >=181117
|
|
||||||
LinuxKernelDirect *LinuxKernelDirect `json:"LinuxKernelDirect,omitempty"`
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.1
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type CloseHandle struct {
|
|
||||||
Handle string `json:"Handle,omitempty"`
|
|
||||||
}
|
|
@ -1,17 +0,0 @@
|
|||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.1
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
// ComPort specifies the named pipe that will be used for the port, with empty string indicating a disconnected port.
|
|
||||||
type ComPort struct {
|
|
||||||
NamedPipe string `json:"NamedPipe,omitempty"`
|
|
||||||
|
|
||||||
OptimizeForDebugger bool `json:"OptimizeForDebugger,omitempty"`
|
|
||||||
}
|
|
@ -1,26 +0,0 @@
|
|||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.1
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type ComputeSystem struct {
|
|
||||||
Owner string `json:"Owner,omitempty"`
|
|
||||||
|
|
||||||
SchemaVersion *Version `json:"SchemaVersion,omitempty"`
|
|
||||||
|
|
||||||
HostingSystemId string `json:"HostingSystemId,omitempty"`
|
|
||||||
|
|
||||||
HostedSystem interface{} `json:"HostedSystem,omitempty"`
|
|
||||||
|
|
||||||
Container *Container `json:"Container,omitempty"`
|
|
||||||
|
|
||||||
VirtualMachine *VirtualMachine `json:"VirtualMachine,omitempty"`
|
|
||||||
|
|
||||||
ShouldTerminateOnLastHandleClosed bool `json:"ShouldTerminateOnLastHandleClosed,omitempty"`
|
|
||||||
}
|
|
@ -1,72 +0,0 @@
|
|||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.1
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
// contextKeys are used to identify the type of value in the context.
|
|
||||||
// Since these are string, it is possible to get a short description of the
|
|
||||||
// context key for logging and debugging using key.String().
|
|
||||||
|
|
||||||
type contextKey string
|
|
||||||
|
|
||||||
func (c contextKey) String() string {
|
|
||||||
return "auth " + string(c)
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
// ContextOAuth2 takes a oauth2.TokenSource as authentication for the request.
|
|
||||||
ContextOAuth2 = contextKey("token")
|
|
||||||
|
|
||||||
// ContextBasicAuth takes BasicAuth as authentication for the request.
|
|
||||||
ContextBasicAuth = contextKey("basic")
|
|
||||||
|
|
||||||
// ContextAccessToken takes a string oauth2 access token as authentication for the request.
|
|
||||||
ContextAccessToken = contextKey("accesstoken")
|
|
||||||
|
|
||||||
// ContextAPIKey takes an APIKey as authentication for the request
|
|
||||||
ContextAPIKey = contextKey("apikey")
|
|
||||||
)
|
|
||||||
|
|
||||||
// BasicAuth provides basic http authentication to a request passed via context using ContextBasicAuth
|
|
||||||
type BasicAuth struct {
|
|
||||||
UserName string `json:"userName,omitempty"`
|
|
||||||
Password string `json:"password,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// APIKey provides API key based authentication to a request passed via context using ContextAPIKey
|
|
||||||
type APIKey struct {
|
|
||||||
Key string
|
|
||||||
Prefix string
|
|
||||||
}
|
|
||||||
|
|
||||||
type Configuration struct {
|
|
||||||
BasePath string `json:"basePath,omitempty"`
|
|
||||||
Host string `json:"host,omitempty"`
|
|
||||||
Scheme string `json:"scheme,omitempty"`
|
|
||||||
DefaultHeader map[string]string `json:"defaultHeader,omitempty"`
|
|
||||||
UserAgent string `json:"userAgent,omitempty"`
|
|
||||||
HTTPClient *http.Client
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewConfiguration() *Configuration {
|
|
||||||
cfg := &Configuration{
|
|
||||||
BasePath: "https://localhost",
|
|
||||||
DefaultHeader: make(map[string]string),
|
|
||||||
UserAgent: "Swagger-Codegen/2.1.0/go",
|
|
||||||
}
|
|
||||||
return cfg
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Configuration) AddDefaultHeader(key string, value string) {
|
|
||||||
c.DefaultHeader[key] = value
|
|
||||||
}
|
|
@ -1,16 +0,0 @@
|
|||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.1
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type ConsoleSize struct {
|
|
||||||
Height int32 `json:"Height,omitempty"`
|
|
||||||
|
|
||||||
Width int32 `json:"Width,omitempty"`
|
|
||||||
}
|
|
@ -1,36 +0,0 @@
|
|||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.1
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type Container struct {
|
|
||||||
GuestOs *GuestOs `json:"GuestOs,omitempty"`
|
|
||||||
|
|
||||||
Storage *Storage `json:"Storage,omitempty"`
|
|
||||||
|
|
||||||
MappedDirectories []MappedDirectory `json:"MappedDirectories,omitempty"`
|
|
||||||
|
|
||||||
MappedPipes []MappedPipe `json:"MappedPipes,omitempty"`
|
|
||||||
|
|
||||||
Memory *Memory `json:"Memory,omitempty"`
|
|
||||||
|
|
||||||
Processor *Processor `json:"Processor,omitempty"`
|
|
||||||
|
|
||||||
Networking *Networking `json:"Networking,omitempty"`
|
|
||||||
|
|
||||||
HvSocket *HvSocket `json:"HvSocket,omitempty"`
|
|
||||||
|
|
||||||
ContainerCredentialGuard *ContainerCredentialGuardState `json:"ContainerCredentialGuard,omitempty"`
|
|
||||||
|
|
||||||
RegistryChanges *RegistryChanges `json:"RegistryChanges,omitempty"`
|
|
||||||
|
|
||||||
AssignedDevices []Device `json:"AssignedDevices,omitempty"`
|
|
||||||
|
|
||||||
AdditionalDeviceNamespace *ContainerDefinitionDevice `json:"AdditionalDeviceNamespace,omitempty"`
|
|
||||||
}
|
|
@ -1,16 +0,0 @@
|
|||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.4
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type ContainerCredentialGuardAddInstanceRequest struct {
|
|
||||||
Id string `json:"Id,omitempty"`
|
|
||||||
CredentialSpec string `json:"CredentialSpec,omitempty"`
|
|
||||||
Transport string `json:"Transport,omitempty"`
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.4
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type ContainerCredentialGuardHvSocketServiceConfig struct {
|
|
||||||
ServiceId string `json:"ServiceId,omitempty"`
|
|
||||||
ServiceConfig *HvSocketServiceConfig `json:"ServiceConfig,omitempty"`
|
|
||||||
}
|
|
@ -1,16 +0,0 @@
|
|||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.4
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type ContainerCredentialGuardInstance struct {
|
|
||||||
Id string `json:"Id,omitempty"`
|
|
||||||
CredentialGuard *ContainerCredentialGuardState `json:"CredentialGuard,omitempty"`
|
|
||||||
HvSocketConfig *ContainerCredentialGuardHvSocketServiceConfig `json:"HvSocketConfig,omitempty"`
|
|
||||||
}
|
|
@ -1,17 +0,0 @@
|
|||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.4
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type ContainerCredentialGuardModifyOperation string
|
|
||||||
|
|
||||||
const (
|
|
||||||
AddInstance ContainerCredentialGuardModifyOperation = "AddInstance"
|
|
||||||
RemoveInstance ContainerCredentialGuardModifyOperation = "RemoveInstance"
|
|
||||||
)
|
|
@ -1,15 +0,0 @@
|
|||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.4
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type ContainerCredentialGuardOperationRequest struct {
|
|
||||||
Operation ContainerCredentialGuardModifyOperation `json:"Operation,omitempty"`
|
|
||||||
OperationDetails interface{} `json:"OperationDetails,omitempty"`
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.4
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type ContainerCredentialGuardRemoveInstanceRequest struct {
|
|
||||||
Id string `json:"Id,omitempty"`
|
|
||||||
}
|
|
@ -1,25 +0,0 @@
|
|||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.1
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type ContainerCredentialGuardState struct {
|
|
||||||
|
|
||||||
// Authentication cookie for calls to a Container Credential Guard instance.
|
|
||||||
Cookie string `json:"Cookie,omitempty"`
|
|
||||||
|
|
||||||
// Name of the RPC endpoint of the Container Credential Guard instance.
|
|
||||||
RpcEndpoint string `json:"RpcEndpoint,omitempty"`
|
|
||||||
|
|
||||||
// Transport used for the configured Container Credential Guard instance.
|
|
||||||
Transport string `json:"Transport,omitempty"`
|
|
||||||
|
|
||||||
// Credential spec used for the configured Container Credential Guard instance.
|
|
||||||
CredentialSpec string `json:"CredentialSpec,omitempty"`
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.4
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type ContainerCredentialGuardSystemInfo struct {
|
|
||||||
Instances []ContainerCredentialGuardInstance `json:"Instances,omitempty"`
|
|
||||||
}
|
|
25
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/container_memory_information.go
generated
vendored
25
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/container_memory_information.go
generated
vendored
@ -1,25 +0,0 @@
|
|||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.1
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
// memory usage as viewed from within the container
|
|
||||||
type ContainerMemoryInformation struct {
|
|
||||||
TotalPhysicalBytes int32 `json:"TotalPhysicalBytes,omitempty"`
|
|
||||||
|
|
||||||
TotalUsage int32 `json:"TotalUsage,omitempty"`
|
|
||||||
|
|
||||||
CommittedBytes int32 `json:"CommittedBytes,omitempty"`
|
|
||||||
|
|
||||||
SharedCommittedBytes int32 `json:"SharedCommittedBytes,omitempty"`
|
|
||||||
|
|
||||||
CommitLimitBytes int32 `json:"CommitLimitBytes,omitempty"`
|
|
||||||
|
|
||||||
PeakCommitmentBytes int32 `json:"PeakCommitmentBytes,omitempty"`
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.4
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
// CPU groups allow Hyper-V administrators to better manage and allocate the host's CPU resources across guest virtual machines
|
|
||||||
type CpuGroup struct {
|
|
||||||
Id string `json:"Id,omitempty"`
|
|
||||||
}
|
|
15
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/cpu_group_affinity.go
generated
vendored
15
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/cpu_group_affinity.go
generated
vendored
@ -1,15 +0,0 @@
|
|||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.4
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type CpuGroupAffinity struct {
|
|
||||||
LogicalProcessorCount int32 `json:"LogicalProcessorCount,omitempty"`
|
|
||||||
LogicalProcessors []int32 `json:"LogicalProcessors,omitempty"`
|
|
||||||
}
|
|
@ -1,18 +0,0 @@
|
|||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.4
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type CpuGroupConfig struct {
|
|
||||||
GroupId string `json:"GroupId,omitempty"`
|
|
||||||
Affinity *CpuGroupAffinity `json:"Affinity,omitempty"`
|
|
||||||
GroupProperties []CpuGroupProperty `json:"GroupProperties,omitempty"`
|
|
||||||
// Hypervisor CPU group IDs exposed to clients
|
|
||||||
HypervisorGroupId uint64 `json:"HypervisorGroupId,omitempty"`
|
|
||||||
}
|
|
15
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/cpu_group_configurations.go
generated
vendored
15
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/cpu_group_configurations.go
generated
vendored
@ -1,15 +0,0 @@
|
|||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.4
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
// Structure used to return cpu groups for a Service property query
|
|
||||||
type CpuGroupConfigurations struct {
|
|
||||||
CpuGroups []CpuGroupConfig `json:"CpuGroups,omitempty"`
|
|
||||||
}
|
|
18
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/cpu_group_operations.go
generated
vendored
18
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/cpu_group_operations.go
generated
vendored
@ -1,18 +0,0 @@
|
|||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.4
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type CPUGroupOperation string
|
|
||||||
|
|
||||||
const (
|
|
||||||
CreateGroup CPUGroupOperation = "CreateGroup"
|
|
||||||
DeleteGroup CPUGroupOperation = "DeleteGroup"
|
|
||||||
SetProperty CPUGroupOperation = "SetProperty"
|
|
||||||
)
|
|
23
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/cpu_group_property.go
generated
vendored
23
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/cpu_group_property.go
generated
vendored
@ -1,23 +0,0 @@
|
|||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.4
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type CPUGroupPropertyCode uint32
|
|
||||||
|
|
||||||
const (
|
|
||||||
CPUCapacityProperty = 0x00010000
|
|
||||||
CPUSchedulingPriorityProperty = 0x00020000
|
|
||||||
IdleLPReserveProperty = 0x00030000
|
|
||||||
)
|
|
||||||
|
|
||||||
type CpuGroupProperty struct {
|
|
||||||
PropertyCode uint32 `json:"PropertyCode,omitempty"`
|
|
||||||
PropertyValue uint32 `json:"PropertyValue,omitempty"`
|
|
||||||
}
|
|
17
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/create_group_operation.go
generated
vendored
17
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/create_group_operation.go
generated
vendored
@ -1,17 +0,0 @@
|
|||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.4
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
// Create group operation settings
|
|
||||||
type CreateGroupOperation struct {
|
|
||||||
GroupId string `json:"GroupId,omitempty"`
|
|
||||||
LogicalProcessorCount uint32 `json:"LogicalProcessorCount,omitempty"`
|
|
||||||
LogicalProcessors []uint32 `json:"LogicalProcessors,omitempty"`
|
|
||||||
}
|
|
@ -1,22 +0,0 @@
|
|||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.1
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type DebugOptions struct {
|
|
||||||
// BugcheckSavedStateFileName is the path for the file in which the guest VM state will be saved when
|
|
||||||
// the guest crashes.
|
|
||||||
BugcheckSavedStateFileName string `json:"BugcheckSavedStateFileName,omitempty"`
|
|
||||||
// BugcheckNoCrashdumpSavedStateFileName is the path of the file in which the guest VM state will be
|
|
||||||
// saved when the guest crashes but the guest isn't able to generate the crash dump. This usually
|
|
||||||
// happens in early boot failures.
|
|
||||||
BugcheckNoCrashdumpSavedStateFileName string `json:"BugcheckNoCrashdumpSavedStateFileName,omitempty"`
|
|
||||||
TripleFaultSavedStateFileName string `json:"TripleFaultSavedStateFileName,omitempty"`
|
|
||||||
FirmwareDumpFileName string `json:"FirmwareDumpFileName,omitempty"`
|
|
||||||
}
|
|
15
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/delete_group_operation.go
generated
vendored
15
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/delete_group_operation.go
generated
vendored
@ -1,15 +0,0 @@
|
|||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.4
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
// Delete group operation settings
|
|
||||||
type DeleteGroupOperation struct {
|
|
||||||
GroupId string `json:"GroupId,omitempty"`
|
|
||||||
}
|
|
@ -1,27 +0,0 @@
|
|||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.1
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type DeviceType string
|
|
||||||
|
|
||||||
const (
|
|
||||||
ClassGUID DeviceType = "ClassGuid"
|
|
||||||
DeviceInstanceID DeviceType = "DeviceInstance"
|
|
||||||
GPUMirror DeviceType = "GpuMirror"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Device struct {
|
|
||||||
// The type of device to assign to the container.
|
|
||||||
Type DeviceType `json:"Type,omitempty"`
|
|
||||||
// The interface class guid of the device interfaces to assign to the container. Only used when Type is ClassGuid.
|
|
||||||
InterfaceClassGuid string `json:"InterfaceClassGuid,omitempty"`
|
|
||||||
// The location path of the device to assign to the container. Only used when Type is DeviceInstanceID.
|
|
||||||
LocationPath string `json:"LocationPath,omitempty"`
|
|
||||||
}
|
|
@ -1,46 +0,0 @@
|
|||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.1
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type Devices struct {
|
|
||||||
ComPorts map[string]ComPort `json:"ComPorts,omitempty"`
|
|
||||||
|
|
||||||
Scsi map[string]Scsi `json:"Scsi,omitempty"`
|
|
||||||
|
|
||||||
VirtualPMem *VirtualPMemController `json:"VirtualPMem,omitempty"`
|
|
||||||
|
|
||||||
NetworkAdapters map[string]NetworkAdapter `json:"NetworkAdapters,omitempty"`
|
|
||||||
|
|
||||||
VideoMonitor *VideoMonitor `json:"VideoMonitor,omitempty"`
|
|
||||||
|
|
||||||
Keyboard *Keyboard `json:"Keyboard,omitempty"`
|
|
||||||
|
|
||||||
Mouse *Mouse `json:"Mouse,omitempty"`
|
|
||||||
|
|
||||||
HvSocket *HvSocket2 `json:"HvSocket,omitempty"`
|
|
||||||
|
|
||||||
EnhancedModeVideo *EnhancedModeVideo `json:"EnhancedModeVideo,omitempty"`
|
|
||||||
|
|
||||||
GuestCrashReporting *GuestCrashReporting `json:"GuestCrashReporting,omitempty"`
|
|
||||||
|
|
||||||
VirtualSmb *VirtualSmb `json:"VirtualSmb,omitempty"`
|
|
||||||
|
|
||||||
Plan9 *Plan9 `json:"Plan9,omitempty"`
|
|
||||||
|
|
||||||
Battery *Battery `json:"Battery,omitempty"`
|
|
||||||
|
|
||||||
FlexibleIov map[string]FlexibleIoDevice `json:"FlexibleIov,omitempty"`
|
|
||||||
|
|
||||||
SharedMemory *SharedMemoryConfiguration `json:"SharedMemory,omitempty"`
|
|
||||||
|
|
||||||
// TODO: This is pre-release support in schema 2.3. Need to add build number
|
|
||||||
// docs when a public build with this is out.
|
|
||||||
VirtualPci map[string]VirtualPciDevice `json:",omitempty"`
|
|
||||||
}
|
|
14
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/enhanced_mode_video.go
generated
vendored
14
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/enhanced_mode_video.go
generated
vendored
@ -1,14 +0,0 @@
|
|||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.1
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type EnhancedModeVideo struct {
|
|
||||||
ConnectionOptions *RdpConnectionOptions `json:"ConnectionOptions,omitempty"`
|
|
||||||
}
|
|
18
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/flexible_io_device.go
generated
vendored
18
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/flexible_io_device.go
generated
vendored
@ -1,18 +0,0 @@
|
|||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.1
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type FlexibleIoDevice struct {
|
|
||||||
EmulatorId string `json:"EmulatorId,omitempty"`
|
|
||||||
|
|
||||||
HostingModel string `json:"HostingModel,omitempty"`
|
|
||||||
|
|
||||||
Configuration []string `json:"Configuration,omitempty"`
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.1
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type GuestConnection struct {
|
|
||||||
|
|
||||||
// Use Vsock rather than Hyper-V sockets to communicate with the guest service.
|
|
||||||
UseVsock bool `json:"UseVsock,omitempty"`
|
|
||||||
|
|
||||||
// Don't disconnect the guest connection when pausing the virtual machine.
|
|
||||||
UseConnectedSuspend bool `json:"UseConnectedSuspend,omitempty"`
|
|
||||||
}
|
|
21
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/guest_connection_info.go
generated
vendored
21
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/guest_connection_info.go
generated
vendored
@ -1,21 +0,0 @@
|
|||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.1
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
// Information about the guest.
|
|
||||||
type GuestConnectionInfo struct {
|
|
||||||
|
|
||||||
// Each schema version x.y stands for the range of versions a.b where a==x and b<=y. This list comes from the SupportedSchemaVersions field in GcsCapabilities.
|
|
||||||
SupportedSchemaVersions []Version `json:"SupportedSchemaVersions,omitempty"`
|
|
||||||
|
|
||||||
ProtocolVersion int32 `json:"ProtocolVersion,omitempty"`
|
|
||||||
|
|
||||||
GuestDefinedCapabilities *interface{} `json:"GuestDefinedCapabilities,omitempty"`
|
|
||||||
}
|
|
14
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/guest_crash_reporting.go
generated
vendored
14
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/guest_crash_reporting.go
generated
vendored
@ -1,14 +0,0 @@
|
|||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.1
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type GuestCrashReporting struct {
|
|
||||||
WindowsCrashSettings *WindowsCrashReporting `json:"WindowsCrashSettings,omitempty"`
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.1
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type GuestOs struct {
|
|
||||||
HostName string `json:"HostName,omitempty"`
|
|
||||||
}
|
|
@ -1,25 +0,0 @@
|
|||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.1
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type GuestState struct {
|
|
||||||
|
|
||||||
// The path to an existing file uses for persistent guest state storage. An empty string indicates the system should initialize new transient, in-memory guest state.
|
|
||||||
GuestStateFilePath string `json:"GuestStateFilePath,omitempty"`
|
|
||||||
|
|
||||||
// The guest state file type affected by different guest isolation modes - whether a file or block storage.
|
|
||||||
GuestStateFileType string `json:"GuestStateFileType,omitempty"`
|
|
||||||
|
|
||||||
// The path to an existing file for persistent runtime state storage. An empty string indicates the system should initialize new transient, in-memory runtime state.
|
|
||||||
RuntimeStateFilePath string `json:"RuntimeStateFilePath,omitempty"`
|
|
||||||
|
|
||||||
// If true, the guest state and runtime state files will be used as templates to populate transient, in-memory state instead of using the files as persistent backing store.
|
|
||||||
ForceTransientState bool `json:"ForceTransientState,omitempty"`
|
|
||||||
}
|
|
@ -1,16 +0,0 @@
|
|||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.4
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
// Structure used to request a service processor modification
|
|
||||||
type HostProcessorModificationRequest struct {
|
|
||||||
Operation CPUGroupOperation `json:"Operation,omitempty"`
|
|
||||||
OperationDetails interface{} `json:"OperationDetails,omitempty"`
|
|
||||||
}
|
|
@ -1,16 +0,0 @@
|
|||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.1
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type HostedSystem struct {
|
|
||||||
SchemaVersion *Version `json:"SchemaVersion,omitempty"`
|
|
||||||
|
|
||||||
Container *Container `json:"Container,omitempty"`
|
|
||||||
}
|
|
@ -1,16 +0,0 @@
|
|||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.1
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type HvSocket struct {
|
|
||||||
Config *HvSocketSystemConfig `json:"Config,omitempty"`
|
|
||||||
|
|
||||||
EnablePowerShellDirect bool `json:"EnablePowerShellDirect,omitempty"`
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.1
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
// HvSocket configuration for a VM
|
|
||||||
type HvSocket2 struct {
|
|
||||||
HvSocketConfig *HvSocketSystemConfig `json:"HvSocketConfig,omitempty"`
|
|
||||||
}
|
|
@ -1,17 +0,0 @@
|
|||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.4
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
// This class defines address settings applied to a VM
|
|
||||||
// by the GCS every time a VM starts or restores.
|
|
||||||
type HvSocketAddress struct {
|
|
||||||
LocalAddress string `json:"LocalAddress,omitempty"`
|
|
||||||
ParentAddress string `json:"ParentAddress,omitempty"`
|
|
||||||
}
|
|
28
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/hv_socket_service_config.go
generated
vendored
28
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/hv_socket_service_config.go
generated
vendored
@ -1,28 +0,0 @@
|
|||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.1
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type HvSocketServiceConfig struct {
|
|
||||||
|
|
||||||
// SDDL string that HvSocket will check before allowing a host process to bind to this specific service. If not specified, defaults to the system DefaultBindSecurityDescriptor, defined in HvSocketSystemWpConfig in V1.
|
|
||||||
BindSecurityDescriptor string `json:"BindSecurityDescriptor,omitempty"`
|
|
||||||
|
|
||||||
// SDDL string that HvSocket will check before allowing a host process to connect to this specific service. If not specified, defaults to the system DefaultConnectSecurityDescriptor, defined in HvSocketSystemWpConfig in V1.
|
|
||||||
ConnectSecurityDescriptor string `json:"ConnectSecurityDescriptor,omitempty"`
|
|
||||||
|
|
||||||
// If true, HvSocket will process wildcard binds for this service/system combination. Wildcard binds are secured in the registry at SOFTWARE/Microsoft/Windows NT/CurrentVersion/Virtualization/HvSocket/WildcardDescriptors
|
|
||||||
AllowWildcardBinds bool `json:"AllowWildcardBinds,omitempty"`
|
|
||||||
|
|
||||||
// Disabled controls whether the HvSocket service is accepting connection requests.
|
|
||||||
// This set to true will make the service refuse all incoming connections as well as cancel
|
|
||||||
// any connections already established. The service itself will still be active however
|
|
||||||
// and can be re-enabled at a future time.
|
|
||||||
Disabled bool `json:"Disabled,omitempty"`
|
|
||||||
}
|
|
22
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/hv_socket_system_config.go
generated
vendored
22
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/hv_socket_system_config.go
generated
vendored
@ -1,22 +0,0 @@
|
|||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.1
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
// This is the HCS Schema version of the HvSocket configuration. The VMWP version is located in Config.Devices.IC in V1.
|
|
||||||
type HvSocketSystemConfig struct {
|
|
||||||
|
|
||||||
// SDDL string that HvSocket will check before allowing a host process to bind to an unlisted service for this specific container/VM (not wildcard binds).
|
|
||||||
DefaultBindSecurityDescriptor string `json:"DefaultBindSecurityDescriptor,omitempty"`
|
|
||||||
|
|
||||||
// SDDL string that HvSocket will check before allowing a host process to connect to an unlisted service in the VM/container.
|
|
||||||
DefaultConnectSecurityDescriptor string `json:"DefaultConnectSecurityDescriptor,omitempty"`
|
|
||||||
|
|
||||||
ServiceTable map[string]HvSocketServiceConfig `json:"ServiceTable,omitempty"`
|
|
||||||
}
|
|
42
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/interrupt_moderation_mode.go
generated
vendored
42
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/interrupt_moderation_mode.go
generated
vendored
@ -1,42 +0,0 @@
|
|||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.4
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type InterruptModerationName string
|
|
||||||
|
|
||||||
// The valid interrupt moderation modes for I/O virtualization (IOV) offloading.
|
|
||||||
const (
|
|
||||||
DefaultName InterruptModerationName = "Default"
|
|
||||||
AdaptiveName InterruptModerationName = "Adaptive"
|
|
||||||
OffName InterruptModerationName = "Off"
|
|
||||||
LowName InterruptModerationName = "Low"
|
|
||||||
MediumName InterruptModerationName = "Medium"
|
|
||||||
HighName InterruptModerationName = "High"
|
|
||||||
)
|
|
||||||
|
|
||||||
type InterruptModerationValue uint32
|
|
||||||
|
|
||||||
const (
|
|
||||||
DefaultValue InterruptModerationValue = iota
|
|
||||||
AdaptiveValue
|
|
||||||
OffValue
|
|
||||||
LowValue InterruptModerationValue = 100
|
|
||||||
MediumValue InterruptModerationValue = 200
|
|
||||||
HighValue InterruptModerationValue = 300
|
|
||||||
)
|
|
||||||
|
|
||||||
var InterruptModerationValueToName = map[InterruptModerationValue]InterruptModerationName{
|
|
||||||
DefaultValue: DefaultName,
|
|
||||||
AdaptiveValue: AdaptiveName,
|
|
||||||
OffValue: OffName,
|
|
||||||
LowValue: LowName,
|
|
||||||
MediumValue: MediumName,
|
|
||||||
HighValue: HighName,
|
|
||||||
}
|
|
@ -1,22 +0,0 @@
|
|||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.4
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type IovSettings struct {
|
|
||||||
// The weight assigned to this port for I/O virtualization (IOV) offloading.
|
|
||||||
// Setting this to 0 disables IOV offloading.
|
|
||||||
OffloadWeight *uint32 `json:"OffloadWeight,omitempty"`
|
|
||||||
|
|
||||||
// The number of queue pairs requested for this port for I/O virtualization (IOV) offloading.
|
|
||||||
QueuePairsRequested *uint32 `json:"QueuePairsRequested,omitempty"`
|
|
||||||
|
|
||||||
// The interrupt moderation mode for I/O virtualization (IOV) offloading.
|
|
||||||
InterruptModeration *InterruptModerationName `json:"InterruptModeration,omitempty"`
|
|
||||||
}
|
|
21
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/isolation_settings.go
generated
vendored
21
vendor/github.com/Microsoft/hcsshim/internal/hcs/schema2/isolation_settings.go
generated
vendored
@ -1,21 +0,0 @@
|
|||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.4
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type IsolationSettings struct {
|
|
||||||
// Guest isolation type options to decide virtual trust levels of virtual machine
|
|
||||||
IsolationType string `json:"IsolationType,omitempty"`
|
|
||||||
// Configuration to debug HCL layer for HCS VM TODO: Task 31102306: Miss the way to prevent the exposure of private debug configuration in HCS TODO: Think about the secret configurations which are private in VMMS VM (only edit by hvsedit)
|
|
||||||
DebugHost string `json:"DebugHost,omitempty"`
|
|
||||||
DebugPort int64 `json:"DebugPort,omitempty"`
|
|
||||||
// Optional data passed by host on isolated virtual machine start
|
|
||||||
LaunchData string `json:"LaunchData,omitempty"`
|
|
||||||
HclEnabled bool `json:"HclEnabled,omitempty"`
|
|
||||||
}
|
|
@ -1,13 +0,0 @@
|
|||||||
/*
|
|
||||||
* HCS API
|
|
||||||
*
|
|
||||||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
|
|
||||||
*
|
|
||||||
* API version: 2.1
|
|
||||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
|
||||||
*/
|
|
||||||
|
|
||||||
package hcsschema
|
|
||||||
|
|
||||||
type Keyboard struct {
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue