mirror of
https://github.com/vmware-tanzu/pinniped.git
synced 2025-12-23 06:15:47 +00:00
allow the kube cert agent deployment's strategy type to be configured
This commit is contained in:
@@ -105,11 +105,16 @@ type AgentConfig struct {
|
||||
// PriorityClassName optionally sets the PriorityClassName for the agent's pod.
|
||||
PriorityClassName string
|
||||
|
||||
// RunAsUser is the UID to run the entrypoint of the container process
|
||||
// RunAsUser is the UID to run the entrypoint of the container process.
|
||||
RunAsUser *int64
|
||||
|
||||
// RunAsGroup is the GID to run the entrypoint of the container process
|
||||
// RunAsGroup is the GID to run the entrypoint of the container process.
|
||||
RunAsGroup *int64
|
||||
|
||||
// DeploymentStrategyType will be set as the agent Deployment's deployment strategy type.
|
||||
// When nil, the Deployment will not specify any deployment strategy type, and will therefore have its
|
||||
// deployment strategy type set by Kubernetes default behavior (currently RollingUpdate).
|
||||
DeploymentStrategyType *appsv1.DeploymentStrategyType
|
||||
}
|
||||
|
||||
// Only select using the unique label which will not match the pods of any other Deployment.
|
||||
@@ -440,12 +445,14 @@ func (c *agentController) createOrUpdateDeployment(ctx context.Context, newestCo
|
||||
desireTemplateLabelsUpdate := !apiequality.Semantic.DeepEqual(updatedDeployment.Spec.Template.Labels, existingDeployment.Spec.Template.Labels)
|
||||
// The user might want to set PriorityClassName back to the default value of empty string. DeepDerivative() won't detect this case below.
|
||||
desirePriorityClassNameUpdate := updatedDeployment.Spec.Template.Spec.PriorityClassName != existingDeployment.Spec.Template.Spec.PriorityClassName
|
||||
// The user might want to set deploymentStrategyType back to the default value. DeepDerivative() won't detect this case below.
|
||||
desireDeploymentStrategyTypeUpdate := updatedDeployment.Spec.Strategy.Type != existingDeployment.Spec.Strategy.Type
|
||||
|
||||
// If the existing Deployment already matches our desired spec, we're done.
|
||||
if apiequality.Semantic.DeepDerivative(updatedDeployment, existingDeployment) {
|
||||
// DeepDerivative allows the map fields of updatedDeployment to be a subset of existingDeployment,
|
||||
// but we want to check that certain of those map fields are exactly equal before deciding to skip the update.
|
||||
if !desireSelectorUpdate && !desireTemplateLabelsUpdate && !desirePriorityClassNameUpdate {
|
||||
if !desireSelectorUpdate && !desireTemplateLabelsUpdate && !desirePriorityClassNameUpdate && !desireDeploymentStrategyTypeUpdate {
|
||||
return nil // already equal enough, so skip update
|
||||
}
|
||||
}
|
||||
@@ -614,6 +621,14 @@ func (c *agentController) getPodSecurityContext() *corev1.PodSecurityContext {
|
||||
return podSecurityContext
|
||||
}
|
||||
|
||||
func (c *agentController) getDeploymentStrategy() appsv1.DeploymentStrategy {
|
||||
s := appsv1.DeploymentStrategy{}
|
||||
if c.cfg.DeploymentStrategyType != nil {
|
||||
s.Type = *c.cfg.DeploymentStrategyType
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (c *agentController) newAgentDeployment(controllerManagerPod *corev1.Pod) *appsv1.Deployment {
|
||||
var volumeMounts []corev1.VolumeMount
|
||||
if len(controllerManagerPod.Spec.Containers) > 0 {
|
||||
@@ -699,6 +714,9 @@ func (c *agentController) newAgentDeployment(controllerManagerPod *corev1.Pod) *
|
||||
|
||||
// Setting MinReadySeconds prevents the agent pods from being churned too quickly by the deployments controller.
|
||||
MinReadySeconds: 10,
|
||||
|
||||
// Allow the user to optionally configure the deployment strategy type.
|
||||
Strategy: c.getDeploymentStrategy(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -232,6 +232,7 @@ func TestAgentController(t *testing.T) {
|
||||
agentPriorityClassName string
|
||||
runAsUser *int64
|
||||
runAsGroup *int64
|
||||
deploymentStrategyType *appsv1.DeploymentStrategyType
|
||||
pinnipedObjects []runtime.Object
|
||||
kubeObjects []runtime.Object
|
||||
addKubeReactions func(*kubefake.Clientset)
|
||||
@@ -510,6 +511,137 @@ func TestAgentController(t *testing.T) {
|
||||
LastUpdateTime: metav1.NewTime(now),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "created new deployment with overridden deploymentStrategyType, no agent pods running yet",
|
||||
deploymentStrategyType: ptr.To(appsv1.RecreateDeploymentStrategyType),
|
||||
pinnipedObjects: []runtime.Object{
|
||||
initialCredentialIssuer,
|
||||
},
|
||||
kubeObjects: []runtime.Object{
|
||||
&corev1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "kube-system",
|
||||
Name: "kube-controller-manager-3",
|
||||
Labels: map[string]string{"component": "kube-controller-manager"},
|
||||
CreationTimestamp: metav1.NewTime(now.Add(-1 * time.Hour)),
|
||||
},
|
||||
Spec: corev1.PodSpec{NodeName: schedulableControllerManagerNode.Name},
|
||||
Status: corev1.PodStatus{Phase: corev1.PodRunning},
|
||||
},
|
||||
healthyKubeControllerManagerPod,
|
||||
&corev1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "kube-system",
|
||||
Name: "kube-controller-manager-2",
|
||||
Labels: map[string]string{"component": "kube-controller-manager"},
|
||||
CreationTimestamp: metav1.NewTime(now.Add(-2 * time.Hour)),
|
||||
},
|
||||
Spec: corev1.PodSpec{NodeName: schedulableControllerManagerNode.Name},
|
||||
Status: corev1.PodStatus{Phase: corev1.PodRunning},
|
||||
},
|
||||
pendingAgentPod,
|
||||
schedulableControllerManagerNode,
|
||||
},
|
||||
wantDistinctErrors: []string{
|
||||
"could not find a healthy agent pod (1 candidate)",
|
||||
},
|
||||
alsoAllowUndesiredDistinctErrors: []string{
|
||||
// due to the high amount of nondeterminism in this test, this error will sometimes also happen, but is not required to happen
|
||||
`could not ensure agent deployment: deployments.apps "pinniped-concierge-kube-cert-agent" already exists`,
|
||||
},
|
||||
wantDistinctLogs: []string{
|
||||
`{"level":"info","timestamp":"2099-08-08T13:57:36.123456Z","logger":"kube-cert-agent-controller","caller":"kubecertagent/kubecertagent.go:<line>$kubecertagent.(*agentController).createOrUpdateDeployment","message":"creating new deployment","deployment":{"name":"pinniped-concierge-kube-cert-agent","namespace":"concierge"},"templatePod":{"name":"kube-controller-manager-1","namespace":"kube-system"}}`,
|
||||
},
|
||||
wantAgentDeployment: modifiedHealthyHealthyAgentDeployment(func(deployment *appsv1.Deployment) {
|
||||
deployment.Spec.Strategy = appsv1.DeploymentStrategy{
|
||||
Type: appsv1.RecreateDeploymentStrategyType,
|
||||
}
|
||||
}),
|
||||
wantDeploymentActionVerbs: []string{"list", "watch", "create"},
|
||||
wantStrategy: &conciergeconfigv1alpha1.CredentialIssuerStrategy{
|
||||
Type: conciergeconfigv1alpha1.KubeClusterSigningCertificateStrategyType,
|
||||
Status: conciergeconfigv1alpha1.ErrorStrategyStatus,
|
||||
Reason: conciergeconfigv1alpha1.CouldNotFetchKeyStrategyReason,
|
||||
Message: "could not find a healthy agent pod (1 candidate)",
|
||||
LastUpdateTime: metav1.NewTime(now),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "deployment exists, configmap is valid, exec succeeds, overridden deploymentStrategyType is updated into the deployment",
|
||||
pinnipedObjects: []runtime.Object{
|
||||
initialCredentialIssuer,
|
||||
},
|
||||
kubeObjects: []runtime.Object{
|
||||
healthyKubeControllerManagerPod,
|
||||
healthyAgentDeployment,
|
||||
healthyAgentPod,
|
||||
validClusterInfoConfigMap,
|
||||
schedulableControllerManagerNode,
|
||||
},
|
||||
deploymentStrategyType: ptr.To(appsv1.RecreateDeploymentStrategyType),
|
||||
mocks: mockExecSucceeds,
|
||||
wantDistinctErrors: []string{""},
|
||||
wantAgentDeployment: modifiedHealthyHealthyAgentDeployment(func(deployment *appsv1.Deployment) {
|
||||
deployment.Spec.Strategy = appsv1.DeploymentStrategy{Type: appsv1.RecreateDeploymentStrategyType}
|
||||
}),
|
||||
wantDeploymentActionVerbs: []string{"list", "watch", "update"},
|
||||
wantDistinctLogs: []string{
|
||||
`{"level":"info","timestamp":"2099-08-08T13:57:36.123456Z","logger":"kube-cert-agent-controller","caller":"kubecertagent/kubecertagent.go:<line>$kubecertagent.(*agentController).createOrUpdateDeployment","message":"updating existing deployment","deployment":{"name":"pinniped-concierge-kube-cert-agent","namespace":"concierge"},"templatePod":{"name":"kube-controller-manager-1","namespace":"kube-system"}}`,
|
||||
`{"level":"info","timestamp":"2099-08-08T13:57:36.123456Z","logger":"kube-cert-agent-controller","caller":"kubecertagent/kubecertagent.go:<line>$kubecertagent.(*agentController).loadSigningKey","message":"successfully loaded signing key from agent pod into cache"}`,
|
||||
},
|
||||
wantStrategy: &conciergeconfigv1alpha1.CredentialIssuerStrategy{
|
||||
Type: conciergeconfigv1alpha1.KubeClusterSigningCertificateStrategyType,
|
||||
Status: conciergeconfigv1alpha1.SuccessStrategyStatus,
|
||||
Reason: conciergeconfigv1alpha1.FetchedKeyStrategyReason,
|
||||
Message: "key was fetched successfully",
|
||||
LastUpdateTime: metav1.NewTime(now),
|
||||
Frontend: &conciergeconfigv1alpha1.CredentialIssuerFrontend{
|
||||
Type: conciergeconfigv1alpha1.TokenCredentialRequestAPIFrontendType,
|
||||
TokenCredentialRequestAPIInfo: &conciergeconfigv1alpha1.TokenCredentialRequestAPIInfo{
|
||||
Server: "https://test-kubernetes-endpoint.example.com",
|
||||
CertificateAuthorityData: "dGVzdC1rdWJlcm5ldGVzLWNh",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "deployment exists with a non-empty deploymentStrategyType, configmap is valid, exec succeeds, deploymentStrategyType config is null so deployment strategy is set back to zero value",
|
||||
pinnipedObjects: []runtime.Object{
|
||||
initialCredentialIssuer,
|
||||
},
|
||||
kubeObjects: []runtime.Object{
|
||||
healthyKubeControllerManagerPod,
|
||||
modifiedHealthyHealthyAgentDeployment(func(deployment *appsv1.Deployment) {
|
||||
deployment.Spec.Strategy = appsv1.DeploymentStrategy{Type: appsv1.RecreateDeploymentStrategyType}
|
||||
}),
|
||||
healthyAgentPod,
|
||||
validClusterInfoConfigMap,
|
||||
schedulableControllerManagerNode,
|
||||
},
|
||||
deploymentStrategyType: nil,
|
||||
mocks: mockExecSucceeds,
|
||||
wantDistinctErrors: []string{""},
|
||||
wantAgentDeployment: healthyAgentDeployment,
|
||||
wantDeploymentActionVerbs: []string{"list", "watch", "update"},
|
||||
wantDistinctLogs: []string{
|
||||
`{"level":"info","timestamp":"2099-08-08T13:57:36.123456Z","logger":"kube-cert-agent-controller","caller":"kubecertagent/kubecertagent.go:<line>$kubecertagent.(*agentController).createOrUpdateDeployment","message":"updating existing deployment","deployment":{"name":"pinniped-concierge-kube-cert-agent","namespace":"concierge"},"templatePod":{"name":"kube-controller-manager-1","namespace":"kube-system"}}`,
|
||||
`{"level":"info","timestamp":"2099-08-08T13:57:36.123456Z","logger":"kube-cert-agent-controller","caller":"kubecertagent/kubecertagent.go:<line>$kubecertagent.(*agentController).loadSigningKey","message":"successfully loaded signing key from agent pod into cache"}`,
|
||||
},
|
||||
wantStrategy: &conciergeconfigv1alpha1.CredentialIssuerStrategy{
|
||||
Type: conciergeconfigv1alpha1.KubeClusterSigningCertificateStrategyType,
|
||||
Status: conciergeconfigv1alpha1.SuccessStrategyStatus,
|
||||
Reason: conciergeconfigv1alpha1.FetchedKeyStrategyReason,
|
||||
Message: "key was fetched successfully",
|
||||
LastUpdateTime: metav1.NewTime(now),
|
||||
Frontend: &conciergeconfigv1alpha1.CredentialIssuerFrontend{
|
||||
Type: conciergeconfigv1alpha1.TokenCredentialRequestAPIFrontendType,
|
||||
TokenCredentialRequestAPIInfo: &conciergeconfigv1alpha1.TokenCredentialRequestAPIInfo{
|
||||
Server: "https://test-kubernetes-endpoint.example.com",
|
||||
CertificateAuthorityData: "dGVzdC1rdWJlcm5ldGVzLWNh",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "created new deployment based on alternate supported controller-manager CLI flags, no agent pods running yet",
|
||||
pinnipedObjects: []runtime.Object{
|
||||
@@ -1681,10 +1813,11 @@ func TestAgentController(t *testing.T) {
|
||||
// Concierge Deployment, so we do not want it to exist on the Kube cert agent pods.
|
||||
"app": "anything",
|
||||
},
|
||||
DiscoveryURLOverride: tt.discoveryURLOverride,
|
||||
PriorityClassName: tt.agentPriorityClassName,
|
||||
RunAsUser: tt.runAsUser,
|
||||
RunAsGroup: tt.runAsGroup,
|
||||
DiscoveryURLOverride: tt.discoveryURLOverride,
|
||||
PriorityClassName: tt.agentPriorityClassName,
|
||||
RunAsUser: tt.runAsUser,
|
||||
RunAsGroup: tt.runAsGroup,
|
||||
DeploymentStrategyType: tt.deploymentStrategyType,
|
||||
},
|
||||
&kubeclient.Client{Kubernetes: kubeClientset, PinnipedConcierge: conciergeClientset},
|
||||
kubeInformers.Core().V1().Pods(),
|
||||
|
||||
Reference in New Issue
Block a user