1package hns
2
3import (
4	"encoding/json"
5	"net"
6
7	"github.com/sirupsen/logrus"
8)
9
10// HNSEndpoint represents a network endpoint in HNS
11type HNSEndpoint struct {
12	Id                 string            `json:"ID,omitempty"`
13	Name               string            `json:",omitempty"`
14	VirtualNetwork     string            `json:",omitempty"`
15	VirtualNetworkName string            `json:",omitempty"`
16	Policies           []json.RawMessage `json:",omitempty"`
17	MacAddress         string            `json:",omitempty"`
18	IPAddress          net.IP            `json:",omitempty"`
19	DNSSuffix          string            `json:",omitempty"`
20	DNSServerList      string            `json:",omitempty"`
21	GatewayAddress     string            `json:",omitempty"`
22	EnableInternalDNS  bool              `json:",omitempty"`
23	DisableICC         bool              `json:",omitempty"`
24	PrefixLength       uint8             `json:",omitempty"`
25	IsRemoteEndpoint   bool              `json:",omitempty"`
26	Namespace          *Namespace        `json:",omitempty"`
27}
28
29//SystemType represents the type of the system on which actions are done
30type SystemType string
31
32// SystemType const
33const (
34	ContainerType      SystemType = "Container"
35	VirtualMachineType SystemType = "VirtualMachine"
36	HostType           SystemType = "Host"
37)
38
39// EndpointAttachDetachRequest is the structure used to send request to the container to modify the system
40// Supported resource types are Network and Request Types are Add/Remove
41type EndpointAttachDetachRequest struct {
42	ContainerID    string     `json:"ContainerId,omitempty"`
43	SystemType     SystemType `json:"SystemType"`
44	CompartmentID  uint16     `json:"CompartmentId,omitempty"`
45	VirtualNICName string     `json:"VirtualNicName,omitempty"`
46}
47
48// EndpointResquestResponse is object to get the endpoint request response
49type EndpointResquestResponse struct {
50	Success bool
51	Error   string
52}
53
54// HNSEndpointRequest makes a HNS call to modify/query a network endpoint
55func HNSEndpointRequest(method, path, request string) (*HNSEndpoint, error) {
56	endpoint := &HNSEndpoint{}
57	err := hnsCall(method, "/endpoints/"+path, request, &endpoint)
58	if err != nil {
59		return nil, err
60	}
61
62	return endpoint, nil
63}
64
65// HNSListEndpointRequest makes a HNS call to query the list of available endpoints
66func HNSListEndpointRequest() ([]HNSEndpoint, error) {
67	var endpoint []HNSEndpoint
68	err := hnsCall("GET", "/endpoints/", "", &endpoint)
69	if err != nil {
70		return nil, err
71	}
72
73	return endpoint, nil
74}
75
76// GetHNSEndpointByID get the Endpoint by ID
77func GetHNSEndpointByID(endpointID string) (*HNSEndpoint, error) {
78	return HNSEndpointRequest("GET", endpointID, "")
79}
80
81// GetHNSEndpointByName gets the endpoint filtered by Name
82func GetHNSEndpointByName(endpointName string) (*HNSEndpoint, error) {
83	hnsResponse, err := HNSListEndpointRequest()
84	if err != nil {
85		return nil, err
86	}
87	for _, hnsEndpoint := range hnsResponse {
88		if hnsEndpoint.Name == endpointName {
89			return &hnsEndpoint, nil
90		}
91	}
92	return nil, EndpointNotFoundError{EndpointName: endpointName}
93}
94
95// Create Endpoint by sending EndpointRequest to HNS. TODO: Create a separate HNS interface to place all these methods
96func (endpoint *HNSEndpoint) Create() (*HNSEndpoint, error) {
97	operation := "Create"
98	title := "hcsshim::HNSEndpoint::" + operation
99	logrus.Debugf(title+" id=%s", endpoint.Id)
100
101	jsonString, err := json.Marshal(endpoint)
102	if err != nil {
103		return nil, err
104	}
105	return HNSEndpointRequest("POST", "", string(jsonString))
106}
107
108// Delete Endpoint by sending EndpointRequest to HNS
109func (endpoint *HNSEndpoint) Delete() (*HNSEndpoint, error) {
110	operation := "Delete"
111	title := "hcsshim::HNSEndpoint::" + operation
112	logrus.Debugf(title+" id=%s", endpoint.Id)
113
114	return HNSEndpointRequest("DELETE", endpoint.Id, "")
115}
116
117// Update Endpoint
118func (endpoint *HNSEndpoint) Update() (*HNSEndpoint, error) {
119	operation := "Update"
120	title := "hcsshim::HNSEndpoint::" + operation
121	logrus.Debugf(title+" id=%s", endpoint.Id)
122	jsonString, err := json.Marshal(endpoint)
123	if err != nil {
124		return nil, err
125	}
126	err = hnsCall("POST", "/endpoints/"+endpoint.Id, string(jsonString), &endpoint)
127
128	return endpoint, err
129}
130
131// ApplyACLPolicy applies a set of ACL Policies on the Endpoint
132func (endpoint *HNSEndpoint) ApplyACLPolicy(policies ...*ACLPolicy) error {
133	operation := "ApplyACLPolicy"
134	title := "hcsshim::HNSEndpoint::" + operation
135	logrus.Debugf(title+" id=%s", endpoint.Id)
136
137	for _, policy := range policies {
138		if policy == nil {
139			continue
140		}
141		jsonString, err := json.Marshal(policy)
142		if err != nil {
143			return err
144		}
145		endpoint.Policies = append(endpoint.Policies, jsonString)
146	}
147
148	_, err := endpoint.Update()
149	return err
150}
151
152// ContainerAttach attaches an endpoint to container
153func (endpoint *HNSEndpoint) ContainerAttach(containerID string, compartmentID uint16) error {
154	operation := "ContainerAttach"
155	title := "hcsshim::HNSEndpoint::" + operation
156	logrus.Debugf(title+" id=%s", endpoint.Id)
157
158	requestMessage := &EndpointAttachDetachRequest{
159		ContainerID:   containerID,
160		CompartmentID: compartmentID,
161		SystemType:    ContainerType,
162	}
163	response := &EndpointResquestResponse{}
164	jsonString, err := json.Marshal(requestMessage)
165	if err != nil {
166		return err
167	}
168	return hnsCall("POST", "/endpoints/"+endpoint.Id+"/attach", string(jsonString), &response)
169}
170
171// ContainerDetach detaches an endpoint from container
172func (endpoint *HNSEndpoint) ContainerDetach(containerID string) error {
173	operation := "ContainerDetach"
174	title := "hcsshim::HNSEndpoint::" + operation
175	logrus.Debugf(title+" id=%s", endpoint.Id)
176
177	requestMessage := &EndpointAttachDetachRequest{
178		ContainerID: containerID,
179		SystemType:  ContainerType,
180	}
181	response := &EndpointResquestResponse{}
182
183	jsonString, err := json.Marshal(requestMessage)
184	if err != nil {
185		return err
186	}
187	return hnsCall("POST", "/endpoints/"+endpoint.Id+"/detach", string(jsonString), &response)
188}
189
190// HostAttach attaches a nic on the host
191func (endpoint *HNSEndpoint) HostAttach(compartmentID uint16) error {
192	operation := "HostAttach"
193	title := "hcsshim::HNSEndpoint::" + operation
194	logrus.Debugf(title+" id=%s", endpoint.Id)
195	requestMessage := &EndpointAttachDetachRequest{
196		CompartmentID: compartmentID,
197		SystemType:    HostType,
198	}
199	response := &EndpointResquestResponse{}
200
201	jsonString, err := json.Marshal(requestMessage)
202	if err != nil {
203		return err
204	}
205	return hnsCall("POST", "/endpoints/"+endpoint.Id+"/attach", string(jsonString), &response)
206
207}
208
209// HostDetach detaches a nic on the host
210func (endpoint *HNSEndpoint) HostDetach() error {
211	operation := "HostDetach"
212	title := "hcsshim::HNSEndpoint::" + operation
213	logrus.Debugf(title+" id=%s", endpoint.Id)
214	requestMessage := &EndpointAttachDetachRequest{
215		SystemType: HostType,
216	}
217	response := &EndpointResquestResponse{}
218
219	jsonString, err := json.Marshal(requestMessage)
220	if err != nil {
221		return err
222	}
223	return hnsCall("POST", "/endpoints/"+endpoint.Id+"/detach", string(jsonString), &response)
224}
225
226// VirtualMachineNICAttach attaches a endpoint to a virtual machine
227func (endpoint *HNSEndpoint) VirtualMachineNICAttach(virtualMachineNICName string) error {
228	operation := "VirtualMachineNicAttach"
229	title := "hcsshim::HNSEndpoint::" + operation
230	logrus.Debugf(title+" id=%s", endpoint.Id)
231	requestMessage := &EndpointAttachDetachRequest{
232		VirtualNICName: virtualMachineNICName,
233		SystemType:     VirtualMachineType,
234	}
235	response := &EndpointResquestResponse{}
236
237	jsonString, err := json.Marshal(requestMessage)
238	if err != nil {
239		return err
240	}
241	return hnsCall("POST", "/endpoints/"+endpoint.Id+"/attach", string(jsonString), &response)
242}
243
244// VirtualMachineNICDetach detaches a endpoint  from a virtual machine
245func (endpoint *HNSEndpoint) VirtualMachineNICDetach() error {
246	operation := "VirtualMachineNicDetach"
247	title := "hcsshim::HNSEndpoint::" + operation
248	logrus.Debugf(title+" id=%s", endpoint.Id)
249
250	requestMessage := &EndpointAttachDetachRequest{
251		SystemType: VirtualMachineType,
252	}
253	response := &EndpointResquestResponse{}
254
255	jsonString, err := json.Marshal(requestMessage)
256	if err != nil {
257		return err
258	}
259	return hnsCall("POST", "/endpoints/"+endpoint.Id+"/detach", string(jsonString), &response)
260}
261