![dependabot[bot]](/assets/img/avatar_default.png)
Bumps the golang group with 5 updates: | Package | From | To | | --- | --- | --- | | [github.com/Microsoft/hcsshim](https://github.com/Microsoft/hcsshim) | `0.11.4` | `0.12.0` | | [github.com/alexflint/go-filemutex](https://github.com/alexflint/go-filemutex) | `1.2.0` | `1.3.0` | | [github.com/onsi/ginkgo/v2](https://github.com/onsi/ginkgo) | `2.13.2` | `2.16.0` | | [github.com/onsi/gomega](https://github.com/onsi/gomega) | `1.30.0` | `1.31.1` | | [golang.org/x/sys](https://github.com/golang/sys) | `0.15.0` | `0.17.0` | Updates `github.com/Microsoft/hcsshim` from 0.11.4 to 0.12.0 - [Release notes](https://github.com/Microsoft/hcsshim/releases) - [Commits](https://github.com/Microsoft/hcsshim/compare/v0.11.4...v0.12.0) Updates `github.com/alexflint/go-filemutex` from 1.2.0 to 1.3.0 - [Release notes](https://github.com/alexflint/go-filemutex/releases) - [Commits](https://github.com/alexflint/go-filemutex/compare/v1.2.0...v1.3.0) Updates `github.com/onsi/ginkgo/v2` from 2.13.2 to 2.16.0 - [Release notes](https://github.com/onsi/ginkgo/releases) - [Changelog](https://github.com/onsi/ginkgo/blob/master/CHANGELOG.md) - [Commits](https://github.com/onsi/ginkgo/compare/v2.13.2...v2.16.0) Updates `github.com/onsi/gomega` from 1.30.0 to 1.31.1 - [Release notes](https://github.com/onsi/gomega/releases) - [Changelog](https://github.com/onsi/gomega/blob/master/CHANGELOG.md) - [Commits](https://github.com/onsi/gomega/compare/v1.30.0...v1.31.1) Updates `golang.org/x/sys` from 0.15.0 to 0.17.0 - [Commits](https://github.com/golang/sys/compare/v0.15.0...v0.17.0) --- updated-dependencies: - dependency-name: github.com/Microsoft/hcsshim dependency-type: direct:production update-type: version-update:semver-minor dependency-group: golang - dependency-name: github.com/alexflint/go-filemutex dependency-type: direct:production update-type: version-update:semver-minor dependency-group: golang - dependency-name: github.com/onsi/ginkgo/v2 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: golang - dependency-name: github.com/onsi/gomega dependency-type: direct:production update-type: version-update:semver-minor dependency-group: golang - dependency-name: golang.org/x/sys dependency-type: direct:production update-type: version-update:semver-minor dependency-group: golang ... Signed-off-by: dependabot[bot] <support@github.com>
451 lines
14 KiB
Go
451 lines
14 KiB
Go
//go:build windows
|
|
|
|
package hcn
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"os"
|
|
"syscall"
|
|
|
|
"github.com/Microsoft/go-winio/pkg/guid"
|
|
icni "github.com/Microsoft/hcsshim/internal/cni"
|
|
"github.com/Microsoft/hcsshim/internal/interop"
|
|
"github.com/Microsoft/hcsshim/internal/regstate"
|
|
"github.com/Microsoft/hcsshim/internal/runhcs"
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
// NamespaceResourceEndpoint represents an Endpoint attached to a Namespace.
|
|
type NamespaceResourceEndpoint struct {
|
|
Id string `json:"ID,"`
|
|
}
|
|
|
|
// NamespaceResourceContainer represents a Container attached to a Namespace.
|
|
type NamespaceResourceContainer struct {
|
|
Id string `json:"ID,"`
|
|
}
|
|
|
|
// NamespaceResourceType determines whether the Namespace resource is a Container or Endpoint.
|
|
type NamespaceResourceType string
|
|
|
|
var (
|
|
// NamespaceResourceTypeContainer are containers associated with a Namespace.
|
|
NamespaceResourceTypeContainer NamespaceResourceType = "Container"
|
|
// NamespaceResourceTypeEndpoint are endpoints associated with a Namespace.
|
|
NamespaceResourceTypeEndpoint NamespaceResourceType = "Endpoint"
|
|
)
|
|
|
|
// NamespaceResource is associated with a namespace
|
|
type NamespaceResource struct {
|
|
Type NamespaceResourceType `json:","` // Container, Endpoint
|
|
Data json.RawMessage `json:","`
|
|
}
|
|
|
|
// NamespaceType determines whether the Namespace is for a Host or Guest
|
|
type NamespaceType string
|
|
|
|
var (
|
|
// NamespaceTypeHost are host namespaces.
|
|
NamespaceTypeHost NamespaceType = "Host"
|
|
// NamespaceTypeHostDefault are host namespaces in the default compartment.
|
|
NamespaceTypeHostDefault NamespaceType = "HostDefault"
|
|
// NamespaceTypeGuest are guest namespaces.
|
|
NamespaceTypeGuest NamespaceType = "Guest"
|
|
// NamespaceTypeGuestDefault are guest namespaces in the default compartment.
|
|
NamespaceTypeGuestDefault NamespaceType = "GuestDefault"
|
|
)
|
|
|
|
// HostComputeNamespace represents a namespace (AKA compartment) in
|
|
type HostComputeNamespace struct {
|
|
Id string `json:"ID,omitempty"`
|
|
NamespaceId uint32 `json:",omitempty"`
|
|
Type NamespaceType `json:",omitempty"` // Host, HostDefault, Guest, GuestDefault
|
|
Resources []NamespaceResource `json:",omitempty"`
|
|
SchemaVersion SchemaVersion `json:",omitempty"`
|
|
}
|
|
|
|
// ModifyNamespaceSettingRequest is the structure used to send request to modify a namespace.
|
|
// Used to Add/Remove an endpoints and containers to/from a namespace.
|
|
type ModifyNamespaceSettingRequest struct {
|
|
ResourceType NamespaceResourceType `json:",omitempty"` // Container, Endpoint
|
|
RequestType RequestType `json:",omitempty"` // Add, Remove, Update, Refresh
|
|
Settings json.RawMessage `json:",omitempty"`
|
|
}
|
|
|
|
func getNamespace(namespaceGUID guid.GUID, query string) (*HostComputeNamespace, error) {
|
|
// Open namespace.
|
|
var (
|
|
namespaceHandle hcnNamespace
|
|
resultBuffer *uint16
|
|
propertiesBuffer *uint16
|
|
)
|
|
hr := hcnOpenNamespace(&namespaceGUID, &namespaceHandle, &resultBuffer)
|
|
if err := checkForErrors("hcnOpenNamespace", hr, resultBuffer); err != nil {
|
|
return nil, err
|
|
}
|
|
// Query namespace.
|
|
hr = hcnQueryNamespaceProperties(namespaceHandle, query, &propertiesBuffer, &resultBuffer)
|
|
if err := checkForErrors("hcnQueryNamespaceProperties", hr, resultBuffer); err != nil {
|
|
return nil, err
|
|
}
|
|
properties := interop.ConvertAndFreeCoTaskMemString(propertiesBuffer)
|
|
// Close namespace.
|
|
hr = hcnCloseNamespace(namespaceHandle)
|
|
if err := checkForErrors("hcnCloseNamespace", hr, nil); err != nil {
|
|
return nil, err
|
|
}
|
|
// Convert output to HostComputeNamespace
|
|
var outputNamespace HostComputeNamespace
|
|
if err := json.Unmarshal([]byte(properties), &outputNamespace); err != nil {
|
|
return nil, err
|
|
}
|
|
return &outputNamespace, nil
|
|
}
|
|
|
|
func enumerateNamespaces(query string) ([]HostComputeNamespace, error) {
|
|
// Enumerate all Namespace Guids
|
|
var (
|
|
resultBuffer *uint16
|
|
namespaceBuffer *uint16
|
|
)
|
|
hr := hcnEnumerateNamespaces(query, &namespaceBuffer, &resultBuffer)
|
|
if err := checkForErrors("hcnEnumerateNamespaces", hr, resultBuffer); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
namespaces := interop.ConvertAndFreeCoTaskMemString(namespaceBuffer)
|
|
var namespaceIds []guid.GUID
|
|
if err := json.Unmarshal([]byte(namespaces), &namespaceIds); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var outputNamespaces []HostComputeNamespace
|
|
for _, namespaceGUID := range namespaceIds {
|
|
namespace, err := getNamespace(namespaceGUID, query)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
outputNamespaces = append(outputNamespaces, *namespace)
|
|
}
|
|
return outputNamespaces, nil
|
|
}
|
|
|
|
func createNamespace(settings string) (*HostComputeNamespace, error) {
|
|
// Create new namespace.
|
|
var (
|
|
namespaceHandle hcnNamespace
|
|
resultBuffer *uint16
|
|
propertiesBuffer *uint16
|
|
)
|
|
namespaceGUID := guid.GUID{}
|
|
hr := hcnCreateNamespace(&namespaceGUID, settings, &namespaceHandle, &resultBuffer)
|
|
if err := checkForErrors("hcnCreateNamespace", hr, resultBuffer); err != nil {
|
|
return nil, err
|
|
}
|
|
// Query namespace.
|
|
hcnQuery := defaultQuery()
|
|
query, err := json.Marshal(hcnQuery)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
hr = hcnQueryNamespaceProperties(namespaceHandle, string(query), &propertiesBuffer, &resultBuffer)
|
|
if err := checkForErrors("hcnQueryNamespaceProperties", hr, resultBuffer); err != nil {
|
|
return nil, err
|
|
}
|
|
properties := interop.ConvertAndFreeCoTaskMemString(propertiesBuffer)
|
|
// Close namespace.
|
|
hr = hcnCloseNamespace(namespaceHandle)
|
|
if err := checkForErrors("hcnCloseNamespace", hr, nil); err != nil {
|
|
return nil, err
|
|
}
|
|
// Convert output to HostComputeNamespace
|
|
var outputNamespace HostComputeNamespace
|
|
if err := json.Unmarshal([]byte(properties), &outputNamespace); err != nil {
|
|
return nil, err
|
|
}
|
|
return &outputNamespace, nil
|
|
}
|
|
|
|
func modifyNamespace(namespaceID string, settings string) (*HostComputeNamespace, error) {
|
|
namespaceGUID, err := guid.FromString(namespaceID)
|
|
if err != nil {
|
|
return nil, errInvalidNamespaceID
|
|
}
|
|
// Open namespace.
|
|
var (
|
|
namespaceHandle hcnNamespace
|
|
resultBuffer *uint16
|
|
propertiesBuffer *uint16
|
|
)
|
|
hr := hcnOpenNamespace(&namespaceGUID, &namespaceHandle, &resultBuffer)
|
|
if err := checkForErrors("hcnOpenNamespace", hr, resultBuffer); err != nil {
|
|
return nil, err
|
|
}
|
|
// Modify namespace.
|
|
hr = hcnModifyNamespace(namespaceHandle, settings, &resultBuffer)
|
|
if err := checkForErrors("hcnModifyNamespace", hr, resultBuffer); err != nil {
|
|
return nil, err
|
|
}
|
|
// Query namespace.
|
|
hcnQuery := defaultQuery()
|
|
query, err := json.Marshal(hcnQuery)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
hr = hcnQueryNamespaceProperties(namespaceHandle, string(query), &propertiesBuffer, &resultBuffer)
|
|
if err := checkForErrors("hcnQueryNamespaceProperties", hr, resultBuffer); err != nil {
|
|
return nil, err
|
|
}
|
|
properties := interop.ConvertAndFreeCoTaskMemString(propertiesBuffer)
|
|
// Close namespace.
|
|
hr = hcnCloseNamespace(namespaceHandle)
|
|
if err := checkForErrors("hcnCloseNamespace", hr, nil); err != nil {
|
|
return nil, err
|
|
}
|
|
// Convert output to Namespace
|
|
var outputNamespace HostComputeNamespace
|
|
if err := json.Unmarshal([]byte(properties), &outputNamespace); err != nil {
|
|
return nil, err
|
|
}
|
|
return &outputNamespace, nil
|
|
}
|
|
|
|
func deleteNamespace(namespaceID string) error {
|
|
namespaceGUID, err := guid.FromString(namespaceID)
|
|
if err != nil {
|
|
return errInvalidNamespaceID
|
|
}
|
|
var resultBuffer *uint16
|
|
hr := hcnDeleteNamespace(&namespaceGUID, &resultBuffer)
|
|
if err := checkForErrors("hcnDeleteNamespace", hr, resultBuffer); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// ListNamespaces makes a call to list all available namespaces.
|
|
func ListNamespaces() ([]HostComputeNamespace, error) {
|
|
hcnQuery := defaultQuery()
|
|
namespaces, err := ListNamespacesQuery(hcnQuery)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return namespaces, nil
|
|
}
|
|
|
|
// ListNamespacesQuery makes a call to query the list of available namespaces.
|
|
func ListNamespacesQuery(query HostComputeQuery) ([]HostComputeNamespace, error) {
|
|
queryJSON, err := json.Marshal(query)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
namespaces, err := enumerateNamespaces(string(queryJSON))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return namespaces, nil
|
|
}
|
|
|
|
// GetNamespaceByID returns the Namespace specified by Id.
|
|
func GetNamespaceByID(namespaceID string) (*HostComputeNamespace, error) {
|
|
hcnQuery := defaultQuery()
|
|
mapA := map[string]string{"ID": namespaceID}
|
|
filter, err := json.Marshal(mapA)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
hcnQuery.Filter = string(filter)
|
|
|
|
namespaces, err := ListNamespacesQuery(hcnQuery)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if len(namespaces) == 0 {
|
|
return nil, NamespaceNotFoundError{NamespaceID: namespaceID}
|
|
}
|
|
|
|
return &namespaces[0], err
|
|
}
|
|
|
|
// GetNamespaceEndpointIds returns the endpoints of the Namespace specified by Id.
|
|
func GetNamespaceEndpointIds(namespaceID string) ([]string, error) {
|
|
namespace, err := GetNamespaceByID(namespaceID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var endpointsIds []string
|
|
for _, resource := range namespace.Resources {
|
|
if resource.Type == "Endpoint" {
|
|
var endpointResource NamespaceResourceEndpoint
|
|
if err := json.Unmarshal([]byte(resource.Data), &endpointResource); err != nil {
|
|
return nil, err
|
|
}
|
|
endpointsIds = append(endpointsIds, endpointResource.Id)
|
|
}
|
|
}
|
|
return endpointsIds, nil
|
|
}
|
|
|
|
// GetNamespaceContainerIds returns the containers of the Namespace specified by Id.
|
|
func GetNamespaceContainerIds(namespaceID string) ([]string, error) {
|
|
namespace, err := GetNamespaceByID(namespaceID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var containerIds []string
|
|
for _, resource := range namespace.Resources {
|
|
if resource.Type == "Container" {
|
|
var containerResource NamespaceResourceContainer
|
|
if err := json.Unmarshal([]byte(resource.Data), &containerResource); err != nil {
|
|
return nil, err
|
|
}
|
|
containerIds = append(containerIds, containerResource.Id)
|
|
}
|
|
}
|
|
return containerIds, nil
|
|
}
|
|
|
|
// NewNamespace creates a new Namespace object
|
|
func NewNamespace(nsType NamespaceType) *HostComputeNamespace {
|
|
return &HostComputeNamespace{
|
|
Type: nsType,
|
|
SchemaVersion: V2SchemaVersion(),
|
|
}
|
|
}
|
|
|
|
// Create Namespace.
|
|
func (namespace *HostComputeNamespace) Create() (*HostComputeNamespace, error) {
|
|
logrus.Debugf("hcn::HostComputeNamespace::Create id=%s", namespace.Id)
|
|
|
|
jsonString, err := json.Marshal(namespace)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
logrus.Debugf("hcn::HostComputeNamespace::Create JSON: %s", jsonString)
|
|
namespace, hcnErr := createNamespace(string(jsonString))
|
|
if hcnErr != nil {
|
|
return nil, hcnErr
|
|
}
|
|
return namespace, nil
|
|
}
|
|
|
|
// Delete Namespace.
|
|
func (namespace *HostComputeNamespace) Delete() error {
|
|
logrus.Debugf("hcn::HostComputeNamespace::Delete id=%s", namespace.Id)
|
|
|
|
if err := deleteNamespace(namespace.Id); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Sync Namespace endpoints with the appropriate sandbox container holding the
|
|
// network namespace open. If no sandbox container is found for this namespace
|
|
// this method is determined to be a success and will not return an error in
|
|
// this case. If the sandbox container is found and a sync is initiated any
|
|
// failures will be returned via this method.
|
|
//
|
|
// This call initiates a sync between endpoints and the matching UtilityVM
|
|
// hosting those endpoints. It is safe to call for any `NamespaceType` but
|
|
// `NamespaceTypeGuest` is the only case when a sync will actually occur. For
|
|
// `NamespaceTypeHost` the process container will be automatically synchronized
|
|
// when the the endpoint is added via `AddNamespaceEndpoint`.
|
|
//
|
|
// Note: This method sync's both additions and removals of endpoints from a
|
|
// `NamespaceTypeGuest` namespace.
|
|
func (namespace *HostComputeNamespace) Sync() error {
|
|
logrus.WithField("id", namespace.Id).Debugf("hcs::HostComputeNamespace::Sync")
|
|
|
|
// We only attempt a sync for namespace guest.
|
|
if namespace.Type != NamespaceTypeGuest {
|
|
return nil
|
|
}
|
|
|
|
// Look in the registry for the key to map from namespace id to pod-id
|
|
cfg, err := icni.LoadPersistedNamespaceConfig(namespace.Id)
|
|
if err != nil {
|
|
if regstate.IsNotFoundError(err) {
|
|
return nil
|
|
}
|
|
return err
|
|
}
|
|
req := runhcs.VMRequest{
|
|
ID: cfg.ContainerID,
|
|
Op: runhcs.OpSyncNamespace,
|
|
}
|
|
shimPath := runhcs.VMPipePath(cfg.HostUniqueID)
|
|
if err := runhcs.IssueVMRequest(shimPath, &req); err != nil {
|
|
// The shim is likely gone. Simply ignore the sync as if it didn't exist.
|
|
var perr *os.PathError
|
|
if errors.As(err, &perr) && errors.Is(perr.Err, syscall.ERROR_FILE_NOT_FOUND) {
|
|
// Remove the reg key there is no point to try again
|
|
_ = cfg.Remove()
|
|
return nil
|
|
}
|
|
f := map[string]interface{}{
|
|
"id": namespace.Id,
|
|
"container-id": cfg.ContainerID,
|
|
}
|
|
logrus.WithFields(f).
|
|
WithError(err).
|
|
Debugf("hcs::HostComputeNamespace::Sync failed to connect to shim pipe: '%s'", shimPath)
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// ModifyNamespaceSettings updates the Endpoints/Containers of a Namespace.
|
|
func ModifyNamespaceSettings(namespaceID string, request *ModifyNamespaceSettingRequest) error {
|
|
logrus.Debugf("hcn::HostComputeNamespace::ModifyNamespaceSettings id=%s", namespaceID)
|
|
|
|
namespaceSettings, err := json.Marshal(request)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
_, err = modifyNamespace(namespaceID, string(namespaceSettings))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// AddNamespaceEndpoint adds an endpoint to a Namespace.
|
|
func AddNamespaceEndpoint(namespaceID string, endpointID string) error {
|
|
logrus.Debugf("hcn::HostComputeEndpoint::AddNamespaceEndpoint id=%s", endpointID)
|
|
|
|
mapA := map[string]string{"EndpointId": endpointID}
|
|
settingsJSON, err := json.Marshal(mapA)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
requestMessage := &ModifyNamespaceSettingRequest{
|
|
ResourceType: NamespaceResourceTypeEndpoint,
|
|
RequestType: RequestTypeAdd,
|
|
Settings: settingsJSON,
|
|
}
|
|
|
|
return ModifyNamespaceSettings(namespaceID, requestMessage)
|
|
}
|
|
|
|
// RemoveNamespaceEndpoint removes an endpoint from a Namespace.
|
|
func RemoveNamespaceEndpoint(namespaceID string, endpointID string) error {
|
|
logrus.Debugf("hcn::HostComputeNamespace::RemoveNamespaceEndpoint id=%s", endpointID)
|
|
|
|
mapA := map[string]string{"EndpointId": endpointID}
|
|
settingsJSON, err := json.Marshal(mapA)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
requestMessage := &ModifyNamespaceSettingRequest{
|
|
ResourceType: NamespaceResourceTypeEndpoint,
|
|
RequestType: RequestTypeRemove,
|
|
Settings: settingsJSON,
|
|
}
|
|
|
|
return ModifyNamespaceSettings(namespaceID, requestMessage)
|
|
}
|