@@ -16,6 +16,7 @@ import (
1616 "github.com/Azure/azure-container-networking/cns/ipamclient"
1717 "github.com/Azure/azure-container-networking/cns/routes"
1818 "github.com/Azure/azure-container-networking/log"
19+ "github.com/Azure/azure-container-networking/platform"
1920 "github.com/Azure/azure-container-networking/store"
2021)
2122
@@ -32,17 +33,24 @@ type httpRestService struct {
3233 ipamClient * ipamclient.IpamClient
3334 routingTable * routes.RoutingTable
3435 store store.KeyValueStore
35- state httpRestServiceState
36+ state * httpRestServiceState
3637}
3738
3839// httpRestServiceState contains the state we would like to persist.
3940type httpRestServiceState struct {
4041 Location string
4142 NetworkType string
4243 Initialized bool
44+ Networks map [string ]* networkInfo
4345 TimeStamp time.Time
4446}
4547
48+ type networkInfo struct {
49+ NetworkName string
50+ NicInfo * imdsclient.InterfaceInfo
51+ Options map [string ]interface {}
52+ }
53+
4654// HTTPService describes the min API interface that every service should have.
4755type HTTPService interface {
4856 common.ServiceAPI
@@ -67,14 +75,19 @@ func NewHTTPRestService(config *common.ServiceConfig) (HTTPService, error) {
6775 return nil , err
6876 }
6977
78+ serviceState := & httpRestServiceState {}
79+ serviceState .Networks = make (map [string ]* networkInfo )
80+
7081 return & httpRestService {
7182 Service : service ,
7283 store : service .Service .Store ,
7384 dockerClient : dc ,
7485 imdsClient : imdsClient ,
7586 ipamClient : ic ,
7687 routingTable : routingTable ,
88+ state : serviceState ,
7789 }, nil
90+
7891}
7992
8093// Start starts the CNS listener.
@@ -86,6 +99,18 @@ func (service *httpRestService) Start(config *common.ServiceConfig) error {
8699 return err
87100 }
88101
102+ err = service .restoreState ()
103+ if err != nil {
104+ log .Printf ("[Azure CNS] Failed to restore state, err:%v." , err )
105+ return err
106+ }
107+
108+ err = service .restoreNetworkState ()
109+ if err != nil {
110+ log .Printf ("[Azure CNS] Failed to restore state, err:%v." , err )
111+ return err
112+ }
113+
89114 // Add handlers.
90115 listener := service .Listener
91116 // default handlers
@@ -186,7 +211,14 @@ func (service *httpRestService) createNetwork(w http.ResponseWriter, r *http.Req
186211 log .Printf ("[Azure CNS] Unable to get routing table from node, %+v." , err .Error ())
187212 }
188213
189- err = dc .CreateNetwork (req .NetworkName , req .Options )
214+ nicInfo , err := service .imdsClient .GetPrimaryInterfaceInfoFromHost ()
215+ if err != nil {
216+ returnMessage = fmt .Sprintf ("[Azure CNS] Error. CreateNetwork failed %v." , err .Error ())
217+ returnCode = UnexpectedError
218+ break
219+ }
220+
221+ err = dc .CreateNetwork (req .NetworkName , nicInfo , req .Options )
190222 if err != nil {
191223 returnMessage = fmt .Sprintf ("[Azure CNS] Error. CreateNetwork failed %v." , err .Error ())
192224 returnCode = UnexpectedError
@@ -197,6 +229,14 @@ func (service *httpRestService) createNetwork(w http.ResponseWriter, r *http.Req
197229 log .Printf ("[Azure CNS] Unable to restore routing table on node, %+v." , err .Error ())
198230 }
199231
232+ networkInfo := & networkInfo {
233+ NetworkName : req .NetworkName ,
234+ NicInfo : nicInfo ,
235+ Options : req .Options ,
236+ }
237+
238+ service .state .Networks [req .NetworkName ] = networkInfo
239+
200240 case "StandAlone" :
201241 returnMessage = fmt .Sprintf ("[Azure CNS] Error. Underlay network is not supported in StandAlone environment. %v." , err .Error ())
202242 returnCode = UnsupportedEnvironment
@@ -228,6 +268,10 @@ func (service *httpRestService) createNetwork(w http.ResponseWriter, r *http.Req
228268
229269 err = service .Listener .Encode (w , & resp )
230270
271+ if returnCode == 0 {
272+ service .saveState ()
273+ }
274+
231275 log .Response (service .Name , resp , err )
232276}
233277
@@ -279,6 +323,11 @@ func (service *httpRestService) deleteNetwork(w http.ResponseWriter, r *http.Req
279323
280324 err = service .Listener .Encode (w , & resp )
281325
326+ if returnCode == 0 {
327+ delete (service .state .Networks , req .NetworkName )
328+ service .saveState ()
329+ }
330+
282331 log .Response (service .Name , resp , err )
283332}
284333
@@ -723,3 +772,45 @@ func (service *httpRestService) restoreState() error {
723772 log .Printf ("[Azure CNS] Restored state, %+v\n " , service .state )
724773 return nil
725774}
775+
776+ // restoreNetworkState restores Network state that existed before reboot.
777+ func (service * httpRestService ) restoreNetworkState () error {
778+ log .Printf ("[Azure CNS] Enter Restoring Network State" )
779+
780+ rebooted := false
781+
782+ modTime , err := service .store .GetModificationTime ()
783+ if err == nil {
784+ log .Printf ("[Azure CNS] Store timestamp is %v." , modTime )
785+
786+ rebootTime , err := platform .GetLastRebootTime ()
787+ if err == nil && rebootTime .After (modTime ) {
788+ log .Printf ("[Azure CNS] reboot time %v mod time %v" , rebootTime , modTime )
789+ rebooted = true
790+ }
791+ }
792+
793+ if rebooted {
794+ for _ , nwInfo := range service .state .Networks {
795+ enableSnat := true
796+
797+ log .Printf ("[Azure CNS] Restore nwinfo %v" , nwInfo )
798+
799+ if nwInfo .Options != nil {
800+ if _ , ok := nwInfo .Options [dockerclient .OptDisableSnat ]; ok {
801+ enableSnat = false
802+ }
803+ }
804+
805+ if enableSnat {
806+ err := common .SetOutboundSNAT (nwInfo .NicInfo .Subnet )
807+ if err != nil {
808+ log .Printf ("[Azure CNS] Error setting up SNAT outbound rule %v" , err )
809+ return err
810+ }
811+ }
812+ }
813+ }
814+
815+ return nil
816+ }
0 commit comments