mirror of
https://github.com/k3s-io/k3s.git
synced 2024-06-07 19:41:36 +00:00
381 lines
12 KiB
Go
381 lines
12 KiB
Go
package hcn
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
|
|
"github.com/Microsoft/go-winio/pkg/guid"
|
|
"github.com/Microsoft/hcsshim/internal/interop"
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
// IpConfig is assoicated with an endpoint
|
|
type IpConfig struct {
|
|
IpAddress string `json:",omitempty"`
|
|
PrefixLength uint8 `json:",omitempty"`
|
|
}
|
|
|
|
// EndpointFlags are special settings on an endpoint.
|
|
type EndpointFlags uint32
|
|
|
|
var (
|
|
// EndpointFlagsNone is the default.
|
|
EndpointFlagsNone EndpointFlags
|
|
// EndpointFlagsRemoteEndpoint means that an endpoint is on another host.
|
|
EndpointFlagsRemoteEndpoint EndpointFlags = 1
|
|
)
|
|
|
|
// HostComputeEndpoint represents a network endpoint
|
|
type HostComputeEndpoint struct {
|
|
Id string `json:"ID,omitempty"`
|
|
Name string `json:",omitempty"`
|
|
HostComputeNetwork string `json:",omitempty"` // GUID
|
|
HostComputeNamespace string `json:",omitempty"` // GUID
|
|
Policies []EndpointPolicy `json:",omitempty"`
|
|
IpConfigurations []IpConfig `json:",omitempty"`
|
|
Dns Dns `json:",omitempty"`
|
|
Routes []Route `json:",omitempty"`
|
|
MacAddress string `json:",omitempty"`
|
|
Flags EndpointFlags `json:",omitempty"`
|
|
SchemaVersion SchemaVersion `json:",omitempty"`
|
|
}
|
|
|
|
// EndpointResourceType are the two different Endpoint settings resources.
|
|
type EndpointResourceType string
|
|
|
|
var (
|
|
// EndpointResourceTypePolicy is for Endpoint Policies. Ex: ACL, NAT
|
|
EndpointResourceTypePolicy EndpointResourceType = "Policy"
|
|
// EndpointResourceTypePort is for Endpoint Port settings.
|
|
EndpointResourceTypePort EndpointResourceType = "Port"
|
|
)
|
|
|
|
// ModifyEndpointSettingRequest is the structure used to send request to modify an endpoint.
|
|
// Used to update policy/port on an endpoint.
|
|
type ModifyEndpointSettingRequest struct {
|
|
ResourceType EndpointResourceType `json:",omitempty"` // Policy, Port
|
|
RequestType RequestType `json:",omitempty"` // Add, Remove, Update, Refresh
|
|
Settings json.RawMessage `json:",omitempty"`
|
|
}
|
|
|
|
type PolicyEndpointRequest struct {
|
|
Policies []EndpointPolicy `json:",omitempty"`
|
|
}
|
|
|
|
func getEndpoint(endpointGuid guid.GUID, query string) (*HostComputeEndpoint, error) {
|
|
// Open endpoint.
|
|
var (
|
|
endpointHandle hcnEndpoint
|
|
resultBuffer *uint16
|
|
propertiesBuffer *uint16
|
|
)
|
|
hr := hcnOpenEndpoint(&endpointGuid, &endpointHandle, &resultBuffer)
|
|
if err := checkForErrors("hcnOpenEndpoint", hr, resultBuffer); err != nil {
|
|
return nil, err
|
|
}
|
|
// Query endpoint.
|
|
hr = hcnQueryEndpointProperties(endpointHandle, query, &propertiesBuffer, &resultBuffer)
|
|
if err := checkForErrors("hcnQueryEndpointProperties", hr, resultBuffer); err != nil {
|
|
return nil, err
|
|
}
|
|
properties := interop.ConvertAndFreeCoTaskMemString(propertiesBuffer)
|
|
// Close endpoint.
|
|
hr = hcnCloseEndpoint(endpointHandle)
|
|
if err := checkForErrors("hcnCloseEndpoint", hr, nil); err != nil {
|
|
return nil, err
|
|
}
|
|
// Convert output to HostComputeEndpoint
|
|
var outputEndpoint HostComputeEndpoint
|
|
if err := json.Unmarshal([]byte(properties), &outputEndpoint); err != nil {
|
|
return nil, err
|
|
}
|
|
return &outputEndpoint, nil
|
|
}
|
|
|
|
func enumerateEndpoints(query string) ([]HostComputeEndpoint, error) {
|
|
// Enumerate all Endpoint Guids
|
|
var (
|
|
resultBuffer *uint16
|
|
endpointBuffer *uint16
|
|
)
|
|
hr := hcnEnumerateEndpoints(query, &endpointBuffer, &resultBuffer)
|
|
if err := checkForErrors("hcnEnumerateEndpoints", hr, resultBuffer); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
endpoints := interop.ConvertAndFreeCoTaskMemString(endpointBuffer)
|
|
var endpointIds []guid.GUID
|
|
err := json.Unmarshal([]byte(endpoints), &endpointIds)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var outputEndpoints []HostComputeEndpoint
|
|
for _, endpointGuid := range endpointIds {
|
|
endpoint, err := getEndpoint(endpointGuid, query)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
outputEndpoints = append(outputEndpoints, *endpoint)
|
|
}
|
|
return outputEndpoints, nil
|
|
}
|
|
|
|
func createEndpoint(networkId string, endpointSettings string) (*HostComputeEndpoint, error) {
|
|
networkGuid, err := guid.FromString(networkId)
|
|
if err != nil {
|
|
return nil, errInvalidNetworkID
|
|
}
|
|
// Open network.
|
|
var networkHandle hcnNetwork
|
|
var resultBuffer *uint16
|
|
hr := hcnOpenNetwork(&networkGuid, &networkHandle, &resultBuffer)
|
|
if err := checkForErrors("hcnOpenNetwork", hr, resultBuffer); err != nil {
|
|
return nil, err
|
|
}
|
|
// Create endpoint.
|
|
endpointId := guid.GUID{}
|
|
var endpointHandle hcnEndpoint
|
|
hr = hcnCreateEndpoint(networkHandle, &endpointId, endpointSettings, &endpointHandle, &resultBuffer)
|
|
if err := checkForErrors("hcnCreateEndpoint", hr, resultBuffer); err != nil {
|
|
return nil, err
|
|
}
|
|
// Query endpoint.
|
|
hcnQuery := defaultQuery()
|
|
query, err := json.Marshal(hcnQuery)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var propertiesBuffer *uint16
|
|
hr = hcnQueryEndpointProperties(endpointHandle, string(query), &propertiesBuffer, &resultBuffer)
|
|
if err := checkForErrors("hcnQueryEndpointProperties", hr, resultBuffer); err != nil {
|
|
return nil, err
|
|
}
|
|
properties := interop.ConvertAndFreeCoTaskMemString(propertiesBuffer)
|
|
// Close endpoint.
|
|
hr = hcnCloseEndpoint(endpointHandle)
|
|
if err := checkForErrors("hcnCloseEndpoint", hr, nil); err != nil {
|
|
return nil, err
|
|
}
|
|
// Close network.
|
|
hr = hcnCloseNetwork(networkHandle)
|
|
if err := checkForErrors("hcnCloseNetwork", hr, nil); err != nil {
|
|
return nil, err
|
|
}
|
|
// Convert output to HostComputeEndpoint
|
|
var outputEndpoint HostComputeEndpoint
|
|
if err := json.Unmarshal([]byte(properties), &outputEndpoint); err != nil {
|
|
return nil, err
|
|
}
|
|
return &outputEndpoint, nil
|
|
}
|
|
|
|
func modifyEndpoint(endpointId string, settings string) (*HostComputeEndpoint, error) {
|
|
endpointGuid, err := guid.FromString(endpointId)
|
|
if err != nil {
|
|
return nil, errInvalidEndpointID
|
|
}
|
|
// Open endpoint
|
|
var (
|
|
endpointHandle hcnEndpoint
|
|
resultBuffer *uint16
|
|
propertiesBuffer *uint16
|
|
)
|
|
hr := hcnOpenEndpoint(&endpointGuid, &endpointHandle, &resultBuffer)
|
|
if err := checkForErrors("hcnOpenEndpoint", hr, resultBuffer); err != nil {
|
|
return nil, err
|
|
}
|
|
// Modify endpoint
|
|
hr = hcnModifyEndpoint(endpointHandle, settings, &resultBuffer)
|
|
if err := checkForErrors("hcnModifyEndpoint", hr, resultBuffer); err != nil {
|
|
return nil, err
|
|
}
|
|
// Query endpoint.
|
|
hcnQuery := defaultQuery()
|
|
query, err := json.Marshal(hcnQuery)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
hr = hcnQueryEndpointProperties(endpointHandle, string(query), &propertiesBuffer, &resultBuffer)
|
|
if err := checkForErrors("hcnQueryEndpointProperties", hr, resultBuffer); err != nil {
|
|
return nil, err
|
|
}
|
|
properties := interop.ConvertAndFreeCoTaskMemString(propertiesBuffer)
|
|
// Close endpoint.
|
|
hr = hcnCloseEndpoint(endpointHandle)
|
|
if err := checkForErrors("hcnCloseEndpoint", hr, nil); err != nil {
|
|
return nil, err
|
|
}
|
|
// Convert output to HostComputeEndpoint
|
|
var outputEndpoint HostComputeEndpoint
|
|
if err := json.Unmarshal([]byte(properties), &outputEndpoint); err != nil {
|
|
return nil, err
|
|
}
|
|
return &outputEndpoint, nil
|
|
}
|
|
|
|
func deleteEndpoint(endpointId string) error {
|
|
endpointGuid, err := guid.FromString(endpointId)
|
|
if err != nil {
|
|
return errInvalidEndpointID
|
|
}
|
|
var resultBuffer *uint16
|
|
hr := hcnDeleteEndpoint(&endpointGuid, &resultBuffer)
|
|
if err := checkForErrors("hcnDeleteEndpoint", hr, resultBuffer); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// ListEndpoints makes a call to list all available endpoints.
|
|
func ListEndpoints() ([]HostComputeEndpoint, error) {
|
|
hcnQuery := defaultQuery()
|
|
endpoints, err := ListEndpointsQuery(hcnQuery)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return endpoints, nil
|
|
}
|
|
|
|
// ListEndpointsQuery makes a call to query the list of available endpoints.
|
|
func ListEndpointsQuery(query HostComputeQuery) ([]HostComputeEndpoint, error) {
|
|
queryJson, err := json.Marshal(query)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
endpoints, err := enumerateEndpoints(string(queryJson))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return endpoints, nil
|
|
}
|
|
|
|
// ListEndpointsOfNetwork queries the list of endpoints on a network.
|
|
func ListEndpointsOfNetwork(networkId string) ([]HostComputeEndpoint, error) {
|
|
hcnQuery := defaultQuery()
|
|
// TODO: Once query can convert schema, change to {HostComputeNetwork:networkId}
|
|
mapA := map[string]string{"VirtualNetwork": networkId}
|
|
filter, err := json.Marshal(mapA)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
hcnQuery.Filter = string(filter)
|
|
|
|
return ListEndpointsQuery(hcnQuery)
|
|
}
|
|
|
|
// GetEndpointByID returns an endpoint specified by Id
|
|
func GetEndpointByID(endpointId string) (*HostComputeEndpoint, error) {
|
|
hcnQuery := defaultQuery()
|
|
mapA := map[string]string{"ID": endpointId}
|
|
filter, err := json.Marshal(mapA)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
hcnQuery.Filter = string(filter)
|
|
|
|
endpoints, err := ListEndpointsQuery(hcnQuery)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if len(endpoints) == 0 {
|
|
return nil, EndpointNotFoundError{EndpointID: endpointId}
|
|
}
|
|
return &endpoints[0], err
|
|
}
|
|
|
|
// GetEndpointByName returns an endpoint specified by Name
|
|
func GetEndpointByName(endpointName string) (*HostComputeEndpoint, error) {
|
|
hcnQuery := defaultQuery()
|
|
mapA := map[string]string{"Name": endpointName}
|
|
filter, err := json.Marshal(mapA)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
hcnQuery.Filter = string(filter)
|
|
|
|
endpoints, err := ListEndpointsQuery(hcnQuery)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if len(endpoints) == 0 {
|
|
return nil, EndpointNotFoundError{EndpointName: endpointName}
|
|
}
|
|
return &endpoints[0], err
|
|
}
|
|
|
|
// Create Endpoint.
|
|
func (endpoint *HostComputeEndpoint) Create() (*HostComputeEndpoint, error) {
|
|
logrus.Debugf("hcn::HostComputeEndpoint::Create id=%s", endpoint.Id)
|
|
|
|
if endpoint.HostComputeNamespace != "" {
|
|
return nil, errors.New("endpoint create error, endpoint json HostComputeNamespace is read only and should not be set")
|
|
}
|
|
|
|
jsonString, err := json.Marshal(endpoint)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
logrus.Debugf("hcn::HostComputeEndpoint::Create JSON: %s", jsonString)
|
|
endpoint, hcnErr := createEndpoint(endpoint.HostComputeNetwork, string(jsonString))
|
|
if hcnErr != nil {
|
|
return nil, hcnErr
|
|
}
|
|
return endpoint, nil
|
|
}
|
|
|
|
// Delete Endpoint.
|
|
func (endpoint *HostComputeEndpoint) Delete() error {
|
|
logrus.Debugf("hcn::HostComputeEndpoint::Delete id=%s", endpoint.Id)
|
|
|
|
if err := deleteEndpoint(endpoint.Id); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// ModifyEndpointSettings updates the Port/Policy of an Endpoint.
|
|
func ModifyEndpointSettings(endpointId string, request *ModifyEndpointSettingRequest) error {
|
|
logrus.Debugf("hcn::HostComputeEndpoint::ModifyEndpointSettings id=%s", endpointId)
|
|
|
|
endpointSettingsRequest, err := json.Marshal(request)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
_, err = modifyEndpoint(endpointId, string(endpointSettingsRequest))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// ApplyPolicy applies a Policy (ex: ACL) on the Endpoint.
|
|
func (endpoint *HostComputeEndpoint) ApplyPolicy(requestType RequestType, endpointPolicy PolicyEndpointRequest) error {
|
|
logrus.Debugf("hcn::HostComputeEndpoint::ApplyPolicy id=%s", endpoint.Id)
|
|
|
|
settingsJson, err := json.Marshal(endpointPolicy)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
requestMessage := &ModifyEndpointSettingRequest{
|
|
ResourceType: EndpointResourceTypePolicy,
|
|
RequestType: requestType,
|
|
Settings: settingsJson,
|
|
}
|
|
|
|
return ModifyEndpointSettings(endpoint.Id, requestMessage)
|
|
}
|
|
|
|
// NamespaceAttach modifies a Namespace to add an endpoint.
|
|
func (endpoint *HostComputeEndpoint) NamespaceAttach(namespaceId string) error {
|
|
return AddNamespaceEndpoint(namespaceId, endpoint.Id)
|
|
}
|
|
|
|
// NamespaceDetach modifies a Namespace to remove an endpoint.
|
|
func (endpoint *HostComputeEndpoint) NamespaceDetach(namespaceId string) error {
|
|
return RemoveNamespaceEndpoint(namespaceId, endpoint.Id)
|
|
}
|