Assigns solver pod to exposed template with defaults, includes
validation Signed-off-by: JoshVanL <vleeuwenjoshua@gmail.com>
This commit is contained in:
parent
0a7a181808
commit
f2ba4d9f20
@ -1394,6 +1394,10 @@ Appears In:
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody><tr>
|
||||
<td><code>PodTemplate</code><br /> <em>PodTemplate</em></td>
|
||||
<td>Optional template for configure the solver pods. Not all pod template options are valid (e.g. name)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>serviceType</code><br /> <em>string</em></td>
|
||||
<td>Optional service type for Kubernetes solver service</td>
|
||||
</tr>
|
||||
|
||||
@ -325,6 +325,11 @@ type ACMEIssuerHTTP01Config struct {
|
||||
// Optional service type for Kubernetes solver service
|
||||
// +optional
|
||||
ServiceType corev1.ServiceType `json:"serviceType,omitempty"`
|
||||
|
||||
// Optional template for configure the solver pods. Not all pod template
|
||||
// options are valid (e.g. name)
|
||||
// +optional
|
||||
PodTemplate corev1.PodTemplate `json"podTemplate,omitempty"`
|
||||
}
|
||||
|
||||
// ACMEIssuerDNS01Config is a structure containing the ACME DNS configuration
|
||||
|
||||
@ -197,7 +197,7 @@ func (in *ACMEIssuer) DeepCopyInto(out *ACMEIssuer) {
|
||||
if in.HTTP01 != nil {
|
||||
in, out := &in.HTTP01, &out.HTTP01
|
||||
*out = new(ACMEIssuerHTTP01Config)
|
||||
**out = **in
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.DNS01 != nil {
|
||||
in, out := &in.DNS01, &out.DNS01
|
||||
@ -463,6 +463,7 @@ func (in *ACMEIssuerDNS01ProviderWebhook) DeepCopy() *ACMEIssuerDNS01ProviderWeb
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ACMEIssuerHTTP01Config) DeepCopyInto(out *ACMEIssuerHTTP01Config) {
|
||||
*out = *in
|
||||
in.PodTemplate.DeepCopyInto(&out.PodTemplate)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@ -169,6 +169,24 @@ func ValidateACMEIssuerHTTP01Config(iss *v1alpha1.ACMEIssuerHTTP01Config, fldPat
|
||||
}
|
||||
}
|
||||
|
||||
// Validate incoming solver pod template
|
||||
if len(iss.PodTemplate.Name) > 0 {
|
||||
el = append(el, field.Invalid(fldPath.Child("podTemplate"), iss.PodTemplate, fmt.Sprintf("name cannot be set for solver pod template, got %s",
|
||||
iss.PodTemplate.Name)))
|
||||
}
|
||||
if len(iss.PodTemplate.GenerateName) > 0 {
|
||||
el = append(el, field.Invalid(fldPath.Child("podTemplate"), iss.PodTemplate, fmt.Sprintf("generateName cannot be set for solver pod template, got %s",
|
||||
iss.PodTemplate.GenerateName)))
|
||||
}
|
||||
if len(iss.PodTemplate.OwnerReferences) > 0 {
|
||||
var names []string
|
||||
for _, o := range iss.PodTemplate.OwnerReferences {
|
||||
names = append(names, o.Name)
|
||||
}
|
||||
el = append(el, field.Invalid(fldPath.Child("podTemplate"), iss.PodTemplate, fmt.Sprintf("owner references cannot be set for solver pod template, got %s",
|
||||
names)))
|
||||
}
|
||||
|
||||
return el
|
||||
}
|
||||
|
||||
|
||||
@ -112,7 +112,7 @@ func httpDomainCfgForChallenge(issuer v1alpha1.GenericIssuer, ch *v1alpha1.Chall
|
||||
func (s *Solver) Present(ctx context.Context, issuer v1alpha1.GenericIssuer, ch *v1alpha1.Challenge) error {
|
||||
ctx = http01LogCtx(ctx)
|
||||
|
||||
_, podErr := s.ensurePod(ctx, ch)
|
||||
_, podErr := s.ensurePod(ctx, issuer, ch)
|
||||
svc, svcErr := s.ensureService(ctx, issuer, ch)
|
||||
if svcErr != nil {
|
||||
return utilerrors.NewAggregate([]error{podErr, svcErr})
|
||||
|
||||
@ -46,7 +46,7 @@ func podLabels(ch *v1alpha1.Challenge) map[string]string {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Solver) ensurePod(ctx context.Context, ch *v1alpha1.Challenge) (*corev1.Pod, error) {
|
||||
func (s *Solver) ensurePod(ctx context.Context, issuer v1alpha1.GenericIssuer, ch *v1alpha1.Challenge) (*corev1.Pod, error) {
|
||||
log := logf.FromContext(ctx).WithName("ensurePod")
|
||||
|
||||
log.V(logf.DebugLevel).Info("checking for existing HTTP01 solver pods")
|
||||
@ -68,7 +68,7 @@ func (s *Solver) ensurePod(ctx context.Context, ch *v1alpha1.Challenge) (*corev1
|
||||
}
|
||||
|
||||
log.Info("creating HTTP01 challenge solver pod")
|
||||
return s.createPod(ch)
|
||||
return s.createPod(issuer, ch)
|
||||
}
|
||||
|
||||
// getPodsForChallenge returns a list of pods that were created to solve
|
||||
@ -130,15 +130,21 @@ func (s *Solver) cleanupPods(ctx context.Context, ch *v1alpha1.Challenge) error
|
||||
|
||||
// createPod will create a challenge solving pod for the given certificate,
|
||||
// domain, token and key.
|
||||
func (s *Solver) createPod(ch *v1alpha1.Challenge) (*corev1.Pod, error) {
|
||||
return s.Client.CoreV1().Pods(ch.Namespace).Create(s.buildPod(ch))
|
||||
func (s *Solver) createPod(issuer v1alpha1.GenericIssuer, ch *v1alpha1.Challenge) (*corev1.Pod, error) {
|
||||
pod, err := s.buildPod(issuer, ch)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return s.Client.CoreV1().Pods(ch.Namespace).Create(pod)
|
||||
}
|
||||
|
||||
// buildPod will build a challenge solving pod for the given certificate,
|
||||
// domain, token and key. It will not create it in the API server
|
||||
func (s *Solver) buildPod(ch *v1alpha1.Challenge) *corev1.Pod {
|
||||
func (s *Solver) buildPod(issuer v1alpha1.GenericIssuer, ch *v1alpha1.Challenge) (*corev1.Pod, error) {
|
||||
podLabels := podLabels(ch)
|
||||
return &corev1.Pod{
|
||||
|
||||
pod := &corev1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
GenerateName: "cm-acme-http-solver-",
|
||||
Namespace: ch.Namespace,
|
||||
@ -183,4 +189,40 @@ func (s *Solver) buildPod(ch *v1alpha1.Challenge) *corev1.Pod {
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// Override defaults if they have changed in the pod template.
|
||||
pod = s.mergePodWithPodTemplate(pod,
|
||||
issuer.GetSpec().ACME.HTTP01.PodTemplate.DeepCopy())
|
||||
|
||||
return pod, nil
|
||||
}
|
||||
|
||||
func (s *Solver) mergePodWithPodTemplate(podDefault *corev1.Pod, podTempl *corev1.PodTemplate) *corev1.Pod {
|
||||
mergedPod := podDefault.DeepCopy()
|
||||
|
||||
if len(podTempl.Namespace) > 0 {
|
||||
mergedPod.Namespace = podTempl.Namespace
|
||||
}
|
||||
|
||||
if len(podTempl.Annotations) > 0 {
|
||||
mergedPod.Annotations = podTempl.Annotations
|
||||
}
|
||||
|
||||
if len(podTempl.Labels) > 0 {
|
||||
mergedPod.Labels = podTempl.Labels
|
||||
}
|
||||
|
||||
// Set merged spec to be equal to the new template
|
||||
mergedPod.Spec = podTempl.Template.Spec
|
||||
|
||||
// These are the only two specs set by default. If they exist in the
|
||||
// template, take the template.
|
||||
if len(podTempl.Template.Spec.RestartPolicy) > 0 {
|
||||
mergedPod.Spec.RestartPolicy = podDefault.Spec.RestartPolicy
|
||||
}
|
||||
if len(podTempl.Template.Spec.Containers) == 0 {
|
||||
mergedPod.Spec.Containers = podDefault.Spec.Containers
|
||||
}
|
||||
|
||||
return mergedPod
|
||||
}
|
||||
|
||||
@ -18,15 +18,18 @@ package http
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
coretesting "k8s.io/client-go/testing"
|
||||
|
||||
"github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha1"
|
||||
"github.com/jetstack/cert-manager/test/util/generate"
|
||||
)
|
||||
|
||||
func TestEnsurePod(t *testing.T) {
|
||||
@ -44,7 +47,7 @@ func TestEnsurePod(t *testing.T) {
|
||||
},
|
||||
},
|
||||
PreFn: func(t *testing.T, s *solverFixture) {
|
||||
ing, err := s.Solver.createPod(s.Challenge)
|
||||
ing, err := s.Solver.createPod(s.Issuer, s.Challenge)
|
||||
if err != nil {
|
||||
t.Errorf("error preparing test: %v", err)
|
||||
}
|
||||
@ -85,7 +88,12 @@ func TestEnsurePod(t *testing.T) {
|
||||
},
|
||||
},
|
||||
PreFn: func(t *testing.T, s *solverFixture) {
|
||||
expectedPod := s.Solver.buildPod(s.Challenge)
|
||||
expectedPod, err := s.Solver.buildPod(s.Issuer, s.Challenge)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error building pod: %s", err)
|
||||
t.Fail()
|
||||
return
|
||||
}
|
||||
// create a reactor that fails the test if a pod is created
|
||||
s.Builder.FakeKubeClient().PrependReactor("create", "pods", func(action coretesting.Action) (handled bool, ret runtime.Object, err error) {
|
||||
pod := action.(coretesting.CreateAction).GetObject().(*v1.Pod)
|
||||
@ -136,11 +144,11 @@ func TestEnsurePod(t *testing.T) {
|
||||
},
|
||||
Err: true,
|
||||
PreFn: func(t *testing.T, s *solverFixture) {
|
||||
_, err := s.Solver.createPod(s.Challenge)
|
||||
_, err := s.Solver.createPod(s.Issuer, s.Challenge)
|
||||
if err != nil {
|
||||
t.Errorf("error preparing test: %v", err)
|
||||
}
|
||||
_, err = s.Solver.createPod(s.Challenge)
|
||||
_, err = s.Solver.createPod(s.Issuer, s.Challenge)
|
||||
if err != nil {
|
||||
t.Errorf("error preparing test: %v", err)
|
||||
}
|
||||
@ -163,7 +171,93 @@ func TestEnsurePod(t *testing.T) {
|
||||
for name, test := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
test.Setup(t)
|
||||
resp, err := test.Solver.ensurePod(context.TODO(), test.Challenge)
|
||||
resp, err := test.Solver.ensurePod(context.TODO(), test.Issuer, test.Challenge)
|
||||
if err != nil && !test.Err {
|
||||
t.Errorf("Expected function to not error, but got: %v", err)
|
||||
}
|
||||
if err == nil && test.Err {
|
||||
t.Errorf("Expected function to get an error, but got: %v", err)
|
||||
}
|
||||
test.Finish(t, resp, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMergePodWithPodTemplate(t *testing.T) {
|
||||
const createdPodKey = "createdPod"
|
||||
tests := map[string]solverFixture{
|
||||
"should return one pod that matches": {
|
||||
Challenge: &v1alpha1.Challenge{
|
||||
Spec: v1alpha1.ChallengeSpec{
|
||||
DNSName: "example.com",
|
||||
Config: &v1alpha1.SolverConfig{
|
||||
HTTP01: &v1alpha1.HTTP01SolverConfig{},
|
||||
},
|
||||
},
|
||||
},
|
||||
//Issuer: &v1alpha1.Issuer{},
|
||||
PreFn: func(t *testing.T, s *solverFixture) {
|
||||
s.testResources[createdPodKey] = v1.PodTemplate{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: map[string]string{
|
||||
"this is": "a label",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
s.Builder.Sync()
|
||||
},
|
||||
Issuer: generate.Issuer(generate.IssuerConfig{
|
||||
Name: defaultTestIssuerName,
|
||||
Namespace: defaultTestNamespace,
|
||||
HTTP01: &v1alpha1.ACMEIssuerHTTP01Config{
|
||||
PodTemplate: v1.PodTemplate{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: map[string]string{
|
||||
"this is a": "label",
|
||||
},
|
||||
},
|
||||
Template: v1.PodTemplateSpec{
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Command: []string{"this is a command foo"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
CheckFn: func(t *testing.T, s *solverFixture, args ...interface{}) {
|
||||
//createdPod := s.testResources[createdPodKey].(*v1.PodTemplate)
|
||||
pod, err := s.Solver.buildPod(s.Issuer, s.Challenge)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("\n\n\n\n\n%s\n\n\n\n\n", pod)
|
||||
|
||||
//resp := args[0].([]*v1.Pod)
|
||||
//if len(resp) != 1 {
|
||||
// t.Errorf("expected one pod to be returned, but got %d", len(resp))
|
||||
// t.Fail()
|
||||
// return
|
||||
//}
|
||||
//if !reflect.DeepEqual(resp[0], createdPod) {
|
||||
// t.Errorf("Expected %v to equal %v", resp[0], createdPod)
|
||||
//}
|
||||
|
||||
return
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for name, test := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
test.Setup(t)
|
||||
resp, err := test.Solver.buildPod(test.Issuer, test.Challenge)
|
||||
if err != nil && !test.Err {
|
||||
t.Errorf("Expected function to not error, but got: %v", err)
|
||||
}
|
||||
@ -188,7 +282,7 @@ func TestGetPodsForCertificate(t *testing.T) {
|
||||
},
|
||||
},
|
||||
PreFn: func(t *testing.T, s *solverFixture) {
|
||||
ing, err := s.Solver.createPod(s.Challenge)
|
||||
ing, err := s.Solver.createPod(s.Issuer, s.Challenge)
|
||||
if err != nil {
|
||||
t.Errorf("error preparing test: %v", err)
|
||||
}
|
||||
@ -221,7 +315,7 @@ func TestGetPodsForCertificate(t *testing.T) {
|
||||
PreFn: func(t *testing.T, s *solverFixture) {
|
||||
differentChallenge := s.Challenge.DeepCopy()
|
||||
differentChallenge.Spec.DNSName = "notexample.com"
|
||||
_, err := s.Solver.createPod(differentChallenge)
|
||||
_, err := s.Solver.createPod(s.Issuer, differentChallenge)
|
||||
if err != nil {
|
||||
t.Errorf("error preparing test: %v", err)
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user