Sync due to defaults
Since we can miss it while checking only spec
This commit is contained in:
		
							parent
							
								
									3e98832703
								
							
						
					
					
						commit
						037d7120ef
					
				|  | @ -1206,7 +1206,7 @@ func (c *Cluster) deletePatroniClusterConfigMaps() error { | |||
| // Test if two connection pool configuration needs to be synced. For simplicity
 | ||||
| // compare not the actual K8S objects, but the configuration itself and request
 | ||||
| // sync if there is any difference.
 | ||||
| func (c *Cluster) needSyncConnPoolDeployments(oldSpec, newSpec *acidv1.ConnectionPool) (sync bool, reasons []string) { | ||||
| func (c *Cluster) needSyncConnPoolSpecs(oldSpec, newSpec *acidv1.ConnectionPool) (sync bool, reasons []string) { | ||||
| 	reasons = []string{} | ||||
| 	sync = false | ||||
| 
 | ||||
|  | @ -1228,3 +1228,69 @@ func (c *Cluster) needSyncConnPoolDeployments(oldSpec, newSpec *acidv1.Connectio | |||
| 
 | ||||
| 	return sync, reasons | ||||
| } | ||||
| 
 | ||||
| func syncResources(a, b *v1.ResourceRequirements) bool { | ||||
| 	for _, res := range []v1.ResourceName{ | ||||
| 		v1.ResourceCPU, | ||||
| 		v1.ResourceMemory, | ||||
| 	} { | ||||
| 		if !a.Limits[res].Equal(b.Limits[res]) || | ||||
| 			!a.Requests[res].Equal(b.Requests[res]) { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| // Check if we need to synchronize connection pool deploymend due to new
 | ||||
| // defaults, that are different from what we see in the DeploymentSpec
 | ||||
| func (c *Cluster) needSyncConnPoolDefaults( | ||||
| 	spec *acidv1.ConnectionPool, | ||||
| 	deployment *appsv1.Deployment) (sync bool, reasons []string) { | ||||
| 
 | ||||
| 	reasons = []string{} | ||||
| 	sync = false | ||||
| 
 | ||||
| 	config := c.OpConfig.ConnectionPool | ||||
| 	podTemplate := deployment.Spec.Template | ||||
| 	poolContainer := podTemplate.Spec.Containers[constants.ConnPoolContainer] | ||||
| 
 | ||||
| 	if spec.NumberOfInstances == nil && | ||||
| 		deployment.Spec.Replicas != config.NumberOfInstances { | ||||
| 
 | ||||
| 		sync = true | ||||
| 		msg := fmt.Sprintf("NumberOfInstances is different (%d vs %d)", | ||||
| 			deployment.Spec.Replicas, config.NumberOfInstances) | ||||
| 		reasons = append(reasons, msg) | ||||
| 	} | ||||
| 
 | ||||
| 	if spec.DockerImage == "" && | ||||
| 		poolContainer.Image != config.Image { | ||||
| 
 | ||||
| 		sync = true | ||||
| 		msg := fmt.Sprintf("DockerImage is different (%s vs %s)", | ||||
| 			poolContainer.Image, config.Image) | ||||
| 		reasons = append(reasons, msg) | ||||
| 	} | ||||
| 
 | ||||
| 	expectedResources, err := generateResourceRequirements(spec.Resources, | ||||
| 		c.makeDefaultConnPoolResources()) | ||||
| 
 | ||||
| 	// An error to generate expected resources means something is not quite
 | ||||
| 	// right, but for the purpose of robustness do not panic here, just report
 | ||||
| 	// and ignore resources comparison (in the worst case there will be no
 | ||||
| 	// updates for new resource values).
 | ||||
| 	if err == nil && syncResources(&poolContainer.Resources, expectedResources) { | ||||
| 		sync = true | ||||
| 		msg := fmt.Sprintf("Resources are different (%+v vs %+v)", | ||||
| 			poolContainer.Resources, expectedResources) | ||||
| 		reasons = append(reasons, msg) | ||||
| 	} | ||||
| 
 | ||||
| 	if err != nil { | ||||
| 		c.logger.Warningf("Cannot generate expected resources, %v", err) | ||||
| 	} | ||||
| 
 | ||||
| 	return sync, reasons | ||||
| } | ||||
|  |  | |||
|  | @ -1754,7 +1754,7 @@ func (c *Cluster) generateConnPoolPodTemplate(spec *acidv1.PostgresSpec) ( | |||
| 	secretSelector := func(key string) *v1.SecretKeySelector { | ||||
| 		return &v1.SecretKeySelector{ | ||||
| 			LocalObjectReference: v1.LocalObjectReference{ | ||||
| 				Name: c.credentialSecretName(c.OpConfig.SuperUsername), | ||||
| 				Name: c.credentialSecretName(c.OpConfig.ConnectionPool.User), | ||||
| 			}, | ||||
| 			Key: key, | ||||
| 		} | ||||
|  |  | |||
|  | @ -702,8 +702,10 @@ func (c *Cluster) syncConnectionPoolWorker(oldSpec, newSpec *acidv1.Postgresql) | |||
| 		// actual synchronization
 | ||||
| 		oldConnPool := oldSpec.Spec.ConnectionPool | ||||
| 		newConnPool := newSpec.Spec.ConnectionPool | ||||
| 		sync, reason := c.needSyncConnPoolDeployments(oldConnPool, newConnPool) | ||||
| 		if sync { | ||||
| 		specSync, specReason := c.needSyncConnPoolSpecs(oldConnPool, newConnPool) | ||||
| 		defaultsSync, defaultsReason := c.needSyncConnPoolDefaults(newConnPool, deployment) | ||||
| 		reason := append(specReason, defaultsReason...) | ||||
| 		if specSync || defaultsSync { | ||||
| 			c.logger.Infof("Update connection pool deployment %s, reason: %s", | ||||
| 				c.connPoolName(), reason) | ||||
| 
 | ||||
|  |  | |||
|  | @ -88,6 +88,11 @@ func TestConnPoolSynchronization(t *testing.T) { | |||
| 		Service:    &v1.Service{}, | ||||
| 	} | ||||
| 
 | ||||
| 	clusterNewDefaultsMock := *cluster | ||||
| 	clusterNewDefaultsMock.KubeClient = k8sutil.NewMockKubernetesClient() | ||||
| 	cluster.OpConfig.ConnectionPool.Image = "pooler:2.0" | ||||
| 	cluster.OpConfig.ConnectionPool.NumberOfInstances = int32ToPointer(2) | ||||
| 
 | ||||
| 	tests := []struct { | ||||
| 		subTest string | ||||
| 		oldSpec *acidv1.Postgresql | ||||
|  | @ -166,6 +171,21 @@ func TestConnPoolSynchronization(t *testing.T) { | |||
| 			cluster: &clusterMock, | ||||
| 			check:   deploymentUpdated, | ||||
| 		}, | ||||
| 		{ | ||||
| 			subTest: "update image from changed defaults", | ||||
| 			oldSpec: &acidv1.Postgresql{ | ||||
| 				Spec: acidv1.PostgresSpec{ | ||||
| 					ConnectionPool: &acidv1.ConnectionPool{}, | ||||
| 				}, | ||||
| 			}, | ||||
| 			newSpec: &acidv1.Postgresql{ | ||||
| 				Spec: acidv1.PostgresSpec{ | ||||
| 					ConnectionPool: &acidv1.ConnectionPool{}, | ||||
| 				}, | ||||
| 			}, | ||||
| 			cluster: &clusterNewDefaultsMock, | ||||
| 			check:   deploymentUpdated, | ||||
| 		}, | ||||
| 	} | ||||
| 	for _, tt := range tests { | ||||
| 		err := tt.cluster.syncConnectionPool(tt.oldSpec, tt.newSpec) | ||||
|  |  | |||
|  | @ -10,4 +10,6 @@ const ( | |||
| 	ConnectionPoolDefaultCpuLimit      = "100m" | ||||
| 	ConnectionPoolDefaultMemoryRequest = "100Mi" | ||||
| 	ConnectionPoolDefaultMemoryLimit   = "100Mi" | ||||
| 
 | ||||
| 	ConnPoolContainer = 0 | ||||
| ) | ||||
|  |  | |||
|  | @ -300,6 +300,18 @@ func (mock *mockDeployment) Get(name string, opts metav1.GetOptions) (*apiappsv1 | |||
| 		ObjectMeta: metav1.ObjectMeta{ | ||||
| 			Name: "test-deployment", | ||||
| 		}, | ||||
| 		Spec: apiappsv1.DeploymentSpec{ | ||||
| 			Replicas: int32ToPointer(1), | ||||
| 			Template: v1.PodTemplateSpec{ | ||||
| 				Spec: v1.PodSpec{ | ||||
| 					Containers: []v1.Container{ | ||||
| 						v1.Container{ | ||||
| 							Image: "pooler:1.0", | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 	}, nil | ||||
| } | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue