Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 14 additions & 8 deletions pkg/reconciler/revision/resources/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,15 +138,19 @@ func certVolume(secret string) corev1.Volume {
}
}

func rewriteUserLivenessProbe(p *corev1.Probe, userPort int) {
func rewriteUserLivenessProbe(p *corev1.Probe, userPort int, allowCustomPort bool) {
if p == nil {
return
}
switch {
case p.HTTPGet != nil:
p.HTTPGet.Port = intstr.FromInt(userPort)
if !allowCustomPort || p.HTTPGet.Port.IntValue() == 0 {
p.HTTPGet.Port = intstr.FromInt(userPort)
}
case p.TCPSocket != nil:
p.TCPSocket.Port = intstr.FromInt(userPort)
if !allowCustomPort || p.TCPSocket.Port.IntValue() == 0 {
p.TCPSocket.Port = intstr.FromInt(userPort)
}
}
}

Expand Down Expand Up @@ -206,7 +210,7 @@ func makePodSpec(rev *v1.Revision, cfg *config.Config) (*corev1.PodSpec, error)
extraVolumes = append(extraVolumes, certVolume(networking.ServingCertName))
}

podSpec := BuildPodSpec(rev, append(BuildUserContainers(rev), *queueContainer), cfg)
podSpec := BuildPodSpec(rev, append(BuildUserContainers(rev, cfg.Features), *queueContainer), cfg)
podSpec.Volumes = append(podSpec.Volumes, extraVolumes...)

if val := cfg.Deployment.PodRuntimeClassName(rev.ObjectMeta.Labels); podSpec.RuntimeClassName == nil {
Expand Down Expand Up @@ -237,12 +241,14 @@ func makePodSpec(rev *v1.Revision, cfg *config.Config) (*corev1.PodSpec, error)
}

// BuildUserContainers makes an array of containers from the Revision template.
func BuildUserContainers(rev *v1.Revision) []corev1.Container {
// features may be nil, in which case default behavior (strict port rewriting) is used.
func BuildUserContainers(rev *v1.Revision, features *apiconfig.Features) []corev1.Container {
allowCustomPort := features != nil && features.MultiContainerProbing == apiconfig.Enabled
containers := make([]corev1.Container, 0, len(rev.Spec.PodSpec.Containers))
for i := range rev.Spec.PodSpec.Containers {
var container corev1.Container
if len(rev.Spec.PodSpec.Containers[i].Ports) != 0 || len(rev.Spec.PodSpec.Containers) == 1 {
container = makeServingContainer(*rev.Spec.PodSpec.Containers[i].DeepCopy(), rev)
container = makeServingContainer(*rev.Spec.PodSpec.Containers[i].DeepCopy(), rev, allowCustomPort)
} else {
container = makeContainer(*rev.Spec.PodSpec.Containers[i].DeepCopy(), rev)
}
Expand Down Expand Up @@ -283,15 +289,15 @@ func makeContainer(container corev1.Container, rev *v1.Revision) corev1.Containe
return container
}

func makeServingContainer(servingContainer corev1.Container, rev *v1.Revision) corev1.Container {
func makeServingContainer(servingContainer corev1.Container, rev *v1.Revision, allowCustomPort bool) corev1.Container {
userPort := getUserPort(rev)
userPortStr := strconv.Itoa(int(userPort))
// Replacement is safe as only up to a single port is allowed on the Revision
servingContainer.Ports = buildContainerPorts(userPort)
servingContainer.Env = append(servingContainer.Env, buildUserPortEnv(userPortStr))
container := makeContainer(servingContainer, rev)
// If the user provides a liveness probe, we should rewrite in the port on the user-container for them.
rewriteUserLivenessProbe(container.LivenessProbe, int(userPort))
rewriteUserLivenessProbe(container.LivenessProbe, int(userPort), allowCustomPort)
return container
}

Expand Down
155 changes: 155 additions & 0 deletions pkg/reconciler/revision/resources/deploy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1077,6 +1077,161 @@ func TestMakePodSpec(t *testing.T) {
),
queueContainer(),
}),
}, {
name: "with HTTP liveness probe on custom port and multi-container-probing enabled",
fc: apicfg.Features{
MultiContainerProbing: apicfg.Enabled,
},
rev: revision("bar", "foo",
withContainers([]corev1.Container{{
Name: servingContainerName,
Image: "busybox",
ReadinessProbe: withTCPReadinessProbe(v1.DefaultUserPort),
LivenessProbe: &corev1.Probe{
ProbeHandler: corev1.ProbeHandler{
HTTPGet: &corev1.HTTPGetAction{
Path: "/health",
Port: intstr.FromInt32(8081),
},
},
},
}}),
WithContainerStatuses([]v1.ContainerStatus{{
ImageDigest: "busybox@sha256:deadbeef",
}}),
),
want: podSpec(
[]corev1.Container{
servingContainer(
func(container *corev1.Container) {
container.Image = "busybox@sha256:deadbeef"
},
withLivenessProbe(corev1.ProbeHandler{
HTTPGet: &corev1.HTTPGetAction{
Path: "/health",
Port: intstr.FromInt32(8081),
},
}),
),
queueContainer(
withEnvVar("ENABLE_MULTI_CONTAINER_PROBES", "true"),
withEnvVar("SERVING_READINESS_PROBE", `[{"tcpSocket":{"port":8080,"host":"127.0.0.1"}}]`),
),
}),
}, {
name: "with TCP liveness probe on custom port and multi-container-probing enabled",
fc: apicfg.Features{
MultiContainerProbing: apicfg.Enabled,
},
rev: revision("bar", "foo",
withContainers([]corev1.Container{{
Name: servingContainerName,
Image: "busybox",
ReadinessProbe: withTCPReadinessProbe(v1.DefaultUserPort),
LivenessProbe: &corev1.Probe{
ProbeHandler: corev1.ProbeHandler{
TCPSocket: &corev1.TCPSocketAction{
Port: intstr.FromInt32(8081),
},
},
},
}}),
WithContainerStatuses([]v1.ContainerStatus{{
ImageDigest: "busybox@sha256:deadbeef",
}}),
),
want: podSpec(
[]corev1.Container{
servingContainer(
func(container *corev1.Container) {
container.Image = "busybox@sha256:deadbeef"
},
withLivenessProbe(corev1.ProbeHandler{
TCPSocket: &corev1.TCPSocketAction{
Port: intstr.FromInt32(8081),
},
}),
),
queueContainer(
withEnvVar("ENABLE_MULTI_CONTAINER_PROBES", "true"),
withEnvVar("SERVING_READINESS_PROBE", `[{"tcpSocket":{"port":8080,"host":"127.0.0.1"}}]`),
),
}),
}, {
name: "with HTTP liveness probe without port and multi-container-probing enabled",
fc: apicfg.Features{
MultiContainerProbing: apicfg.Enabled,
},
rev: revision("bar", "foo",
withContainers([]corev1.Container{{
Name: servingContainerName,
Image: "busybox",
ReadinessProbe: withTCPReadinessProbe(v1.DefaultUserPort),
LivenessProbe: &corev1.Probe{
ProbeHandler: corev1.ProbeHandler{
HTTPGet: &corev1.HTTPGetAction{
Path: "/",
},
},
},
}}),
WithContainerStatuses([]v1.ContainerStatus{{
ImageDigest: "busybox@sha256:deadbeef",
}}),
),
want: podSpec(
[]corev1.Container{
servingContainer(
func(container *corev1.Container) {
container.Image = "busybox@sha256:deadbeef"
},
withLivenessProbe(corev1.ProbeHandler{
HTTPGet: &corev1.HTTPGetAction{
Path: "/",
Port: intstr.FromInt32(v1.DefaultUserPort),
},
}),
),
queueContainer(
withEnvVar("ENABLE_MULTI_CONTAINER_PROBES", "true"),
withEnvVar("SERVING_READINESS_PROBE", `[{"tcpSocket":{"port":8080,"host":"127.0.0.1"}}]`),
),
}),
}, {
name: "with HTTP liveness probe on custom port and multi-container-probing disabled",
rev: revision("bar", "foo",
withContainers([]corev1.Container{{
Name: servingContainerName,
Image: "busybox",
ReadinessProbe: withTCPReadinessProbe(v1.DefaultUserPort),
LivenessProbe: &corev1.Probe{
ProbeHandler: corev1.ProbeHandler{
HTTPGet: &corev1.HTTPGetAction{
Path: "/health",
Port: intstr.FromInt32(8081),
},
},
},
}}),
WithContainerStatuses([]v1.ContainerStatus{{
ImageDigest: "busybox@sha256:deadbeef",
}}),
),
want: podSpec(
[]corev1.Container{
servingContainer(
func(container *corev1.Container) {
container.Image = "busybox@sha256:deadbeef"
},
withLivenessProbe(corev1.ProbeHandler{
HTTPGet: &corev1.HTTPGetAction{
Path: "/health",
Port: intstr.FromInt32(v1.DefaultUserPort),
},
}),
),
queueContainer(),
}),
}, {
name: "with HTTP startup probe",
rev: revision("bar", "foo",
Expand Down
2 changes: 1 addition & 1 deletion pkg/webhook/podspec_dryrun.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ func validatePodSpec(ctx context.Context, ps v1.RevisionSpec, namespace string)
Spec: ps,
}
rev.SetDefaults(ctx)
podSpec := resources.BuildPodSpec(rev, resources.BuildUserContainers(rev), nil /*configs*/)
podSpec := resources.BuildPodSpec(rev, resources.BuildUserContainers(rev, nil /*features*/), nil /*configs*/)

// Make a sample pod with the template Revisions & PodSpec and dryrun call to API-server
pod := &corev1.Pod{
Expand Down
Loading