...

Source file src/github.com/Microsoft/hcsshim/hcn/hcnendpoint.go

Documentation: github.com/Microsoft/hcsshim/hcn

     1  //go:build windows
     2  
     3  package hcn
     4  
     5  import (
     6  	"encoding/json"
     7  	"errors"
     8  
     9  	"github.com/Microsoft/go-winio/pkg/guid"
    10  	"github.com/Microsoft/hcsshim/internal/interop"
    11  	"github.com/sirupsen/logrus"
    12  )
    13  
    14  // IpConfig is associated with an endpoint
    15  type IpConfig struct {
    16  	IpAddress    string `json:",omitempty"`
    17  	PrefixLength uint8  `json:",omitempty"`
    18  }
    19  
    20  // EndpointFlags are special settings on an endpoint.
    21  type EndpointFlags uint32
    22  
    23  var (
    24  	// EndpointFlagsNone is the default.
    25  	EndpointFlagsNone EndpointFlags
    26  	// EndpointFlagsRemoteEndpoint means that an endpoint is on another host.
    27  	EndpointFlagsRemoteEndpoint EndpointFlags = 1
    28  )
    29  
    30  // HostComputeEndpoint represents a network endpoint
    31  type HostComputeEndpoint struct {
    32  	Id                   string           `json:"ID,omitempty"`
    33  	Name                 string           `json:",omitempty"`
    34  	HostComputeNetwork   string           `json:",omitempty"` // GUID
    35  	HostComputeNamespace string           `json:",omitempty"` // GUID
    36  	Policies             []EndpointPolicy `json:",omitempty"`
    37  	IpConfigurations     []IpConfig       `json:",omitempty"`
    38  	Dns                  Dns              `json:",omitempty"`
    39  	Routes               []Route          `json:",omitempty"`
    40  	MacAddress           string           `json:",omitempty"`
    41  	Flags                EndpointFlags    `json:",omitempty"`
    42  	Health               Health           `json:",omitempty"`
    43  	SchemaVersion        SchemaVersion    `json:",omitempty"`
    44  }
    45  
    46  // EndpointResourceType are the two different Endpoint settings resources.
    47  type EndpointResourceType string
    48  
    49  var (
    50  	// EndpointResourceTypePolicy is for Endpoint Policies. Ex: ACL, NAT
    51  	EndpointResourceTypePolicy EndpointResourceType = "Policy"
    52  	// EndpointResourceTypePort is for Endpoint Port settings.
    53  	EndpointResourceTypePort EndpointResourceType = "Port"
    54  )
    55  
    56  // ModifyEndpointSettingRequest is the structure used to send request to modify an endpoint.
    57  // Used to update policy/port on an endpoint.
    58  type ModifyEndpointSettingRequest struct {
    59  	ResourceType EndpointResourceType `json:",omitempty"` // Policy, Port
    60  	RequestType  RequestType          `json:",omitempty"` // Add, Remove, Update, Refresh
    61  	Settings     json.RawMessage      `json:",omitempty"`
    62  }
    63  
    64  // VmEndpointRequest creates a switch port with identifier `PortId`.
    65  type VmEndpointRequest struct {
    66  	PortId           guid.GUID `json:",omitempty"`
    67  	VirtualNicName   string    `json:",omitempty"`
    68  	VirtualMachineId guid.GUID `json:",omitempty"`
    69  }
    70  
    71  type PolicyEndpointRequest struct {
    72  	Policies []EndpointPolicy `json:",omitempty"`
    73  }
    74  
    75  func getEndpoint(endpointGUID guid.GUID, query string) (*HostComputeEndpoint, error) {
    76  	// Open endpoint.
    77  	var (
    78  		endpointHandle   hcnEndpoint
    79  		resultBuffer     *uint16
    80  		propertiesBuffer *uint16
    81  	)
    82  	hr := hcnOpenEndpoint(&endpointGUID, &endpointHandle, &resultBuffer)
    83  	if err := checkForErrors("hcnOpenEndpoint", hr, resultBuffer); err != nil {
    84  		return nil, err
    85  	}
    86  	// Query endpoint.
    87  	hr = hcnQueryEndpointProperties(endpointHandle, query, &propertiesBuffer, &resultBuffer)
    88  	if err := checkForErrors("hcnQueryEndpointProperties", hr, resultBuffer); err != nil {
    89  		return nil, err
    90  	}
    91  	properties := interop.ConvertAndFreeCoTaskMemString(propertiesBuffer)
    92  	// Close endpoint.
    93  	hr = hcnCloseEndpoint(endpointHandle)
    94  	if err := checkForErrors("hcnCloseEndpoint", hr, nil); err != nil {
    95  		return nil, err
    96  	}
    97  	// Convert output to HostComputeEndpoint
    98  	var outputEndpoint HostComputeEndpoint
    99  	if err := json.Unmarshal([]byte(properties), &outputEndpoint); err != nil {
   100  		return nil, err
   101  	}
   102  	return &outputEndpoint, nil
   103  }
   104  
   105  func enumerateEndpoints(query string) ([]HostComputeEndpoint, error) {
   106  	// Enumerate all Endpoint Guids
   107  	var (
   108  		resultBuffer   *uint16
   109  		endpointBuffer *uint16
   110  	)
   111  	hr := hcnEnumerateEndpoints(query, &endpointBuffer, &resultBuffer)
   112  	if err := checkForErrors("hcnEnumerateEndpoints", hr, resultBuffer); err != nil {
   113  		return nil, err
   114  	}
   115  
   116  	endpoints := interop.ConvertAndFreeCoTaskMemString(endpointBuffer)
   117  	var endpointIds []guid.GUID
   118  	err := json.Unmarshal([]byte(endpoints), &endpointIds)
   119  	if err != nil {
   120  		return nil, err
   121  	}
   122  
   123  	var outputEndpoints []HostComputeEndpoint
   124  	for _, endpointGUID := range endpointIds {
   125  		endpoint, err := getEndpoint(endpointGUID, query)
   126  		if err != nil {
   127  			return nil, err
   128  		}
   129  		outputEndpoints = append(outputEndpoints, *endpoint)
   130  	}
   131  	return outputEndpoints, nil
   132  }
   133  
   134  func createEndpoint(networkID string, endpointSettings string) (*HostComputeEndpoint, error) {
   135  	networkGUID, err := guid.FromString(networkID)
   136  	if err != nil {
   137  		return nil, errInvalidNetworkID
   138  	}
   139  	// Open network.
   140  	var networkHandle hcnNetwork
   141  	var resultBuffer *uint16
   142  	hr := hcnOpenNetwork(&networkGUID, &networkHandle, &resultBuffer)
   143  	if err := checkForErrors("hcnOpenNetwork", hr, resultBuffer); err != nil {
   144  		return nil, err
   145  	}
   146  	// Create endpoint.
   147  	endpointID := guid.GUID{}
   148  	var endpointHandle hcnEndpoint
   149  	hr = hcnCreateEndpoint(networkHandle, &endpointID, endpointSettings, &endpointHandle, &resultBuffer)
   150  	if err := checkForErrors("hcnCreateEndpoint", hr, resultBuffer); err != nil {
   151  		return nil, err
   152  	}
   153  	// Query endpoint.
   154  	hcnQuery := defaultQuery()
   155  	query, err := json.Marshal(hcnQuery)
   156  	if err != nil {
   157  		return nil, err
   158  	}
   159  	var propertiesBuffer *uint16
   160  	hr = hcnQueryEndpointProperties(endpointHandle, string(query), &propertiesBuffer, &resultBuffer)
   161  	if err := checkForErrors("hcnQueryEndpointProperties", hr, resultBuffer); err != nil {
   162  		return nil, err
   163  	}
   164  	properties := interop.ConvertAndFreeCoTaskMemString(propertiesBuffer)
   165  	// Close endpoint.
   166  	hr = hcnCloseEndpoint(endpointHandle)
   167  	if err := checkForErrors("hcnCloseEndpoint", hr, nil); err != nil {
   168  		return nil, err
   169  	}
   170  	// Close network.
   171  	hr = hcnCloseNetwork(networkHandle)
   172  	if err := checkForErrors("hcnCloseNetwork", hr, nil); err != nil {
   173  		return nil, err
   174  	}
   175  	// Convert output to HostComputeEndpoint
   176  	var outputEndpoint HostComputeEndpoint
   177  	if err := json.Unmarshal([]byte(properties), &outputEndpoint); err != nil {
   178  		return nil, err
   179  	}
   180  	return &outputEndpoint, nil
   181  }
   182  
   183  func modifyEndpoint(endpointID string, settings string) (*HostComputeEndpoint, error) {
   184  	endpointGUID, err := guid.FromString(endpointID)
   185  	if err != nil {
   186  		return nil, errInvalidEndpointID
   187  	}
   188  	// Open endpoint
   189  	var (
   190  		endpointHandle   hcnEndpoint
   191  		resultBuffer     *uint16
   192  		propertiesBuffer *uint16
   193  	)
   194  	hr := hcnOpenEndpoint(&endpointGUID, &endpointHandle, &resultBuffer)
   195  	if err := checkForErrors("hcnOpenEndpoint", hr, resultBuffer); err != nil {
   196  		return nil, err
   197  	}
   198  	// Modify endpoint
   199  	hr = hcnModifyEndpoint(endpointHandle, settings, &resultBuffer)
   200  	if err := checkForErrors("hcnModifyEndpoint", hr, resultBuffer); err != nil {
   201  		return nil, err
   202  	}
   203  	// Query endpoint.
   204  	hcnQuery := defaultQuery()
   205  	query, err := json.Marshal(hcnQuery)
   206  	if err != nil {
   207  		return nil, err
   208  	}
   209  	hr = hcnQueryEndpointProperties(endpointHandle, string(query), &propertiesBuffer, &resultBuffer)
   210  	if err := checkForErrors("hcnQueryEndpointProperties", hr, resultBuffer); err != nil {
   211  		return nil, err
   212  	}
   213  	properties := interop.ConvertAndFreeCoTaskMemString(propertiesBuffer)
   214  	// Close endpoint.
   215  	hr = hcnCloseEndpoint(endpointHandle)
   216  	if err := checkForErrors("hcnCloseEndpoint", hr, nil); err != nil {
   217  		return nil, err
   218  	}
   219  	// Convert output to HostComputeEndpoint
   220  	var outputEndpoint HostComputeEndpoint
   221  	if err := json.Unmarshal([]byte(properties), &outputEndpoint); err != nil {
   222  		return nil, err
   223  	}
   224  	return &outputEndpoint, nil
   225  }
   226  
   227  func deleteEndpoint(endpointID string) error {
   228  	endpointGUID, err := guid.FromString(endpointID)
   229  	if err != nil {
   230  		return errInvalidEndpointID
   231  	}
   232  	var resultBuffer *uint16
   233  	hr := hcnDeleteEndpoint(&endpointGUID, &resultBuffer)
   234  	if err := checkForErrors("hcnDeleteEndpoint", hr, resultBuffer); err != nil {
   235  		return err
   236  	}
   237  	return nil
   238  }
   239  
   240  // ListEndpoints makes a call to list all available endpoints.
   241  func ListEndpoints() ([]HostComputeEndpoint, error) {
   242  	hcnQuery := defaultQuery()
   243  	endpoints, err := ListEndpointsQuery(hcnQuery)
   244  	if err != nil {
   245  		return nil, err
   246  	}
   247  	return endpoints, nil
   248  }
   249  
   250  // ListEndpointsQuery makes a call to query the list of available endpoints.
   251  func ListEndpointsQuery(query HostComputeQuery) ([]HostComputeEndpoint, error) {
   252  	queryJSON, err := json.Marshal(query)
   253  	if err != nil {
   254  		return nil, err
   255  	}
   256  
   257  	endpoints, err := enumerateEndpoints(string(queryJSON))
   258  	if err != nil {
   259  		return nil, err
   260  	}
   261  	return endpoints, nil
   262  }
   263  
   264  // ListEndpointsOfNetwork queries the list of endpoints on a network.
   265  func ListEndpointsOfNetwork(networkID string) ([]HostComputeEndpoint, error) {
   266  	hcnQuery := defaultQuery()
   267  	// TODO: Once query can convert schema, change to {HostComputeNetwork:networkId}
   268  	mapA := map[string]string{"VirtualNetwork": networkID}
   269  	filter, err := json.Marshal(mapA)
   270  	if err != nil {
   271  		return nil, err
   272  	}
   273  	hcnQuery.Filter = string(filter)
   274  
   275  	return ListEndpointsQuery(hcnQuery)
   276  }
   277  
   278  // GetEndpointByID returns an endpoint specified by Id
   279  func GetEndpointByID(endpointID string) (*HostComputeEndpoint, error) {
   280  	hcnQuery := defaultQuery()
   281  	mapA := map[string]string{"ID": endpointID}
   282  	filter, err := json.Marshal(mapA)
   283  	if err != nil {
   284  		return nil, err
   285  	}
   286  	hcnQuery.Filter = string(filter)
   287  
   288  	endpoints, err := ListEndpointsQuery(hcnQuery)
   289  	if err != nil {
   290  		return nil, err
   291  	}
   292  	if len(endpoints) == 0 {
   293  		return nil, EndpointNotFoundError{EndpointID: endpointID}
   294  	}
   295  	return &endpoints[0], err
   296  }
   297  
   298  // GetEndpointByName returns an endpoint specified by Name
   299  func GetEndpointByName(endpointName string) (*HostComputeEndpoint, error) {
   300  	hcnQuery := defaultQuery()
   301  	mapA := map[string]string{"Name": endpointName}
   302  	filter, err := json.Marshal(mapA)
   303  	if err != nil {
   304  		return nil, err
   305  	}
   306  	hcnQuery.Filter = string(filter)
   307  
   308  	endpoints, err := ListEndpointsQuery(hcnQuery)
   309  	if err != nil {
   310  		return nil, err
   311  	}
   312  	if len(endpoints) == 0 {
   313  		return nil, EndpointNotFoundError{EndpointName: endpointName}
   314  	}
   315  	return &endpoints[0], err
   316  }
   317  
   318  // Create Endpoint.
   319  func (endpoint *HostComputeEndpoint) Create() (*HostComputeEndpoint, error) {
   320  	logrus.Debugf("hcn::HostComputeEndpoint::Create id=%s", endpoint.Id)
   321  
   322  	if endpoint.HostComputeNamespace != "" {
   323  		return nil, errors.New("endpoint create error, endpoint json HostComputeNamespace is read only and should not be set")
   324  	}
   325  
   326  	jsonString, err := json.Marshal(endpoint)
   327  	if err != nil {
   328  		return nil, err
   329  	}
   330  
   331  	logrus.Debugf("hcn::HostComputeEndpoint::Create JSON: %s", jsonString)
   332  	endpoint, hcnErr := createEndpoint(endpoint.HostComputeNetwork, string(jsonString))
   333  	if hcnErr != nil {
   334  		return nil, hcnErr
   335  	}
   336  	return endpoint, nil
   337  }
   338  
   339  // Delete Endpoint.
   340  func (endpoint *HostComputeEndpoint) Delete() error {
   341  	logrus.Debugf("hcn::HostComputeEndpoint::Delete id=%s", endpoint.Id)
   342  
   343  	if err := deleteEndpoint(endpoint.Id); err != nil {
   344  		return err
   345  	}
   346  	return nil
   347  }
   348  
   349  // ModifyEndpointSettings updates the Port/Policy of an Endpoint.
   350  func ModifyEndpointSettings(endpointID string, request *ModifyEndpointSettingRequest) error {
   351  	logrus.Debugf("hcn::HostComputeEndpoint::ModifyEndpointSettings id=%s", endpointID)
   352  
   353  	endpointSettingsRequest, err := json.Marshal(request)
   354  	if err != nil {
   355  		return err
   356  	}
   357  
   358  	_, err = modifyEndpoint(endpointID, string(endpointSettingsRequest))
   359  	if err != nil {
   360  		return err
   361  	}
   362  	return nil
   363  }
   364  
   365  // ApplyPolicy applies a Policy (ex: ACL) on the Endpoint.
   366  func (endpoint *HostComputeEndpoint) ApplyPolicy(requestType RequestType, endpointPolicy PolicyEndpointRequest) error {
   367  	logrus.Debugf("hcn::HostComputeEndpoint::ApplyPolicy id=%s", endpoint.Id)
   368  
   369  	settingsJSON, err := json.Marshal(endpointPolicy)
   370  	if err != nil {
   371  		return err
   372  	}
   373  	requestMessage := &ModifyEndpointSettingRequest{
   374  		ResourceType: EndpointResourceTypePolicy,
   375  		RequestType:  requestType,
   376  		Settings:     settingsJSON,
   377  	}
   378  
   379  	return ModifyEndpointSettings(endpoint.Id, requestMessage)
   380  }
   381  
   382  // NamespaceAttach modifies a Namespace to add an endpoint.
   383  func (endpoint *HostComputeEndpoint) NamespaceAttach(namespaceID string) error {
   384  	return AddNamespaceEndpoint(namespaceID, endpoint.Id)
   385  }
   386  
   387  // NamespaceDetach modifies a Namespace to remove an endpoint.
   388  func (endpoint *HostComputeEndpoint) NamespaceDetach(namespaceID string) error {
   389  	return RemoveNamespaceEndpoint(namespaceID, endpoint.Id)
   390  }
   391  

View as plain text