Compare commits
6 commits
0ae856a894
...
fbccb05e2e
Author | SHA1 | Date | |
---|---|---|---|
fbccb05e2e | |||
c50a80834c | |||
6caef548c1 | |||
a2b75bc832 | |||
7fd4476406 | |||
a9f3d0e96d |
4 changed files with 57 additions and 38 deletions
8
go.mod
8
go.mod
|
@ -3,11 +3,11 @@ module git.ar21.de/yolokube/go-traefik-certmanager
|
|||
go 1.23.4
|
||||
|
||||
require (
|
||||
github.com/alecthomas/kong v1.6.0
|
||||
github.com/alecthomas/kong v1.6.1
|
||||
github.com/cert-manager/cert-manager v1.16.2
|
||||
k8s.io/api v0.32.0
|
||||
k8s.io/apimachinery v0.32.0
|
||||
k8s.io/client-go v0.32.0
|
||||
k8s.io/api v0.32.1
|
||||
k8s.io/apimachinery v0.32.1
|
||||
k8s.io/client-go v0.32.1
|
||||
)
|
||||
|
||||
require (
|
||||
|
|
16
go.sum
16
go.sum
|
@ -1,7 +1,7 @@
|
|||
github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0=
|
||||
github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
|
||||
github.com/alecthomas/kong v1.6.0 h1:mwOzbdMR7uv2vul9J0FU3GYxE7ls/iX1ieMg5WIM6gE=
|
||||
github.com/alecthomas/kong v1.6.0/go.mod h1:p2vqieVMeTAnaC83txKtXe8FLke2X07aruPWXyMPQrU=
|
||||
github.com/alecthomas/kong v1.6.1 h1:/7bVimARU3uxPD0hbryPE8qWrS3Oz3kPQoxA/H2NKG8=
|
||||
github.com/alecthomas/kong v1.6.1/go.mod h1:p2vqieVMeTAnaC83txKtXe8FLke2X07aruPWXyMPQrU=
|
||||
github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc=
|
||||
github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
|
||||
github.com/cert-manager/cert-manager v1.16.2 h1:c9UU2E+8XWGruyvC/mdpc1wuLddtgmNr8foKdP7a8Jg=
|
||||
|
@ -122,14 +122,14 @@ gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
|||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
k8s.io/api v0.32.0 h1:OL9JpbvAU5ny9ga2fb24X8H6xQlVp+aJMFlgtQjR9CE=
|
||||
k8s.io/api v0.32.0/go.mod h1:4LEwHZEf6Q/cG96F3dqR965sYOfmPM7rq81BLgsE0p0=
|
||||
k8s.io/api v0.32.1 h1:f562zw9cy+GvXzXf0CKlVQ7yHJVYzLfL6JAS4kOAaOc=
|
||||
k8s.io/api v0.32.1/go.mod h1:/Yi/BqkuueW1BgpoePYBRdDYfjPF5sgTr5+YqDZra5k=
|
||||
k8s.io/apiextensions-apiserver v0.31.1 h1:L+hwULvXx+nvTYX/MKM3kKMZyei+UiSXQWciX/N6E40=
|
||||
k8s.io/apiextensions-apiserver v0.31.1/go.mod h1:tWMPR3sgW+jsl2xm9v7lAyRF1rYEK71i9G5dRtkknoQ=
|
||||
k8s.io/apimachinery v0.32.0 h1:cFSE7N3rmEEtv4ei5X6DaJPHHX0C+upp+v5lVPiEwpg=
|
||||
k8s.io/apimachinery v0.32.0/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE=
|
||||
k8s.io/client-go v0.32.0 h1:DimtMcnN/JIKZcrSrstiwvvZvLjG0aSxy8PxN8IChp8=
|
||||
k8s.io/client-go v0.32.0/go.mod h1:boDWvdM1Drk4NJj/VddSLnx59X3OPgwrOo0vGbtq9+8=
|
||||
k8s.io/apimachinery v0.32.1 h1:683ENpaCBjma4CYqsmZyhEzrGz6cjn1MY/X2jB2hkZs=
|
||||
k8s.io/apimachinery v0.32.1/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE=
|
||||
k8s.io/client-go v0.32.1 h1:otM0AxdhdBIaQh7l1Q0jQpmo7WOFIk5FFa4bg6YMdUU=
|
||||
k8s.io/client-go v0.32.1/go.mod h1:aTTKZY7MdxUaJ/KiUs8D+GssR9zJZi77ZqtzcGXIiDg=
|
||||
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
|
||||
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
|
||||
k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f h1:GA7//TjRY9yWGy1poLzYYJJ4JRdzg3+O6e8I+e+8T5Y=
|
||||
|
|
|
@ -77,7 +77,7 @@ func (c *certificateClient) Create(
|
|||
},
|
||||
}
|
||||
|
||||
obj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(cert)
|
||||
obj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&cert)
|
||||
if err != nil {
|
||||
return errors.Join(ErrCertificateToUnstructured, err)
|
||||
}
|
||||
|
@ -140,6 +140,7 @@ func extractHosts(routes []map[string]interface{}) []string {
|
|||
}
|
||||
|
||||
if match, ok = route["match"].(string); ok {
|
||||
match = strings.ReplaceAll(match, "`", "")
|
||||
hostMatches := re.FindAllStringSubmatch(match, -1)
|
||||
for _, match := range hostMatches {
|
||||
if len(match) > 1 {
|
||||
|
|
|
@ -51,26 +51,9 @@ func (i *ingressRouteClient) Watch(stopCh chan struct{}) {
|
|||
_, err := informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
|
||||
AddFunc: func(obj interface{}) {
|
||||
key, err := cache.MetaNamespaceKeyFunc(obj)
|
||||
if err != nil {
|
||||
return
|
||||
if err == nil {
|
||||
queue.Add(event{key: key, eventType: watch.Added})
|
||||
}
|
||||
|
||||
convObj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(obj)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
rawRoutes, found, err := unstructured.NestedSlice(convObj, "spec", "routes")
|
||||
if err != nil || !found {
|
||||
return
|
||||
}
|
||||
|
||||
routes, err := routeInterfaceToMapSlice(rawRoutes)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
queue.Add(event{key: key, eventType: watch.Added, routes: routes})
|
||||
},
|
||||
UpdateFunc: func(_, newObj interface{}) {
|
||||
key, err := cache.MetaNamespaceKeyFunc(newObj)
|
||||
|
@ -83,7 +66,7 @@ func (i *ingressRouteClient) Watch(stopCh chan struct{}) {
|
|||
return
|
||||
}
|
||||
|
||||
key, err := cache.DeletionHandlingMetaNamespaceKeyFunc(obj)
|
||||
key, err := cache.MetaNamespaceKeyFunc(obj)
|
||||
if err == nil {
|
||||
queue.Add(event{key: key, eventType: watch.Deleted})
|
||||
}
|
||||
|
@ -96,12 +79,12 @@ func (i *ingressRouteClient) Watch(stopCh chan struct{}) {
|
|||
go informer.Run(stopCh)
|
||||
|
||||
wait.Until(func() {
|
||||
for i.processNextItem(queue) {
|
||||
for i.processNextItem(queue, informer) {
|
||||
}
|
||||
}, time.Second, stopCh)
|
||||
}
|
||||
|
||||
func (i *ingressRouteClient) processNextItem(queue workqueue.TypedRateLimitingInterface[any]) bool {
|
||||
func (i *ingressRouteClient) processNextItem(queue workqueue.TypedRateLimitingInterface[any], informer cache.SharedInformer) bool {
|
||||
item, quit := queue.Get()
|
||||
if quit {
|
||||
return false
|
||||
|
@ -122,10 +105,44 @@ func (i *ingressRouteClient) processNextItem(queue workqueue.TypedRateLimitingIn
|
|||
return true
|
||||
}
|
||||
|
||||
obj, exists, err := informer.GetStore().GetByKey(event.key)
|
||||
if err != nil || !exists {
|
||||
log.Printf("Failed to retrieve object for key %s: %v", event.key, err)
|
||||
return true
|
||||
}
|
||||
|
||||
convObj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(obj)
|
||||
if err != nil {
|
||||
log.Printf("Failed to convert unstructured object for key %s: %v", event.key, err)
|
||||
return true
|
||||
}
|
||||
|
||||
rawRoutes, found, err := unstructured.NestedSlice(convObj, "spec", "routes")
|
||||
if err != nil || !found {
|
||||
log.Printf("No routes found for key %s", event.key)
|
||||
return true
|
||||
}
|
||||
|
||||
secretName, found, err := unstructured.NestedString(convObj, "spec", "tls", "secretName")
|
||||
if err != nil {
|
||||
log.Printf("Failed to scrape secret name for %s: %v", event.key, err)
|
||||
return true
|
||||
}
|
||||
if !found {
|
||||
log.Printf("No secret name found, using ingressroute name %s", name)
|
||||
secretName = name
|
||||
}
|
||||
|
||||
routes, err := routeInterfaceToMapSlice(rawRoutes)
|
||||
if err != nil {
|
||||
log.Printf("Failed to convert routes for key %s: %v", event.key, err)
|
||||
return true
|
||||
}
|
||||
|
||||
//nolint:exhaustive // ignore missing switch cases
|
||||
switch event.eventType {
|
||||
case watch.Added, watch.Modified:
|
||||
createErr := i.client.certmanager.Certificates.Create(context.Background(), namespace, name, event.routes)
|
||||
createErr := i.client.certmanager.Certificates.Create(context.Background(), namespace, secretName, routes)
|
||||
if createErr != nil {
|
||||
if errors.Is(createErr, certmanager.ErrCertificateAlreadyExist) {
|
||||
log.Printf("Certificate %s for %s already exists", secretName, event.key)
|
||||
|
@ -133,10 +150,12 @@ func (i *ingressRouteClient) processNextItem(queue workqueue.TypedRateLimitingIn
|
|||
log.Printf("Failed to create certificate %s: %v", event.key, createErr)
|
||||
}
|
||||
}
|
||||
log.Printf("Certificate %s for %s created", secretName, event.key)
|
||||
case watch.Deleted:
|
||||
if deleteErr := i.client.certmanager.Certificates.Delete(context.Background(), namespace, name); deleteErr != nil {
|
||||
if deleteErr := i.client.certmanager.Certificates.Delete(context.Background(), namespace, secretName); deleteErr != nil {
|
||||
log.Printf("Failed to delete certificate %s: %v", event.key, deleteErr)
|
||||
}
|
||||
log.Printf("Certificate %s for %s deleted", secretName, event.key)
|
||||
}
|
||||
|
||||
return true
|
||||
|
@ -145,7 +164,6 @@ func (i *ingressRouteClient) processNextItem(queue workqueue.TypedRateLimitingIn
|
|||
type event struct {
|
||||
key string
|
||||
eventType watch.EventType
|
||||
routes []map[string]interface{}
|
||||
}
|
||||
|
||||
func routeInterfaceToMapSlice(input []interface{}) ([]map[string]interface{}, error) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue