@@ -611,7 +611,6 @@ func (c *Controller) handleAddOrUpdatePod(key string) (err error) {
611
611
return nil
612
612
}
613
613
pod = cachedPod .DeepCopy ()
614
- // check if allocate subnet is need. also allocate subnet when hotplug nic
615
614
needAllocatePodNets := needAllocateSubnets (pod , podNets )
616
615
if len (needAllocatePodNets ) != 0 {
617
616
if cachedPod , err = c .reconcileAllocateSubnets (cachedPod , pod , needAllocatePodNets ); err != nil {
@@ -641,6 +640,16 @@ func (c *Controller) reconcileAllocateSubnets(cachedPod, pod *v1.Pod, needAlloca
641
640
podName := c .getNameByPod (pod )
642
641
// todo: isVmPod, getPodType, getNameByPod has duplicated logic
643
642
643
+ var err error
644
+ var isMigrate , migrated , migratedFail bool
645
+ var vmKey , srcNodeName , targetNodeName string
646
+ if isVMPod && c .config .EnableKeepVMIP {
647
+ vmKey = fmt .Sprintf ("%s/%s" , namespace , vmName )
648
+ if isMigrate , migrated , migratedFail , srcNodeName , targetNodeName , err = c .migrateVM (pod , vmKey ); err != nil {
649
+ klog .Error (err )
650
+ return nil , err
651
+ }
652
+ }
644
653
// Avoid create lsp for already running pod in ovn-nb when controller restart
645
654
for _ , podNet := range needAllocatePodNets {
646
655
// the subnet may changed when alloc static ip from the latter subnet after ns supports multi subnets
@@ -669,10 +678,11 @@ func (c *Controller) reconcileAllocateSubnets(cachedPod, pod *v1.Pod, needAlloca
669
678
delete (pod .Annotations , fmt .Sprintf (util .PodNicAnnotationTemplate , podNet .ProviderName ))
670
679
}
671
680
pod .Annotations [fmt .Sprintf (util .AllocatedAnnotationTemplate , podNet .ProviderName )] = "true"
672
- if isVMPod && c .config .EnableKeepVMIP {
681
+
682
+ if vmKey != "" {
673
683
pod .Annotations [fmt .Sprintf (util .VMTemplate , podNet .ProviderName )] = vmName
674
684
if err := c .changeVMSubnet (vmName , namespace , podNet .ProviderName , subnet .Name ); err != nil {
675
- klog .Errorf ("change subnet of pod %s/%s to %s failed: %v" , namespace , name , subnet .Name , err )
685
+ klog .Errorf ("vm %s change subnet to %s failed: %v" , vmKey , subnet .Name , err )
676
686
return nil , err
677
687
}
678
688
}
@@ -719,13 +729,31 @@ func (c *Controller) reconcileAllocateSubnets(cachedPod, pod *v1.Pod, needAlloca
719
729
DHCPv4OptionsUUID : subnet .Status .DHCPv4OptionsUUID ,
720
730
DHCPv6OptionsUUID : subnet .Status .DHCPv6OptionsUUID ,
721
731
}
722
-
723
- if err := c . OVNNbClient . CreateLogicalSwitchPort ( subnet . Name , portName , ipStr , mac , podName , pod . Namespace , portSecurity , securityGroupAnnotation , vips , podNet .Subnet .Spec .EnableDHCP , dhcpOptions , subnet .Spec .Vpc ); err != nil {
732
+ if err := c . OVNNbClient . CreateLogicalSwitchPort ( subnet . Name , portName , ipStr , mac , podName , pod . Namespace ,
733
+ portSecurity , securityGroupAnnotation , vips , podNet .Subnet .Spec .EnableDHCP , dhcpOptions , subnet .Spec .Vpc ); err != nil {
724
734
c .recorder .Eventf (pod , v1 .EventTypeWarning , "CreateOVNPortFailed" , err .Error ())
725
735
klog .Errorf ("%v" , err )
726
736
return nil , err
727
737
}
728
738
739
+ if isMigrate {
740
+ if migrated {
741
+ klog .Infof ("migrate end reset options for lsp %s from %s to %s, migrated fail: %t" , portName , srcNodeName , targetNodeName , migratedFail )
742
+ if err := c .OVNNbClient .ResetLogicalSwitchPortMigrateOptions (portName , srcNodeName , targetNodeName , migratedFail ); err != nil {
743
+ err = fmt .Errorf ("failed to clean migrate options for lsp %s, %v" , portName , err )
744
+ klog .Error (err )
745
+ return nil , err
746
+ }
747
+ } else {
748
+ klog .Infof ("migrate start set options for lsp %s from %s to %s" , portName , srcNodeName , targetNodeName )
749
+ if err := c .OVNNbClient .SetLogicalSwitchPortMigrateOptions (portName , srcNodeName , targetNodeName ); err != nil {
750
+ err = fmt .Errorf ("failed to set migrate options for lsp %s, %v" , portName , err )
751
+ klog .Error (err )
752
+ return nil , err
753
+ }
754
+ }
755
+ }
756
+
729
757
if pod .Annotations [fmt .Sprintf (util .Layer2ForwardAnnotationTemplate , podNet .ProviderName )] == "true" {
730
758
if err := c .OVNNbClient .EnablePortLayer2forward (portName ); err != nil {
731
759
c .recorder .Eventf (pod , v1 .EventTypeWarning , "SetOVNPortL2ForwardFailed" , err .Error ())
@@ -1008,6 +1036,19 @@ func (c *Controller) handleDeletePod(key string) error {
1008
1036
}
1009
1037
isVMPod , vmName := isVMPod (pod )
1010
1038
if isVMPod && c .config .EnableKeepVMIP {
1039
+ ports , err := c .OVNNbClient .ListNormalLogicalSwitchPorts (true , map [string ]string {"pod" : podKey })
1040
+ if err != nil {
1041
+ klog .Errorf ("failed to list lsps of pod '%s', %v" , pod .Name , err )
1042
+ return err
1043
+ }
1044
+ for _ , port := range ports {
1045
+ klog .Infof ("clean migrate options for vm lsp %s" , port .Name )
1046
+ if err := c .OVNNbClient .CleanLogicalSwitchPortMigrateOptions (port .Name ); err != nil {
1047
+ err = fmt .Errorf ("failed to clean migrate options for vm lsp %s, %v" , port .Name , err )
1048
+ klog .Error (err )
1049
+ return err
1050
+ }
1051
+ }
1011
1052
vmToBeDel := c .isVMToDel (pod , vmName )
1012
1053
isDelete , err := appendCheckPodToDel (c , pod , vmName , util .VMInstance )
1013
1054
if pod .DeletionTimestamp != nil {
@@ -1341,6 +1382,9 @@ func getNextHopByTunnelIP(gw []net.IP) string {
1341
1382
}
1342
1383
1343
1384
func needAllocateSubnets (pod * v1.Pod , nets []* kubeovnNet ) []* kubeovnNet {
1385
+ // check if allocate from subnet is need.
1386
+ // allocate subnet when change subnet to hotplug nic
1387
+ // allocate subnet when migrate vm
1344
1388
if ! isPodAlive (pod ) {
1345
1389
return nil
1346
1390
}
@@ -1349,9 +1393,15 @@ func needAllocateSubnets(pod *v1.Pod, nets []*kubeovnNet) []*kubeovnNet {
1349
1393
return nets
1350
1394
}
1351
1395
1396
+ migrate := false
1397
+ if job , ok := pod .Annotations [util .MigrationJobAnnotation ]; ok {
1398
+ klog .Infof ("pod %s/%s is in the migration job %s" , pod .Namespace , pod .Name , job )
1399
+ migrate = true
1400
+ }
1401
+
1352
1402
result := make ([]* kubeovnNet , 0 , len (nets ))
1353
1403
for _ , n := range nets {
1354
- if pod .Annotations [fmt .Sprintf (util .AllocatedAnnotationTemplate , n .ProviderName )] != "true" {
1404
+ if migrate || pod .Annotations [fmt .Sprintf (util .AllocatedAnnotationTemplate , n .ProviderName )] != "true" {
1355
1405
result = append (result , n )
1356
1406
}
1357
1407
}
@@ -2089,3 +2139,60 @@ func (c *Controller) getVirtualIPs(pod *v1.Pod, podNets []*kubeovnNet) map[strin
2089
2139
}
2090
2140
return vipsMap
2091
2141
}
2142
+
2143
+ // migrate vm return migrate, migrated, fail, src node, target node, err
2144
+ func (c * Controller ) migrateVM (pod * v1.Pod , vmKey string ) (bool , bool , bool , string , string , error ) {
2145
+ // try optimize vm migration, no need return error
2146
+ // migrate true means need ovn set migrate options
2147
+ // migrated ok means need set migrate options to target node
2148
+ // migrated failed means need set migrate options to source node
2149
+ if _ , ok := pod .Annotations [util .MigrationJobAnnotation ]; ! ok {
2150
+ return false , false , false , "" , "" , nil
2151
+ }
2152
+ if _ , ok := pod .Annotations [util .MigrationSourceAnnotation ]; ok {
2153
+ klog .Infof ("will migrate out vm %s pod %s from source node %s" , vmKey , pod .Name , pod .Spec .NodeName )
2154
+ return false , false , false , "" , "" , nil
2155
+ }
2156
+ // ovn set migrator only in the process of target vm pod
2157
+ if _ , ok := pod .Annotations [util .MigrationTargetAnnotation ]; ! ok {
2158
+ return false , false , false , "" , "" , nil
2159
+ }
2160
+ srcNode , ok := pod .Annotations [util .MigrationSourceNodeAnnotation ]
2161
+ if ! ok || srcNode == "" {
2162
+ err := fmt .Errorf ("vm %s migration source node is not set" , vmKey )
2163
+ klog .Warning (err )
2164
+ return false , false , false , "" , "" , nil
2165
+ }
2166
+ targetNode := pod .Spec .NodeName
2167
+ if targetNode == "" {
2168
+ err := fmt .Errorf ("vm %s migration target node is not set" , vmKey )
2169
+ klog .Warning (err )
2170
+ return false , false , false , "" , "" , nil
2171
+ }
2172
+ migratePhase , ok := pod .Annotations [util .MigrationPhaseAnnotation ]
2173
+ if ! ok {
2174
+ err := fmt .Errorf ("vm %s migration phase is not set" , vmKey )
2175
+ klog .Warning (err )
2176
+ return false , false , false , "" , "" , nil
2177
+ }
2178
+ // check migrate phase
2179
+ if migratePhase == "" {
2180
+ err := fmt .Errorf ("vm %s migration phase is empty" , vmKey )
2181
+ klog .Warning (err )
2182
+ return false , false , false , "" , "" , nil
2183
+ }
2184
+ if migratePhase == util .MigrationPhaseStarted {
2185
+ klog .Infof ("start to migrate src vm %s from %s to %s" , vmKey , srcNode , targetNode )
2186
+ return true , false , false , srcNode , targetNode , nil
2187
+ }
2188
+ if migratePhase == util .MigrationPhaseSucceeded {
2189
+ klog .Infof ("succeed to migrate src vm %s from %s to %s" , vmKey , srcNode , targetNode )
2190
+ return true , true , false , srcNode , targetNode , nil
2191
+ }
2192
+ if migratePhase == util .MigrationPhaseFailed {
2193
+ klog .Infof ("failed to migrate src vm %s from %s to %s" , vmKey , srcNode , targetNode )
2194
+ return true , true , true , srcNode , targetNode , nil
2195
+ }
2196
+
2197
+ return false , false , false , "" , "" , nil
2198
+ }
0 commit comments