@@ -41,6 +41,7 @@ var diffFuncs = map[reflect.Type]diffFunc{
4141 reflect .TypeOf (rbacv1.RoleBinding {}): allDiffFuncs (metadataDiffFunc , basicDiffFunc (rolebindingDiffOpts )),
4242 reflect .TypeOf (corev1.ServiceAccount {}): metadataDiffFunc ,
4343 reflect .TypeOf (appsv1.Deployment {}): allDiffFuncs (deploymentDiffFunc , metadataDiffFunc , basicDiffFunc (deploymentDiffOpts )),
44+ reflect .TypeOf (corev1.Pod {}): allDiffFuncs (podDiffFunc , metadataDiffFunc ),
4445 reflect .TypeOf (corev1.ConfigMap {}): allDiffFuncs (metadataDiffFunc , basicDiffFunc (configmapDiffOpts )),
4546 reflect .TypeOf (corev1.Secret {}): allDiffFuncs (metadataDiffFunc , basicDiffFunc (secretDiffOpts )),
4647 reflect .TypeOf (v1alpha1.DevWorkspaceRouting {}): allDiffFuncs (routingDiffFunc , metadataDiffFunc , basicDiffFunc (routingDiffOpts )),
@@ -105,6 +106,107 @@ func deploymentDiffFunc(spec, cluster crclient.Object) (delete, update bool) {
105106 return false , false
106107}
107108
109+ func podDiffFunc (spec , cluster crclient.Object ) (delete , update bool ) {
110+ specPod := spec .(* corev1.Pod )
111+ clusterPod := cluster .(* corev1.Pod )
112+ // Check immutable podSpecFields -- unset fields we don't want to check
113+ specCopy := specPod .DeepCopy ()
114+ clusterCopy := clusterPod .DeepCopy ()
115+ for _ , specVolume := range specCopy .Spec .Volumes {
116+ found := false
117+ for _ , clusterVolume := range clusterCopy .Spec .Volumes {
118+ if equality .Semantic .DeepDerivative (specVolume , clusterVolume ) {
119+ found = true
120+ break
121+ }
122+ }
123+ if ! found {
124+ return true , false
125+ }
126+ }
127+ specCopy .Spec .ActiveDeadlineSeconds = clusterCopy .Spec .ActiveDeadlineSeconds
128+ specCopy .Spec .TerminationGracePeriodSeconds = clusterCopy .Spec .TerminationGracePeriodSeconds
129+ specCopy .Spec .Tolerations = clusterCopy .Spec .Tolerations
130+ specCopy .Spec .Containers = nil
131+ specCopy .Spec .InitContainers = nil
132+ specCopy .Spec .Volumes = nil
133+ if ! equality .Semantic .DeepDerivative (specCopy .Spec , clusterCopy .Spec ) {
134+ return true , false
135+ }
136+
137+ // Check mutable pod fields
138+ if specPod .Spec .ActiveDeadlineSeconds != nil &&
139+ specPod .Spec .ActiveDeadlineSeconds != clusterPod .Spec .ActiveDeadlineSeconds {
140+ return false , true
141+ }
142+ if specPod .Spec .TerminationGracePeriodSeconds != nil &&
143+ specPod .Spec .TerminationGracePeriodSeconds != clusterPod .Spec .TerminationGracePeriodSeconds {
144+ negOne := int64 (- 1 )
145+ if clusterPod .Spec .TerminationGracePeriodSeconds == & negOne {
146+ return false , true
147+ } else {
148+ return true , false
149+ }
150+ }
151+ if len (specPod .Spec .Tolerations ) > 0 {
152+ // Technically, it's safe to add tolerations. However, this would require including any default tolerations
153+ // in the object we're applying, so instead we delete the pod and re-create it if tolerations are changed.
154+ for _ , specToleration := range clusterPod .Spec .Tolerations {
155+ found := false
156+ for _ , clusterToleration := range clusterPod .Spec .Tolerations {
157+ if cmp .Equal (specToleration , clusterToleration ) {
158+ found = true
159+ }
160+ }
161+ if ! found {
162+ return true , false
163+ }
164+ }
165+ }
166+
167+ shouldDelete , shouldUpdate := containersDiffFunc (specPod .Spec .Containers , clusterPod .Spec .Containers )
168+ if shouldDelete || shouldUpdate {
169+ return shouldDelete , shouldUpdate
170+ }
171+ shouldDelete , shouldUpdate = containersDiffFunc (specPod .Spec .InitContainers , clusterPod .Spec .InitContainers )
172+ if shouldDelete || shouldUpdate {
173+ return shouldDelete , shouldUpdate
174+ }
175+
176+ return false , false
177+ }
178+
179+ // containersDiffFunc compares a pods containers/initContainers and returns whether
180+ // the pod should be re-created or updated. Only the image field in containers is
181+ // updatable.
182+ func containersDiffFunc (spec , cluster []corev1.Container ) (delete , update bool ) {
183+ findContainer := func (name string , containers []corev1.Container ) (corev1.Container , bool ) {
184+ for _ , container := range containers {
185+ if container .Name == name {
186+ return container , true
187+ }
188+ }
189+ return corev1.Container {}, false
190+ }
191+ for _ , clusterContainer := range cluster {
192+ specContainer , ok := findContainer (clusterContainer .Name , spec )
193+ if ! ok {
194+ return true , false
195+ }
196+ specImage := specContainer .Image
197+ clusterImage := clusterContainer .Image
198+ // Images can be updated, so we want to ignore changes when checking for immutable fields
199+ specContainer .Image = clusterImage
200+ if ! equality .Semantic .DeepDerivative (specContainer , clusterContainer ) {
201+ return true , false
202+ }
203+ if specImage != clusterImage {
204+ return false , true
205+ }
206+ }
207+ return false , false
208+ }
209+
108210func routingDiffFunc (spec , cluster crclient.Object ) (delete , update bool ) {
109211 specRouting := spec .(* v1alpha1.DevWorkspaceRouting )
110212 clusterRouting := cluster .(* v1alpha1.DevWorkspaceRouting )
0 commit comments