160 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			160 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			Go
		
	
	
	
| package cluster
 | |
| 
 | |
| import (
 | |
| 	"reflect"
 | |
| 
 | |
| 	u "github.com/zalando-incubator/postgres-operator/pkg/util"
 | |
| 	"k8s.io/api/core/v1"
 | |
| 	"k8s.io/api/apps/v1beta1"
 | |
| )
 | |
| 
 | |
| type ContainerCondition func(a, b *v1.Container) bool
 | |
| type StatefulSetCondition func(a, b *v1beta1.StatefulSet) bool
 | |
| type VolumeClaimCondition func(a, b *v1.PersistentVolumeClaim) bool
 | |
| 
 | |
| type ResourceCheck struct {
 | |
| 	containerCondition   ContainerCondition
 | |
| 	statefulSetCondition StatefulSetCondition
 | |
| 	volumeClaimCondition VolumeClaimCondition
 | |
| 	result               Result
 | |
| 	reason               string
 | |
| }
 | |
| 
 | |
| type Result struct {
 | |
| 	needUpdate      *bool
 | |
| 	needsRollUpdate *bool
 | |
| 	needsReplace    *bool
 | |
| }
 | |
| 
 | |
| func (c *Cluster) NewCheck(msg string, cond interface{}, result Result) ResourceCheck {
 | |
| 	switch cond.(type) {
 | |
| 	case ContainerCondition:
 | |
| 		return ResourceCheck{
 | |
| 			reason:             msg,
 | |
| 			containerCondition: cond.(ContainerCondition),
 | |
| 			result:             result,
 | |
| 		}
 | |
| 	case StatefulSetCondition:
 | |
| 		return ResourceCheck{
 | |
| 			reason:               msg,
 | |
| 			statefulSetCondition: cond.(StatefulSetCondition),
 | |
| 			result:               result,
 | |
| 		}
 | |
| 	case VolumeClaimCondition:
 | |
| 		return ResourceCheck{
 | |
| 			reason:               msg,
 | |
| 			volumeClaimCondition: cond.(VolumeClaimCondition),
 | |
| 			result:               result,
 | |
| 		}
 | |
| 	default:
 | |
| 		c.logger.Errorf("Undefined check condition type: %v", cond)
 | |
| 		return ResourceCheck{}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (c *Cluster) getStatefulSetChecks() []ResourceCheck {
 | |
| 	return []ResourceCheck{
 | |
| 		c.NewCheck("new statefulset's number of replicas doesn't match the current one",
 | |
| 			func(a, b *v1beta1.StatefulSet) bool { return a.Spec.Replicas != b.Spec.Replicas },
 | |
| 			Result{needUpdate: u.True()}),
 | |
| 
 | |
| 		c.NewCheck("new statefulset's annotations doesn't match the current one",
 | |
| 			func(a, b *v1beta1.StatefulSet) bool { return !reflect.DeepEqual(a.Annotations, b.Annotations) },
 | |
| 			Result{needUpdate: u.True()}),
 | |
| 
 | |
| 		c.NewCheck("new statefulset's serviceAccountName service asccount name doesn't match the current one",
 | |
| 			func(a, b *v1beta1.StatefulSet) bool {
 | |
| 				return len(a.Spec.Template.Spec.Containers) != len(b.Spec.Template.Spec.Containers)
 | |
| 			}, Result{needsRollUpdate: u.True()}),
 | |
| 
 | |
| 		c.NewCheck("new statefulset's serviceAccountName service asccount name doesn't match the current one",
 | |
| 			func(a, b *v1beta1.StatefulSet) bool {
 | |
| 				return a.Spec.Template.Spec.ServiceAccountName !=
 | |
| 					b.Spec.Template.Spec.ServiceAccountName
 | |
| 			}, Result{needsRollUpdate: u.True(), needsReplace: u.True()}),
 | |
| 
 | |
| 		c.NewCheck("new statefulset's terminationGracePeriodSeconds  doesn't match the current one",
 | |
| 			func(a, b *v1beta1.StatefulSet) bool {
 | |
| 				return a.Spec.Template.Spec.TerminationGracePeriodSeconds !=
 | |
| 					b.Spec.Template.Spec.TerminationGracePeriodSeconds
 | |
| 			}, Result{needsRollUpdate: u.True(), needsReplace: u.True()}),
 | |
| 
 | |
| 		c.NewCheck("new statefulset's pod affinity doesn't match the current one",
 | |
| 			func(a, b *v1beta1.StatefulSet) bool {
 | |
| 				return !reflect.DeepEqual(a.Spec.Template.Spec.Affinity,
 | |
| 					b.Spec.Template.Spec.Affinity)
 | |
| 			}, Result{needsRollUpdate: u.True(), needsReplace: u.True()}),
 | |
| 
 | |
| 		// Some generated fields like creationTimestamp make it not possible to
 | |
| 		// use DeepCompare on Spec.Template.ObjectMeta
 | |
| 		c.NewCheck("new statefulset's metadata labels doesn't match the current one",
 | |
| 			func(a, b *v1beta1.StatefulSet) bool {
 | |
| 				return !reflect.DeepEqual(a.Spec.Template.Labels, b.Spec.Template.Labels)
 | |
| 			}, Result{needsRollUpdate: u.True(), needsReplace: u.True()}),
 | |
| 
 | |
| 		c.NewCheck("new statefulset's pod template metadata annotations doesn't match the current one",
 | |
| 			func(a, b *v1beta1.StatefulSet) bool {
 | |
| 				return !reflect.DeepEqual(a.Spec.Template.Annotations, b.Spec.Template.Annotations)
 | |
| 			}, Result{needUpdate: u.True(), needsRollUpdate: u.True(), needsReplace: u.True()}),
 | |
| 
 | |
| 		c.NewCheck("new statefulset's volumeClaimTemplates contains different number of volumes to the old one",
 | |
| 			func(a, b *v1beta1.StatefulSet) bool {
 | |
| 				return len(a.Spec.VolumeClaimTemplates) != len(b.Spec.VolumeClaimTemplates)
 | |
| 			}, Result{needsReplace: u.True()}),
 | |
| 
 | |
| 		c.NewCheck("new statefulset's selector doesn't match the current one",
 | |
| 			func(a, b *v1beta1.StatefulSet) bool {
 | |
| 				if a.Spec.Selector == nil || b.Spec.Selector == nil {
 | |
| 					return false
 | |
| 				}
 | |
| 				return !reflect.DeepEqual(a.Spec.Selector.MatchLabels, b.Spec.Selector.MatchLabels)
 | |
| 			}, Result{needsReplace: u.True()}),
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (c *Cluster) getContainerChecks() []ResourceCheck {
 | |
| 	return []ResourceCheck{
 | |
| 		c.NewCheck("new statefulset's container %d name doesn't match the current one",
 | |
| 			func(a, b *v1.Container) bool { return a.Name != b.Name },
 | |
| 			Result{needsRollUpdate: u.True()}),
 | |
| 
 | |
| 		c.NewCheck("new statefulset's container %d image doesn't match the current one",
 | |
| 			func(a, b *v1.Container) bool { return a.Image != b.Image },
 | |
| 			Result{needsRollUpdate: u.True()}),
 | |
| 
 | |
| 		c.NewCheck("new statefulset's container %d ports don't match the current one",
 | |
| 			func(a, b *v1.Container) bool { return !reflect.DeepEqual(a.Ports, b.Ports) },
 | |
| 			Result{needsRollUpdate: u.True()}),
 | |
| 
 | |
| 		c.NewCheck("new statefulset's container %d resources don't match the current ones",
 | |
| 			func(a, b *v1.Container) bool { return !compareResources(&a.Resources, &b.Resources) },
 | |
| 			Result{needsRollUpdate: u.True()}),
 | |
| 
 | |
| 		c.NewCheck("new statefulset's container %d environment doesn't match the current one",
 | |
| 			func(a, b *v1.Container) bool { return !reflect.DeepEqual(a.Env, b.Env) },
 | |
| 			Result{needsRollUpdate: u.True()}),
 | |
| 
 | |
| 		c.NewCheck("new statefulset's container %d environment sources don't match the current one",
 | |
| 			func(a, b *v1.Container) bool { return !reflect.DeepEqual(a.EnvFrom, b.EnvFrom) },
 | |
| 			Result{needsRollUpdate: u.True()}),
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (c *Cluster) getVolumeClaimChecks() []ResourceCheck {
 | |
| 	return []ResourceCheck{
 | |
| 		c.NewCheck("new statefulset's name for volume %d doesn't match the current one",
 | |
| 			func(a, b *v1.PersistentVolumeClaim) bool { return a.Name != b.Name },
 | |
| 			Result{needsReplace: u.True()}),
 | |
| 
 | |
| 		c.NewCheck("new statefulset's annotations for volume %q doesn't match the current one",
 | |
| 			func(a, b *v1.PersistentVolumeClaim) bool {
 | |
| 				return !reflect.DeepEqual(a.Annotations, b.Annotations)
 | |
| 			},
 | |
| 			Result{needsReplace: u.True()}),
 | |
| 
 | |
| 		c.NewCheck("new statefulset's volumeClaimTemplates specification for volume %q doesn't match the current one",
 | |
| 			func(a, b *v1.PersistentVolumeClaim) bool { return !reflect.DeepEqual(a.Spec, b.Spec) },
 | |
| 			Result{needsRollUpdate: u.True()}),
 | |
| 	}
 | |
| }
 |