-
Notifications
You must be signed in to change notification settings - Fork 19
Add CoreDNS rewrite support for external services. #656
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
5211ffd
083a46c
fdcd150
b287952
52ad6af
bb9b316
e7dad17
6e337cf
92c266a
8d7cda9
d6b94fa
b31c0a3
bafabdc
cbe72e2
1e251a5
f73b4b9
805194c
40d67ce
f0cb126
caf3536
4177a82
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,178 @@ | ||
| // Copyright (c) The ClusterLink Authors. | ||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||
| // you may not use this file except in compliance with the License. | ||
| // You may obtain a copy of the License at | ||
| // | ||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||
| // | ||
| // Unless required by applicable law or agreed to in writing, software | ||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| // See the License for the specific language governing permissions and | ||
| // limitations under the License. | ||
|
|
||
| package control | ||
|
|
||
| import ( | ||
| "context" | ||
| "errors" | ||
| "fmt" | ||
| "strings" | ||
| "time" | ||
|
|
||
| "github.com/sirupsen/logrus" | ||
| appsv1 "k8s.io/api/apps/v1" | ||
| v1 "k8s.io/api/core/v1" | ||
| k8serrors "k8s.io/apimachinery/pkg/api/errors" | ||
| metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
| "k8s.io/apimachinery/pkg/types" | ||
| "sigs.k8s.io/controller-runtime/pkg/client" | ||
| ) | ||
|
|
||
| // Restart coredns deployment. | ||
| func restartCoreDNS(ctx context.Context, mClient client.Client, logger *logrus.Entry) error { | ||
| logger.Infof("restarting coredns deployment") | ||
| patch := []byte( | ||
| fmt.Sprintf( | ||
| `{"spec": {"template": {"metadata": {"annotations":{"kubectl.kubernetes.io/restartedAt": %q}}}}}`, | ||
| time.Now().String(), | ||
| ), | ||
| ) | ||
|
|
||
| return mClient.Patch(ctx, &appsv1.Deployment{ | ||
| ObjectMeta: metav1.ObjectMeta{ | ||
| Namespace: "kube-system", | ||
| Name: "coredns", | ||
| }, | ||
| }, client.RawPatch(types.StrategicMergePatchType, patch)) | ||
| } | ||
|
|
||
| // Add coredns rewrite for a given external dns service. | ||
| func addCoreDNSRewrite(ctx context.Context, mClient client.Client, logger *logrus.Entry, name *types.NamespacedName, | ||
| alias string, | ||
| ) error { | ||
| corednsName := types.NamespacedName{ | ||
| Name: "coredns", | ||
| Namespace: "kube-system", | ||
| } | ||
| var cm v1.ConfigMap | ||
|
|
||
| if err := mClient.Get(ctx, corednsName, &cm); err != nil { | ||
| if k8serrors.IsNotFound(err) { | ||
| logger.Warnf("coredns configmap not found.") | ||
| return nil | ||
| } | ||
| return err | ||
| } | ||
| if _, ok := cm.Data["Corefile"]; !ok { | ||
| return errors.New("coredns configmap['Corefile'] not found") | ||
| } | ||
|
|
||
| data := cm.Data["Corefile"] | ||
| // remove trailing end-of-line | ||
| data = strings.TrimSuffix(data, "\n") | ||
| // break into lines | ||
| lines := strings.Split(data, "\n") | ||
| serviceFqdn := fmt.Sprintf("%s.%s.svc.cluster.local", name.Name, name.Namespace) | ||
|
|
||
| coreFileUpdated := false | ||
| rewriteLine := "" | ||
| for i, line := range lines { | ||
| if strings.Contains(line, serviceFqdn) { | ||
| // matched line already exists | ||
| break | ||
| } | ||
| // ready marker is reached - matched line not found, append it here | ||
| if strings.Contains(line, " ready") { | ||
| if strings.HasPrefix(alias, "*.") { // wildcard DNS | ||
| alias = strings.TrimPrefix(alias, "*") | ||
| alias = strings.ReplaceAll(alias, ".", "\\.") | ||
| alias = "(.*)" + alias | ||
|
|
||
| rewriteLine = fmt.Sprintf(" rewrite name regex %s %s answer auto", alias, serviceFqdn) | ||
| } else { | ||
| rewriteLine = fmt.Sprintf(" rewrite name %s %s", alias, serviceFqdn) | ||
| } | ||
| // add matched line | ||
| lines = append(lines[:i+1], lines[i:]...) | ||
| lines[i] = rewriteLine | ||
| coreFileUpdated = true | ||
| break | ||
| } | ||
| } | ||
|
|
||
| if coreFileUpdated { | ||
| // update configmap and restart the pods | ||
| var newLines string | ||
| for _, line := range lines { | ||
| // return back EOL | ||
| newLines += (line + "\n") | ||
| } | ||
| cm.Data["Corefile"] = newLines | ||
| if err := mClient.Update(ctx, &cm); err != nil { | ||
| return err | ||
| } | ||
|
|
||
| if err := restartCoreDNS(ctx, mClient, logger); err != nil { | ||
| return err | ||
| } | ||
| } | ||
|
|
||
| return nil | ||
| } | ||
|
|
||
| // Remove coredns rewrite for a given external dns service. | ||
| func removeCoreDNSRewrite(ctx context.Context, mClient client.Client, logger *logrus.Entry, name *types.NamespacedName) error { | ||
| corednsName := types.NamespacedName{ | ||
| Name: "coredns", | ||
| Namespace: "kube-system", | ||
| } | ||
| var cm v1.ConfigMap | ||
|
|
||
| if err := mClient.Get(ctx, corednsName, &cm); err != nil { | ||
| if k8serrors.IsNotFound(err) { | ||
| logger.Warnf("coredns configmap not found.") | ||
| return nil | ||
| } | ||
| return err | ||
| } | ||
| if _, ok := cm.Data["Corefile"]; !ok { | ||
| return errors.New("coredns configmap['Corefile'] not found") | ||
| } | ||
|
|
||
| data := cm.Data["Corefile"] | ||
| // remove trailing end-of-line | ||
| dataEol := strings.TrimSuffix(data, "\n") | ||
| // break into lines | ||
| lines := strings.Split(dataEol, "\n") | ||
| serviceFqdn := fmt.Sprintf("%s.%s.svc.cluster.local", name.Name, name.Namespace) | ||
|
|
||
| coreFileUpdated := false | ||
| for i, line := range lines { | ||
| if strings.Contains(line, serviceFqdn) { | ||
| // remove matched line | ||
| lines = append(lines[:i], lines[i+1:]...) | ||
| coreFileUpdated = true | ||
| break | ||
| } | ||
| } | ||
|
|
||
| if coreFileUpdated { | ||
| // update configmap and restart the pods | ||
| var newLines string | ||
| for _, line := range lines { | ||
| // return back EOL | ||
| newLines += (line + "\n") | ||
| } | ||
| cm.Data["Corefile"] = newLines | ||
| if err := mClient.Update(ctx, &cm); err != nil { | ||
| return err | ||
| } | ||
|
|
||
| if err := restartCoreDNS(ctx, mClient, logger); err != nil { | ||
| return err | ||
| } | ||
| } | ||
|
|
||
| return nil | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -253,31 +253,39 @@ func (m *Manager) addImport(ctx context.Context, imp *v1alpha1.Import) (err erro | |
| return err | ||
| } | ||
|
|
||
| if imp.Namespace == m.namespace { | ||
| return nil | ||
| } | ||
| if imp.Namespace != m.namespace { | ||
| userService := &v1.Service{ | ||
| ObjectMeta: metav1.ObjectMeta{ | ||
| Name: imp.Name, | ||
| Namespace: imp.Namespace, | ||
| Labels: make(map[string]string), | ||
| }, | ||
| Spec: v1.ServiceSpec{ | ||
| ExternalName: fmt.Sprintf("%s.%s.svc.cluster.local", serviceName, m.namespace), | ||
| Type: v1.ServiceTypeExternalName, | ||
| }, | ||
| } | ||
|
|
||
| userService := &v1.Service{ | ||
| ObjectMeta: metav1.ObjectMeta{ | ||
| Name: imp.Name, | ||
| Namespace: imp.Namespace, | ||
| Labels: make(map[string]string), | ||
| }, | ||
| Spec: v1.ServiceSpec{ | ||
| ExternalName: fmt.Sprintf("%s.%s.svc.cluster.local", serviceName, m.namespace), | ||
| Type: v1.ServiceTypeExternalName, | ||
| }, | ||
| if err := m.addImportService(ctx, imp, userService); err != nil { | ||
| return err | ||
| } | ||
| } | ||
|
|
||
| return m.addImportService(ctx, imp, userService) | ||
| if imp.Spec.Alias != "" { | ||
| if err := addCoreDNSRewrite(ctx, m.client, m.logger, &importName, imp.Spec.Alias); err != nil { | ||
| m.logger.Errorf("failed to configure CoreDNS: %v.", err) | ||
| return err | ||
| } | ||
| } | ||
| return nil | ||
| } | ||
|
|
||
| // deleteImport removes the listening socket of a previously imported service. | ||
| func (m *Manager) deleteImport(ctx context.Context, name types.NamespacedName) error { | ||
| m.logger.Infof("Deleting import '%s/%s'.", name.Namespace, name.Name) | ||
|
|
||
| // delete user service | ||
| errs := make([]error, 3) | ||
| errs := make([]error, 4) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: I realize it is not part of the new code, but I wonder if using append won't be a cleaner solution instead of assigning specific array entries. Unless, of course, there is a reliance on the specific order even when there are nil errors in the array. |
||
| errs[0] = m.deleteImportService(ctx, name, name) | ||
|
|
||
| if name.Namespace != m.namespace { | ||
|
|
@@ -294,6 +302,8 @@ func (m *Manager) deleteImport(ctx context.Context, name types.NamespacedName) e | |
|
|
||
| m.ports.Release(name) | ||
|
|
||
| errs[3] = removeCoreDNSRewrite(ctx, m.client, m.logger, &name) | ||
|
|
||
| return errors.Join(errs...) | ||
| } | ||
|
|
||
|
|
@@ -889,7 +899,6 @@ func generateJWKSecret() ([]byte, error) { | |
| Type: "RSA PRIVATE KEY", | ||
| Bytes: x509.MarshalPKCS1PrivateKey(rsaKey), | ||
| }) | ||
|
|
||
| if err != nil { | ||
| return nil, fmt.Errorf("cannot encode JWK key: %w", err) | ||
| } | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.