1package hns
2
3import (
4	"encoding/json"
5
6	"github.com/sirupsen/logrus"
7)
8
9// RoutePolicy is a structure defining schema for Route based Policy
10type RoutePolicy struct {
11	Policy
12	DestinationPrefix string `json:"DestinationPrefix,omitempty"`
13	NextHop           string `json:"NextHop,omitempty"`
14	EncapEnabled      bool   `json:"NeedEncap,omitempty"`
15}
16
17// ELBPolicy is a structure defining schema for ELB LoadBalancing based Policy
18type ELBPolicy struct {
19	LBPolicy
20	SourceVIP string   `json:"SourceVIP,omitempty"`
21	VIPs      []string `json:"VIPs,omitempty"`
22	ILB       bool     `json:"ILB,omitempty"`
23	DSR       bool     `json:"IsDSR,omitempty"`
24}
25
26// LBPolicy is a structure defining schema for LoadBalancing based Policy
27type LBPolicy struct {
28	Policy
29	Protocol     uint16 `json:"Protocol,omitempty"`
30	InternalPort uint16
31	ExternalPort uint16
32}
33
34// PolicyList is a structure defining schema for Policy list request
35type PolicyList struct {
36	ID                 string            `json:"ID,omitempty"`
37	EndpointReferences []string          `json:"References,omitempty"`
38	Policies           []json.RawMessage `json:"Policies,omitempty"`
39}
40
41// HNSPolicyListRequest makes a call into HNS to update/query a single network
42func HNSPolicyListRequest(method, path, request string) (*PolicyList, error) {
43	var policy PolicyList
44	err := hnsCall(method, "/policylists/"+path, request, &policy)
45	if err != nil {
46		return nil, err
47	}
48
49	return &policy, nil
50}
51
52// HNSListPolicyListRequest gets all the policy list
53func HNSListPolicyListRequest() ([]PolicyList, error) {
54	var plist []PolicyList
55	err := hnsCall("GET", "/policylists/", "", &plist)
56	if err != nil {
57		return nil, err
58	}
59
60	return plist, nil
61}
62
63// PolicyListRequest makes a HNS call to modify/query a network policy list
64func PolicyListRequest(method, path, request string) (*PolicyList, error) {
65	policylist := &PolicyList{}
66	err := hnsCall(method, "/policylists/"+path, request, &policylist)
67	if err != nil {
68		return nil, err
69	}
70
71	return policylist, nil
72}
73
74// GetPolicyListByID get the policy list by ID
75func GetPolicyListByID(policyListID string) (*PolicyList, error) {
76	return PolicyListRequest("GET", policyListID, "")
77}
78
79// Create PolicyList by sending PolicyListRequest to HNS.
80func (policylist *PolicyList) Create() (*PolicyList, error) {
81	operation := "Create"
82	title := "hcsshim::PolicyList::" + operation
83	logrus.Debugf(title+" id=%s", policylist.ID)
84	jsonString, err := json.Marshal(policylist)
85	if err != nil {
86		return nil, err
87	}
88	return PolicyListRequest("POST", "", string(jsonString))
89}
90
91// Delete deletes PolicyList
92func (policylist *PolicyList) Delete() (*PolicyList, error) {
93	operation := "Delete"
94	title := "hcsshim::PolicyList::" + operation
95	logrus.Debugf(title+" id=%s", policylist.ID)
96
97	return PolicyListRequest("DELETE", policylist.ID, "")
98}
99
100// AddEndpoint add an endpoint to a Policy List
101func (policylist *PolicyList) AddEndpoint(endpoint *HNSEndpoint) (*PolicyList, error) {
102	operation := "AddEndpoint"
103	title := "hcsshim::PolicyList::" + operation
104	logrus.Debugf(title+" id=%s, endpointId:%s", policylist.ID, endpoint.Id)
105
106	_, err := policylist.Delete()
107	if err != nil {
108		return nil, err
109	}
110
111	// Add Endpoint to the Existing List
112	policylist.EndpointReferences = append(policylist.EndpointReferences, "/endpoints/"+endpoint.Id)
113
114	return policylist.Create()
115}
116
117// RemoveEndpoint removes an endpoint from the Policy List
118func (policylist *PolicyList) RemoveEndpoint(endpoint *HNSEndpoint) (*PolicyList, error) {
119	operation := "RemoveEndpoint"
120	title := "hcsshim::PolicyList::" + operation
121	logrus.Debugf(title+" id=%s, endpointId:%s", policylist.ID, endpoint.Id)
122
123	_, err := policylist.Delete()
124	if err != nil {
125		return nil, err
126	}
127
128	elementToRemove := "/endpoints/" + endpoint.Id
129
130	var references []string
131
132	for _, endpointReference := range policylist.EndpointReferences {
133		if endpointReference == elementToRemove {
134			continue
135		}
136		references = append(references, endpointReference)
137	}
138	policylist.EndpointReferences = references
139	return policylist.Create()
140}
141
142// AddLoadBalancer policy list for the specified endpoints
143func AddLoadBalancer(endpoints []HNSEndpoint, isILB bool, sourceVIP, vip string, protocol uint16, internalPort uint16, externalPort uint16) (*PolicyList, error) {
144	operation := "AddLoadBalancer"
145	title := "hcsshim::PolicyList::" + operation
146	logrus.Debugf(title+" endpointId=%v, isILB=%v, sourceVIP=%s, vip=%s, protocol=%v, internalPort=%v, externalPort=%v", endpoints, isILB, sourceVIP, vip, protocol, internalPort, externalPort)
147
148	policylist := &PolicyList{}
149
150	elbPolicy := &ELBPolicy{
151		SourceVIP: sourceVIP,
152		ILB:       isILB,
153	}
154
155	if len(vip) > 0 {
156		elbPolicy.VIPs = []string{vip}
157	}
158	elbPolicy.Type = ExternalLoadBalancer
159	elbPolicy.Protocol = protocol
160	elbPolicy.InternalPort = internalPort
161	elbPolicy.ExternalPort = externalPort
162
163	for _, endpoint := range endpoints {
164		policylist.EndpointReferences = append(policylist.EndpointReferences, "/endpoints/"+endpoint.Id)
165	}
166
167	jsonString, err := json.Marshal(elbPolicy)
168	if err != nil {
169		return nil, err
170	}
171	policylist.Policies = append(policylist.Policies, jsonString)
172	return policylist.Create()
173}
174
175// AddRoute adds route policy list for the specified endpoints
176func AddRoute(endpoints []HNSEndpoint, destinationPrefix string, nextHop string, encapEnabled bool) (*PolicyList, error) {
177	operation := "AddRoute"
178	title := "hcsshim::PolicyList::" + operation
179	logrus.Debugf(title+" destinationPrefix:%s", destinationPrefix)
180
181	policylist := &PolicyList{}
182
183	rPolicy := &RoutePolicy{
184		DestinationPrefix: destinationPrefix,
185		NextHop:           nextHop,
186		EncapEnabled:      encapEnabled,
187	}
188	rPolicy.Type = Route
189
190	for _, endpoint := range endpoints {
191		policylist.EndpointReferences = append(policylist.EndpointReferences, "/endpoints/"+endpoint.Id)
192	}
193
194	jsonString, err := json.Marshal(rPolicy)
195	if err != nil {
196		return nil, err
197	}
198
199	policylist.Policies = append(policylist.Policies, jsonString)
200	return policylist.Create()
201}
202