Skip to content

Commit 2dbc856

Browse files
Add option in CNS to pre-provision hns network (#323)
* Add option in CNS to pre-provision hns network Add a commandline option in CNS to pre-provision hns network. The commandline option take the type of the network that needs pre-provisioning. This allows orchestrators to start CNS with this option so that the VM network blip / disconnect is avoided when calling cni add the very first time.
1 parent e28f583 commit 2dbc856

File tree

6 files changed

+358
-2
lines changed

6 files changed

+358
-2
lines changed

cns/api.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,15 @@
33

44
package cns
55

6+
import "encoding/json"
7+
68
// Container Network Service remote API Contract
79
const (
810
SetEnvironmentPath = "/network/environment"
911
CreateNetworkPath = "/network/create"
1012
DeleteNetworkPath = "/network/delete"
13+
CreateHnsNetworkPath = "/network/hns/create"
14+
DeleteHnsNetworkPath = "/network/hns/delete"
1115
ReserveIPAddressPath = "/network/ip/reserve"
1216
ReleaseIPAddressPath = "/network/ip/release"
1317
GetHostLocalIPPath = "/network/ip/hostlocal"
@@ -44,6 +48,42 @@ type DeleteNetworkRequest struct {
4448
NetworkName string
4549
}
4650

51+
// CreateHnsNetworkRequest describes request to create the HNS network.
52+
type CreateHnsNetworkRequest struct {
53+
NetworkName string
54+
NetworkType string
55+
NetworkAdapterName string `json:",omitempty"`
56+
SourceMac string `json:",omitempty"`
57+
Policies []json.RawMessage `json:",omitempty"`
58+
MacPools []MacPool `json:",omitempty"`
59+
Subnets []SubnetInfo
60+
DNSSuffix string `json:",omitempty"`
61+
DNSServerList string `json:",omitempty"`
62+
DNSServerCompartment uint32 `json:",omitempty"`
63+
ManagementIP string `json:",omitempty"`
64+
AutomaticDNS bool `json:",omitempty"`
65+
}
66+
67+
// SubnetInfo is assoicated with HNS network and represents a list
68+
// of subnets available to the network
69+
type SubnetInfo struct {
70+
AddressPrefix string `json:",omitempty"`
71+
GatewayAddress string `json:",omitempty"`
72+
Policies []json.RawMessage `json:",omitempty"`
73+
}
74+
75+
// MacPool is assoicated with HNS network and represents a list
76+
// of macaddresses available to the network
77+
type MacPool struct {
78+
StartMacAddress string `json:",omitempty"`
79+
EndMacAddress string `json:",omitempty"`
80+
}
81+
82+
// DeleteHnsNetworkRequest describes request to delete the HNS network.
83+
type DeleteHnsNetworkRequest struct {
84+
NetworkName string
85+
}
86+
4787
// ReserveIPAddressRequest describes request to reserve an IP Address
4888
type ReserveIPAddressRequest struct {
4989
ReservationID string

cns/restserver/restserver.go

Lines changed: 115 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,8 @@ func (service *HTTPRestService) Start(config *common.ServiceConfig) error {
154154
listener.AddHandler(cns.GetNetworkContainerByOrchestratorContext, service.getNetworkContainerByOrchestratorContext)
155155
listener.AddHandler(cns.AttachContainerToNetwork, service.attachNetworkContainerToNetwork)
156156
listener.AddHandler(cns.DetachContainerFromNetwork, service.detachNetworkContainerFromNetwork)
157+
listener.AddHandler(cns.CreateHnsNetworkPath, service.createHnsNetwork)
158+
listener.AddHandler(cns.DeleteHnsNetworkPath, service.deleteHnsNetwork)
157159

158160
// handlers for v0.2
159161
listener.AddHandler(cns.V2Prefix+cns.SetEnvironmentPath, service.setEnvironment)
@@ -172,6 +174,8 @@ func (service *HTTPRestService) Start(config *common.ServiceConfig) error {
172174
listener.AddHandler(cns.V2Prefix+cns.GetNetworkContainerByOrchestratorContext, service.getNetworkContainerByOrchestratorContext)
173175
listener.AddHandler(cns.V2Prefix+cns.AttachContainerToNetwork, service.attachNetworkContainerToNetwork)
174176
listener.AddHandler(cns.V2Prefix+cns.DetachContainerFromNetwork, service.detachNetworkContainerFromNetwork)
177+
listener.AddHandler(cns.V2Prefix+cns.CreateHnsNetworkPath, service.createHnsNetwork)
178+
listener.AddHandler(cns.V2Prefix+cns.DeleteHnsNetworkPath, service.deleteHnsNetwork)
175179

176180
log.Printf("[Azure CNS] Listening.")
177181
return nil
@@ -248,7 +252,7 @@ func (service *HTTPRestService) createNetwork(w http.ResponseWriter, r *http.Req
248252
case "Underlay":
249253
switch service.state.Location {
250254
case "Azure":
251-
log.Printf("[Azure CNS] Goign to create network with name %v.", req.NetworkName)
255+
log.Printf("[Azure CNS] Creating network with name %v.", req.NetworkName)
252256

253257
err = rt.GetRoutingTable()
254258
if err != nil {
@@ -344,7 +348,7 @@ func (service *HTTPRestService) deleteNetwork(w http.ResponseWriter, r *http.Req
344348

345349
// Network does exist
346350
if err == nil {
347-
log.Printf("[Azure CNS] Goign to delete network with name %v.", req.NetworkName)
351+
log.Printf("[Azure CNS] Deleting network with name %v.", req.NetworkName)
348352
err := dc.DeleteNetwork(req.NetworkName)
349353
if err != nil {
350354
returnMessage = fmt.Sprintf("[Azure CNS] Error. DeleteNetwork failed %v.", err.Error())
@@ -379,6 +383,115 @@ func (service *HTTPRestService) deleteNetwork(w http.ResponseWriter, r *http.Req
379383
log.Response(service.Name, resp, resp.ReturnCode, ReturnCodeToString(resp.ReturnCode), err)
380384
}
381385

386+
// Handles CreateHnsNetwork requests.
387+
func (service *HTTPRestService) createHnsNetwork(w http.ResponseWriter, r *http.Request) {
388+
log.Printf("[Azure CNS] createHnsNetwork")
389+
390+
var err error
391+
returnCode := 0
392+
returnMessage := ""
393+
394+
var req cns.CreateHnsNetworkRequest
395+
err = service.Listener.Decode(w, r, &req)
396+
log.Request(service.Name, &req, err)
397+
398+
if err != nil {
399+
returnMessage = fmt.Sprintf("[Azure CNS] Error. Unable to decode input request.")
400+
returnCode = InvalidParameter
401+
} else {
402+
switch r.Method {
403+
case "POST":
404+
if err := platform.CreateHnsNetwork(req); err == nil {
405+
// Save the newly created HnsNetwork name. CNS deleteHnsNetwork API
406+
// will only allow deleting these networks.
407+
networkInfo := &networkInfo{
408+
NetworkName: req.NetworkName,
409+
}
410+
service.lock.Lock()
411+
service.state.Networks[req.NetworkName] = networkInfo
412+
service.lock.Unlock()
413+
returnMessage = fmt.Sprintf("[Azure CNS] Successfully created HNS network: %s", req.NetworkName)
414+
} else {
415+
returnMessage = fmt.Sprintf("[Azure CNS] CreateHnsNetwork failed with error %v", err.Error())
416+
returnCode = UnexpectedError
417+
}
418+
default:
419+
returnMessage = "[Azure CNS] Error. CreateHnsNetwork did not receive a POST."
420+
returnCode = InvalidParameter
421+
}
422+
}
423+
424+
resp := &cns.Response{
425+
ReturnCode: returnCode,
426+
Message: returnMessage,
427+
}
428+
429+
err = service.Listener.Encode(w, &resp)
430+
431+
if returnCode == 0 {
432+
service.lock.Lock()
433+
service.saveState()
434+
service.lock.Unlock()
435+
}
436+
437+
log.Response(service.Name, resp, resp.ReturnCode, ReturnCodeToString(resp.ReturnCode), err)
438+
}
439+
440+
// Handles deleteHnsNetwork requests.
441+
func (service *HTTPRestService) deleteHnsNetwork(w http.ResponseWriter, r *http.Request) {
442+
log.Printf("[Azure CNS] deleteHnsNetwork")
443+
444+
var err error
445+
var req cns.DeleteHnsNetworkRequest
446+
returnCode := 0
447+
returnMessage := ""
448+
449+
err = service.Listener.Decode(w, r, &req)
450+
log.Request(service.Name, &req, err)
451+
452+
if err != nil {
453+
returnMessage = fmt.Sprintf("[Azure CNS] Error. Unable to decode input request.")
454+
returnCode = InvalidParameter
455+
} else {
456+
switch r.Method {
457+
case "POST":
458+
service.lock.Lock()
459+
networkInfo, ok := service.state.Networks[req.NetworkName]
460+
if ok && networkInfo.NetworkName == req.NetworkName {
461+
if err = platform.DeleteHnsNetwork(req.NetworkName); err == nil {
462+
returnMessage = fmt.Sprintf("[Azure CNS] Successfully deleted HNS network: %s", req.NetworkName)
463+
} else {
464+
returnMessage = fmt.Sprintf("[Azure CNS] DeleteHnsNetwork failed with error %v", err.Error())
465+
returnCode = UnexpectedError
466+
}
467+
} else {
468+
returnMessage = fmt.Sprintf("[Azure CNS] Network %s not found", req.NetworkName)
469+
returnCode = InvalidParameter
470+
}
471+
service.lock.Unlock()
472+
default:
473+
returnMessage = "[Azure CNS] Error. DeleteHnsNetwork did not receive a POST."
474+
returnCode = InvalidParameter
475+
}
476+
}
477+
478+
resp := &cns.Response{
479+
ReturnCode: returnCode,
480+
Message: returnMessage,
481+
}
482+
483+
err = service.Listener.Encode(w, &resp)
484+
485+
if returnCode == 0 {
486+
service.lock.Lock()
487+
delete(service.state.Networks, req.NetworkName)
488+
service.saveState()
489+
service.lock.Unlock()
490+
}
491+
492+
log.Response(service.Name, resp, resp.ReturnCode, ReturnCodeToString(resp.ReturnCode), err)
493+
}
494+
382495
// Handles ip reservation requests.
383496
func (service *HTTPRestService) reserveIPAddress(w http.ResponseWriter, r *http.Request) {
384497
log.Printf("[Azure CNS] reserveIPAddress")

cns/service/main.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"fmt"
88
"os"
99
"os/signal"
10+
"strings"
1011
"syscall"
1112

1213
"github.com/Azure/azure-container-networking/cnm/ipam"
@@ -136,6 +137,13 @@ var args = acn.ArgumentList{
136137
Type: "string",
137138
DefaultValue: platform.K8SNetConfigPath + string(os.PathSeparator) + defaultCNINetworkConfigFileName,
138139
},
140+
{
141+
Name: acn.OptCreateDefaultExtNetworkType,
142+
Shorthand: acn.OptCreateDefaultExtNetworkTypeAlias,
143+
Description: "Create default external network for windows platform with the specified type (l2bridge or l2tunnel)",
144+
Type: "string",
145+
DefaultValue: "",
146+
},
139147
{
140148
Name: acn.OptTelemetry,
141149
Shorthand: acn.OptTelemetryAlias,
@@ -169,6 +177,7 @@ func main() {
169177
ipamQueryInterval, _ := acn.GetArg(acn.OptIpamQueryInterval).(int)
170178
stopcnm = acn.GetArg(acn.OptStopAzureVnet).(bool)
171179
vers := acn.GetArg(acn.OptVersion).(bool)
180+
createDefaultExtNetworkType := acn.GetArg(acn.OptCreateDefaultExtNetworkType).(string)
172181
telemetryEnabled := acn.GetArg(acn.OptTelemetry).(bool)
173182

174183
if vers {
@@ -230,6 +239,17 @@ func main() {
230239
httpRestService.SetOption(acn.OptCnsURL, cnsURL)
231240
httpRestService.SetOption(acn.OptNetPluginPath, cniPath)
232241
httpRestService.SetOption(acn.OptNetPluginConfigFile, cniConfigFile)
242+
httpRestService.SetOption(acn.OptCreateDefaultExtNetworkType, createDefaultExtNetworkType)
243+
244+
// Create default ext network if commandline option is set
245+
if len(strings.TrimSpace(createDefaultExtNetworkType)) > 0 {
246+
if err := platform.CreateDefaultExtNetwork(createDefaultExtNetworkType); err == nil {
247+
log.Printf("[Azure CNS] Successfully created default ext network")
248+
} else {
249+
log.Printf("[Azure CNS] Failed to create default ext network due to error: %v", err)
250+
return
251+
}
252+
}
233253

234254
// Start CNS.
235255
if httpRestService != nil {
@@ -308,6 +328,14 @@ func main() {
308328
log.Printf("CNS Received unhandled error %v, shutting down.", err)
309329
}
310330

331+
if len(strings.TrimSpace(createDefaultExtNetworkType)) > 0 {
332+
if err := platform.DeleteDefaultExtNetwork(); err == nil {
333+
log.Printf("[Azure CNS] Successfully deleted default ext network")
334+
} else {
335+
log.Printf("[Azure CNS] Failed to delete default ext network due to error: %v", err)
336+
}
337+
}
338+
311339
// Cleanup.
312340
if httpRestService != nil {
313341
httpRestService.Stop()

common/config.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@ const (
7272
OptTelemetryConfigDir = "telemetry-config-file"
7373
OptTelemetryConfigDirAlias = "d"
7474

75+
// Create ext Hns network
76+
OptCreateDefaultExtNetworkType = "create-defaultextnetwork-type"
77+
OptCreateDefaultExtNetworkTypeAlias = "defaultextnetworktype"
78+
7579
// Disable Telemetry
7680
OptTelemetry = "telemetry"
7781
OptTelemetryAlias = "dt"

platform/os_linux.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"os/exec"
1111
"time"
1212

13+
"github.com/Azure/azure-container-networking/cns"
1314
"github.com/Azure/azure-container-networking/log"
1415
)
1516

@@ -111,3 +112,28 @@ func KillProcessByName(processName string) error {
111112
func SetSdnRemoteArpMacAddress() error {
112113
return nil
113114
}
115+
116+
// CreateDefaultExtNetwork creates the default ext network (if it doesn't exist already)
117+
// to create external switch on windows platform.
118+
// This is windows platform specific.
119+
func CreateDefaultExtNetwork(networkType string) error {
120+
return fmt.Errorf("CreateDefaultExtNetwork shouldn't be called for the platform: %s", GetOSInfo)
121+
}
122+
123+
// DeleteDefaultExtNetwork deletes the default HNS network.
124+
// This is windows platform specific.
125+
func DeleteDefaultExtNetwork() error {
126+
return fmt.Errorf("DeleteDefaultExtNetwork shouldn't be called for the platform: %s", GetOSInfo)
127+
}
128+
129+
// CreateHnsNetwork creates the HNS network with the provided configuration
130+
// This is windows platform specific.
131+
func CreateHnsNetwork(nwConfig cns.CreateHnsNetworkRequest) error {
132+
return fmt.Errorf("CreateHnsNetwork shouldn't be called for the platform: %s", GetOSInfo)
133+
}
134+
135+
// DeleteHnsNetwork deletes the HNS network with the provided name.
136+
// This is windows platform specific.
137+
func DeleteHnsNetwork(networkName string) error {
138+
return fmt.Errorf("DeleteHnsNetwork shouldn't be called for the platform: %s", GetOSInfo)
139+
}

0 commit comments

Comments
 (0)