Update to use custom PodSpec struct and support Affinity too

Signed-off-by: James Munnelly <james@munnelly.eu>
This commit is contained in:
James Munnelly 2019-07-05 15:21:40 +01:00
parent 521f02e988
commit 361ee83102
6 changed files with 78 additions and 50 deletions

View File

@ -74,9 +74,9 @@ podTemplate
You may wish to change or add to the labels and annotations of solver pods.
These can be configured under the ``metadata`` field under ``podTemplate``.
Similarly, you can set the node selector and tolerations of solver pods by
configuring under the ``spec`` field of the ``podTemplate``. No other spec fields
can be edited.
Similarly, you can set the nodeSelector, tolerations and affinity of solver
pods by configuring under the ``spec`` field of the ``podTemplate``. No other
spec fields can be edited.
An example of how you could configure the template is as so:

View File

@ -298,16 +298,38 @@ type ACMEChallengeSolverHTTP01Ingress struct {
Name string `json:"name,omitempty"`
// Optional pod template used to configure the ACME challenge solver pods
// used for HTTP01 challenges. Only labels and annotations may be set and
// will be merged ontop of the defaults. PodTemplate labels and annotation
// fields will override fields with matching keys.
// used for HTTP01 challenges
// +optional
PodTemplate *ACMEChallengeSolverHTTP01IngressPodTemplate `json:"podTemplate,omitempty"`
}
type ACMEChallengeSolverHTTP01IngressPodTemplate struct {
// ObjectMeta overrides for the pod used to solve HTTP01 challenges.
// Only the 'labels' and 'annotations' fields may be set.
// If labels or annotations overlap with in-built value, the values here
// will override the in-built values.
metav1.ObjectMeta `json:"metadata,omitempty"`
corev1.PodSpec `json:"spec,omitempty"`
// PodSpec defines overrides for the HTTP01 challenge solver pod.
// Only the 'nodeSelector', 'affinity' and 'tolerations' fields are
// supported currently. All other fields will be ignored.
Spec ACMEChallengeSolverHTTP01IngressPodSpec `json:"spec,omitempty"`
}
type ACMEChallengeSolverHTTP01IngressPodSpec struct {
// NodeSelector is a selector which must be true for the pod to fit on a node.
// Selector which must match a node's labels for the pod to be scheduled on that node.
// More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/
// +optional
NodeSelector map[string]string `json:"nodeSelector,omitempty"`
// If specified, the pod's scheduling constraints
// +optional
Affinity *corev1.Affinity `json:"affinity,omitempty"`
// If specified, the pod's tolerations.
// +optional
Tolerations []corev1.Toleration `json:"tolerations,omitempty"`
}
type ACMEChallengeSolverDNS01 struct {

View File

@ -21,8 +21,9 @@ limitations under the License.
package v1alpha1
import (
v1 "k8s.io/api/core/v1"
v1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
)
@ -188,11 +189,46 @@ func (in *ACMEChallengeSolverHTTP01Ingress) DeepCopy() *ACMEChallengeSolverHTTP0
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ACMEChallengeSolverHTTP01IngressPodSpec) DeepCopyInto(out *ACMEChallengeSolverHTTP01IngressPodSpec) {
*out = *in
if in.NodeSelector != nil {
in, out := &in.NodeSelector, &out.NodeSelector
*out = make(map[string]string, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
if in.Affinity != nil {
in, out := &in.Affinity, &out.Affinity
*out = new(v1.Affinity)
(*in).DeepCopyInto(*out)
}
if in.Tolerations != nil {
in, out := &in.Tolerations, &out.Tolerations
*out = make([]v1.Toleration, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ACMEChallengeSolverHTTP01IngressPodSpec.
func (in *ACMEChallengeSolverHTTP01IngressPodSpec) DeepCopy() *ACMEChallengeSolverHTTP01IngressPodSpec {
if in == nil {
return nil
}
out := new(ACMEChallengeSolverHTTP01IngressPodSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ACMEChallengeSolverHTTP01IngressPodTemplate) DeepCopyInto(out *ACMEChallengeSolverHTTP01IngressPodTemplate) {
*out = *in
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
in.PodSpec.DeepCopyInto(&out.PodSpec)
in.Spec.DeepCopyInto(&out.Spec)
return
}
@ -731,7 +767,7 @@ func (in *CertificateRequestSpec) DeepCopyInto(out *CertificateRequestSpec) {
*out = *in
if in.Duration != nil {
in, out := &in.Duration, &out.Duration
*out = new(v1.Duration)
*out = new(metav1.Duration)
(*in).DeepCopyInto(*out)
}
out.IssuerRef = in.IssuerRef
@ -796,12 +832,12 @@ func (in *CertificateSpec) DeepCopyInto(out *CertificateSpec) {
}
if in.Duration != nil {
in, out := &in.Duration, &out.Duration
*out = new(v1.Duration)
*out = new(metav1.Duration)
(*in).DeepCopyInto(*out)
}
if in.RenewBefore != nil {
in, out := &in.RenewBefore, &out.RenewBefore
*out = new(v1.Duration)
*out = new(metav1.Duration)
(*in).DeepCopyInto(*out)
}
if in.DNSNames != nil {

View File

@ -156,13 +156,6 @@ func ValidateACMEIssuerChallengeSolverHTTP01IngressPodTemplateConfig(podTempl *v
el = append(el, field.Invalid(fldPath.Child("metadata"), "", "only labels and annotations may be set on podTemplate metadata"))
}
cpyPodTempl.NodeSelector = nil
cpyPodTempl.Tolerations = nil
if !reflect.DeepEqual(cpyPodTempl.PodSpec, corev1.PodSpec{}) {
el = append(el, field.Invalid(fldPath.Child("spec"), "", "only nodeSelector and tolerations may be set on podTemplate spec"))
}
return el
}

View File

@ -266,7 +266,7 @@ func TestValidateACMEIssuerConfig(t *testing.T) {
HTTP01: &v1alpha1.ACMEChallengeSolverHTTP01{
Ingress: &v1alpha1.ACMEChallengeSolverHTTP01Ingress{
PodTemplate: &v1alpha1.ACMEChallengeSolverHTTP01IngressPodTemplate{
PodSpec: corev1.PodSpec{
Spec: v1alpha1.ACMEChallengeSolverHTTP01IngressPodSpec{
NodeSelector: map[string]string{
"valid_to_contain": "nodeSelector",
},
@ -288,33 +288,6 @@ func TestValidateACMEIssuerConfig(t *testing.T) {
},
},
},
"acme issue with invalid pod template PodSpec attributes": {
spec: &v1alpha1.ACMEIssuer{
Email: "valid-email",
Server: "valid-server",
PrivateKey: validSecretKeyRef,
Solvers: []v1alpha1.ACMEChallengeSolver{
{
HTTP01: &v1alpha1.ACMEChallengeSolverHTTP01{
Ingress: &v1alpha1.ACMEChallengeSolverHTTP01Ingress{
PodTemplate: &v1alpha1.ACMEChallengeSolverHTTP01IngressPodTemplate{
PodSpec: corev1.PodSpec{
NodeSelector: map[string]string{
"valid_to_contain": "nodeSelector",
},
NodeName: "unable-to-change-nodeName",
},
},
},
},
},
},
},
errs: []*field.Error{
field.Invalid(fldPath.Child("solver", "http01", "ingress", "podTemplate", "spec"),
"", "only nodeSelector and tolerations may be set on podTemplate spec"),
},
},
"acme issue with valid pod template ObjectMeta and PodSpec attributes": {
spec: &v1alpha1.ACMEIssuer{
Email: "valid-email",
@ -330,7 +303,7 @@ func TestValidateACMEIssuerConfig(t *testing.T) {
"valid_to_contain": "labels",
},
},
PodSpec: corev1.PodSpec{
Spec: v1alpha1.ACMEChallengeSolverHTTP01IngressPodSpec{
NodeSelector: map[string]string{
"valid_to_contain": "nodeSelector",
},

View File

@ -228,7 +228,7 @@ func (s *Solver) mergePodObjectMetaWithPodTemplate(pod *corev1.Pod, podTempl *v1
pod.Spec.NodeSelector = make(map[string]string)
}
for k, v := range podTempl.NodeSelector {
for k, v := range podTempl.Spec.NodeSelector {
pod.Spec.NodeSelector[k] = v
}
@ -236,9 +236,13 @@ func (s *Solver) mergePodObjectMetaWithPodTemplate(pod *corev1.Pod, podTempl *v1
pod.Spec.Tolerations = []corev1.Toleration{}
}
for _, t := range podTempl.Tolerations {
for _, t := range podTempl.Spec.Tolerations {
pod.Spec.Tolerations = append(pod.Spec.Tolerations, t)
}
if podTempl.Spec.Affinity != nil {
pod.Spec.Affinity = podTempl.Spec.Affinity
}
return pod
}