mirror of
https://github.com/tailscale/tailscale.git
synced 2026-07-20 21:23:07 +08:00
cmd/k8s-operator: rework [unexpected] log lines (#20065)
* cmd/k8s-operator: rework [unexpected] log lines This commit modifies several places in the operator logs where we prepend `[unexpected]` to instead use an appropriate logging level. The `[unexpected]` prefix is intended to be used when the program violates some internal invariant (or for example, a database has become corrupted). Many of these cases were simply log lines that then fell back to a default value/behaviour. These have been releveled to warnings. Some of these log lines also seemed extraeneous as for the example of service reconcilers logging when there is no proxy group annotation. As far as I can tell we've never had any predicates for limiting the services reconciled to ones with that annotation, so they can just be removed to reduce log spam. Fixes: #cleanup Signed-off-by: David Bond <davidsbond93@gmail.com> * Update cmd/k8s-operator/egress-services-readiness.go Co-authored-by: BeckyPauley <64131207+BeckyPauley@users.noreply.github.com> Signed-off-by: David Bond <davidsbond@users.noreply.github.com> * Update cmd/k8s-operator/operator.go Co-authored-by: BeckyPauley <64131207+BeckyPauley@users.noreply.github.com> Signed-off-by: David Bond <davidsbond@users.noreply.github.com> --------- Signed-off-by: David Bond <davidsbond93@gmail.com> Signed-off-by: David Bond <davidsbond@users.noreply.github.com> Co-authored-by: BeckyPauley <64131207+BeckyPauley@users.noreply.github.com>
This commit is contained in:
parent
be44e66e99
commit
7fb6751ddd
@ -436,14 +436,16 @@ func exclusiveOwnerAnnotations(pg *tsapi.ProxyGroup, operatorID string, svc *tai
|
||||
}
|
||||
if svc == nil {
|
||||
c := ownerAnnotationValue{OwnerRefs: []OwnerRef{ref}}
|
||||
json, err := json.Marshal(c)
|
||||
data, err := json.Marshal(c)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("[unexpected] unable to marshal Tailscale Service's owner annotation contents: %w, please report this", err)
|
||||
return nil, fmt.Errorf("failed to marshal Tailscale Service's owner annotation contents: %w", err)
|
||||
}
|
||||
|
||||
return map[string]string{
|
||||
ownerAnnotation: string(json),
|
||||
ownerAnnotation: string(data),
|
||||
}, nil
|
||||
}
|
||||
|
||||
o, err := parseOwnerAnnotation(svc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -451,15 +453,19 @@ func exclusiveOwnerAnnotations(pg *tsapi.ProxyGroup, operatorID string, svc *tai
|
||||
if o == nil || len(o.OwnerRefs) == 0 {
|
||||
return nil, fmt.Errorf("Tailscale Service %s exists, but does not contain owner annotation with owner references; not proceeding as this is likely a resource created by something other than the Tailscale Kubernetes operator", svc.Name)
|
||||
}
|
||||
|
||||
if len(o.OwnerRefs) > 1 || o.OwnerRefs[0].OperatorID != operatorID {
|
||||
return nil, fmt.Errorf("Tailscale Service %s is already owned by other operator(s) and cannot be shared across multiple clusters; configure a difference Service name to continue", svc.Name)
|
||||
}
|
||||
|
||||
if o.OwnerRefs[0].Resource == nil {
|
||||
return nil, fmt.Errorf("Tailscale Service %s exists, but does not reference an owning resource; not proceeding as this is likely a Service already owned by an Ingress", svc.Name)
|
||||
}
|
||||
|
||||
if o.OwnerRefs[0].Resource.Kind != "ProxyGroup" || o.OwnerRefs[0].Resource.UID != string(pg.UID) {
|
||||
return nil, fmt.Errorf("Tailscale Service %s is already owned by another resource: %#v; configure a difference Service name to continue", svc.Name, o.OwnerRefs[0].Resource)
|
||||
}
|
||||
|
||||
if o.OwnerRefs[0].Resource.Name != pg.Name {
|
||||
// ProxyGroup name can be updated in place.
|
||||
o.OwnerRefs[0].Resource.Name = pg.Name
|
||||
|
||||
@ -22,6 +22,7 @@
|
||||
"k8s.io/utils/net"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
|
||||
operatorutils "tailscale.com/k8s-operator"
|
||||
tsapi "tailscale.com/k8s-operator/apis/v1alpha1"
|
||||
"tailscale.com/util/mak"
|
||||
@ -281,19 +282,26 @@ func (dnsRR *dnsRecordsReconciler) fqdnForDNSRecord(ctx context.Context, proxySv
|
||||
if err := dnsRR.Get(ctx, parentName, ing); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if len(ing.Status.LoadBalancer.Ingress) == 0 {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
return ing.Status.LoadBalancer.Ingress[0].Hostname, nil
|
||||
}
|
||||
|
||||
if isManagedByType(proxySvc, serviceTypeSvc) {
|
||||
svc := new(corev1.Service)
|
||||
if err := dnsRR.Get(ctx, parentName, svc); apierrors.IsNotFound(err) {
|
||||
logger.Infof("[unexpected] parent Service for egress proxy %s not found", proxySvc.Name)
|
||||
var svc corev1.Service
|
||||
|
||||
err := dnsRR.Get(ctx, parentName, &svc)
|
||||
switch {
|
||||
case apierrors.IsNotFound(err):
|
||||
logger.Warnf("parent Service for egress proxy %q not found", proxySvc.Name)
|
||||
return "", nil
|
||||
} else if err != nil {
|
||||
case err != nil:
|
||||
return "", err
|
||||
}
|
||||
|
||||
return svc.Annotations[AnnotationTailnetTargetFQDN], nil
|
||||
}
|
||||
return "", nil
|
||||
@ -303,28 +311,31 @@ func (dnsRR *dnsRecordsReconciler) fqdnForDNSRecord(ctx context.Context, proxySv
|
||||
// ConfigMap. At this point the in-cluster ts.net nameserver is expected to be
|
||||
// successfully created together with the ConfigMap.
|
||||
func (dnsRR *dnsRecordsReconciler) updateDNSConfig(ctx context.Context, update func(*operatorutils.Records)) error {
|
||||
cm := &corev1.ConfigMap{}
|
||||
err := dnsRR.Get(ctx, types.NamespacedName{Name: operatorutils.DNSRecordsCMName, Namespace: dnsRR.tsNamespace}, cm)
|
||||
if apierrors.IsNotFound(err) {
|
||||
dnsRR.logger.Info("[unexpected] dnsrecords ConfigMap not found in cluster. Not updating DNS records. Please open an issue and attach operator logs.")
|
||||
var cm corev1.ConfigMap
|
||||
err := dnsRR.Get(ctx, types.NamespacedName{Name: operatorutils.DNSRecordsCMName, Namespace: dnsRR.tsNamespace}, &cm)
|
||||
switch {
|
||||
case apierrors.IsNotFound(err):
|
||||
dnsRR.logger.Warn("dnsrecords ConfigMap not found in cluster. Not updating DNS records. Please open an issue and attach operator logs.")
|
||||
return nil
|
||||
case err != nil:
|
||||
return fmt.Errorf("failed to retrieve dnsrecords ConfigMap: %w", err)
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("error retrieving dnsrecords ConfigMap: %w", err)
|
||||
}
|
||||
|
||||
dnsRecords := operatorutils.Records{Version: operatorutils.Alpha1Version, IP4: map[string][]string{}}
|
||||
if cm.Data != nil && cm.Data[operatorutils.DNSRecordsCMKey] != "" {
|
||||
if err := json.Unmarshal([]byte(cm.Data[operatorutils.DNSRecordsCMKey]), &dnsRecords); err != nil {
|
||||
if err = json.Unmarshal([]byte(cm.Data[operatorutils.DNSRecordsCMKey]), &dnsRecords); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
update(&dnsRecords)
|
||||
dnsRecordsBs, err := json.Marshal(dnsRecords)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error marshalling DNS records: %w", err)
|
||||
}
|
||||
|
||||
mak.Set(&cm.Data, operatorutils.DNSRecordsCMKey, string(dnsRecordsBs))
|
||||
return dnsRR.Update(ctx, cm)
|
||||
return dnsRR.Update(ctx, &cm)
|
||||
}
|
||||
|
||||
// isSvcForFQDNEgressProxy returns true if the Service is a headless Service
|
||||
|
||||
@ -91,9 +91,10 @@ func (er *egressEpsReconciler) Reconcile(ctx context.Context, req reconcile.Requ
|
||||
lg.Debugf("No egress config found, likely because ProxyGroup has not been created")
|
||||
return res, nil
|
||||
}
|
||||
|
||||
cfg, ok := cfgs[tailnetSvc]
|
||||
if !ok {
|
||||
lg.Infof("[unexpected] configuration for tailnet service %s not found", tailnetSvc)
|
||||
lg.Warnf("configuration for tailnet service %q not found", tailnetSvc)
|
||||
return res, nil
|
||||
}
|
||||
|
||||
@ -130,11 +131,12 @@ func (er *egressEpsReconciler) Reconcile(ctx context.Context, req reconcile.Requ
|
||||
// run a cleanup for deleted Pods etc.
|
||||
eps.Endpoints = newEndpoints
|
||||
if !reflect.DeepEqual(eps, oldEps) {
|
||||
lg.Infof("Updating EndpointSlice to ensure traffic is routed to ready proxy Pods")
|
||||
if err := er.Update(ctx, eps); err != nil {
|
||||
lg.Info("Updating EndpointSlice to ensure traffic is routed to ready proxy Pods")
|
||||
if err = er.Update(ctx, eps); err != nil {
|
||||
return res, fmt.Errorf("error updating EndpointSlice: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
@ -156,59 +158,69 @@ func podIPv4(pod *corev1.Pod) (string, error) {
|
||||
// status written there to the desired service configuration.
|
||||
func (er *egressEpsReconciler) podIsReadyToRouteTraffic(ctx context.Context, pod corev1.Pod, cfg *egressservices.Config, tailnetSvcName string, lg *zap.SugaredLogger) (bool, error) {
|
||||
lg = lg.With("proxy_pod", pod.Name)
|
||||
lg.Debugf("checking whether proxy is ready to route to egress service")
|
||||
lg.Debug("checking whether proxy is ready to route to egress service")
|
||||
if !pod.DeletionTimestamp.IsZero() {
|
||||
lg.Debugf("proxy Pod is being deleted, ignore")
|
||||
lg.Debug("proxy Pod is being deleted, ignore")
|
||||
return false, nil
|
||||
}
|
||||
|
||||
podIP, err := podIPv4(&pod)
|
||||
if err != nil {
|
||||
switch {
|
||||
case err != nil:
|
||||
return false, fmt.Errorf("error determining Pod IP address: %v", err)
|
||||
}
|
||||
if podIP == "" {
|
||||
lg.Infof("[unexpected] Pod does not have an IPv4 address, and IPv6 is not currently supported")
|
||||
case podIP == "":
|
||||
lg.Warn("Pod does not have an IPv4 address, and IPv6 is not currently supported")
|
||||
return false, nil
|
||||
}
|
||||
|
||||
stateS := &corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: pod.Name,
|
||||
Namespace: pod.Namespace,
|
||||
},
|
||||
}
|
||||
|
||||
err = er.Get(ctx, client.ObjectKeyFromObject(stateS), stateS)
|
||||
if apierrors.IsNotFound(err) {
|
||||
lg.Debugf("proxy does not have a state Secret, waiting...")
|
||||
switch {
|
||||
case apierrors.IsNotFound(err):
|
||||
lg.Debug("proxy does not yet have a state Secret, waiting...")
|
||||
return false, nil
|
||||
case err != nil:
|
||||
return false, fmt.Errorf("error retrieving state Secret: %w", err)
|
||||
}
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("error getting state Secret: %w", err)
|
||||
}
|
||||
|
||||
svcStatusBS := stateS.Data[egressservices.KeyEgressServices]
|
||||
if len(svcStatusBS) == 0 {
|
||||
lg.Debugf("proxy's state Secret does not contain egress services status, waiting...")
|
||||
lg.Debug("proxy's state Secret does not contain egress services status, waiting...")
|
||||
return false, nil
|
||||
}
|
||||
|
||||
svcStatus := &egressservices.Status{}
|
||||
if err := json.Unmarshal(svcStatusBS, svcStatus); err != nil {
|
||||
if err = json.Unmarshal(svcStatusBS, svcStatus); err != nil {
|
||||
return false, fmt.Errorf("error unmarshalling egress service status: %w", err)
|
||||
}
|
||||
|
||||
if !strings.EqualFold(podIP, svcStatus.PodIPv4) {
|
||||
lg.Infof("proxy's egress service status is for Pod IP %s, current proxy's Pod IP %s, waiting for the proxy to reconfigure...", svcStatus.PodIPv4, podIP)
|
||||
lg.Infof("proxy's egress service status is for Pod IP %q, current proxy's Pod IP %q, waiting for the proxy to reconfigure...", svcStatus.PodIPv4, podIP)
|
||||
return false, nil
|
||||
}
|
||||
st, ok := (*svcStatus).Services[tailnetSvcName]
|
||||
|
||||
st, ok := svcStatus.Services[tailnetSvcName]
|
||||
if !ok {
|
||||
lg.Infof("proxy's state Secret does not have egress service status, waiting...")
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(cfg.TailnetTarget, st.TailnetTarget) {
|
||||
lg.Infof("proxy has configured egress service for tailnet target %v, current target is %v, waiting for proxy to reconfigure...", st.TailnetTarget, cfg.TailnetTarget)
|
||||
lg.Infof("proxy has configured egress service for tailnet target %q, current target is %q, waiting for proxy to reconfigure...", st.TailnetTarget, cfg.TailnetTarget)
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(cfg.Ports, st.Ports) {
|
||||
lg.Debugf("proxy has configured egress service for ports %#+v, wants ports %#+v, waiting for proxy to reconfigure", st.Ports, cfg.Ports)
|
||||
return false, nil
|
||||
}
|
||||
lg.Debugf("proxy is ready to route traffic to egress service")
|
||||
|
||||
lg.Debug("proxy is ready to route traffic to egress service")
|
||||
return true, nil
|
||||
}
|
||||
|
||||
@ -23,6 +23,7 @@
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
|
||||
tsapi "tailscale.com/k8s-operator/apis/v1alpha1"
|
||||
"tailscale.com/kube/kubetypes"
|
||||
"tailscale.com/tstime"
|
||||
@ -87,8 +88,9 @@ func (er *egressPodsReconciler) Reconcile(ctx context.Context, req reconcile.Req
|
||||
lg.Debugf("Pod is being deleted, do nothing")
|
||||
return res, nil
|
||||
}
|
||||
|
||||
if pod.Labels[LabelParentType] != proxyTypeProxyGroup {
|
||||
lg.Infof("[unexpected] reconciler called for a Pod that is not a ProxyGroup Pod")
|
||||
lg.Warn("reconciler called for a Pod that is not a ProxyGroup Pod")
|
||||
return res, nil
|
||||
}
|
||||
|
||||
@ -106,10 +108,12 @@ func (er *egressPodsReconciler) Reconcile(ctx context.Context, req reconcile.Req
|
||||
if err := er.Get(ctx, types.NamespacedName{Name: proxyGroupName}, pg); err != nil {
|
||||
return res, fmt.Errorf("error getting ProxyGroup %q: %w", proxyGroupName, err)
|
||||
}
|
||||
|
||||
if pg.Spec.Type != typeEgress {
|
||||
lg.Infof("[unexpected] reconciler called for %q ProxyGroup Pod", pg.Spec.Type)
|
||||
lg.Warnf("reconciler called for %q ProxyGroup Pod", pg.Spec.Type)
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// Get all ClusterIP Services for all egress targets exposed to cluster via this ProxyGroup.
|
||||
lbls := map[string]string{
|
||||
kubetypes.LabelManaged: "true",
|
||||
|
||||
@ -20,6 +20,7 @@
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
|
||||
tsoperator "tailscale.com/k8s-operator"
|
||||
tsapi "tailscale.com/k8s-operator/apis/v1alpha1"
|
||||
"tailscale.com/tstime"
|
||||
@ -127,11 +128,13 @@ func (esrr *egressSvcsReadinessReconciler) Reconcile(ctx context.Context, req re
|
||||
msg = err.Error()
|
||||
return res, err
|
||||
}
|
||||
|
||||
if pod == nil {
|
||||
lg.Warnf("[unexpected] ProxyGroup is ready, but replica %d was not found", i)
|
||||
lg.Warnf("ProxyGroup is ready, but replica %d was not found", i)
|
||||
reason, msg = reasonClusterResourcesNotReady, reasonClusterResourcesNotReady
|
||||
return res, nil
|
||||
}
|
||||
|
||||
lg.Debugf("looking at Pod with IPs %v", pod.Status.PodIPs)
|
||||
ready := false
|
||||
for _, ep := range eps.Endpoints {
|
||||
@ -166,9 +169,10 @@ func (esrr *egressSvcsReadinessReconciler) Reconcile(ctx context.Context, req re
|
||||
func endpointReadyForPod(ep *discoveryv1.Endpoint, pod *corev1.Pod, lg *zap.SugaredLogger) bool {
|
||||
podIP, err := podIPv4(pod)
|
||||
if err != nil {
|
||||
lg.Warnf("[unexpected] error retrieving Pod's IPv4 address: %v", err)
|
||||
lg.Warnf("error retrieving Pod's IPv4 address: %v", err)
|
||||
return false
|
||||
}
|
||||
|
||||
// Currently we only ever set a single address on and Endpoint and nothing else is meant to modify this.
|
||||
if len(ep.Addresses) != 1 {
|
||||
return false
|
||||
|
||||
@ -173,14 +173,14 @@ func (r *HAIngressReconciler) maybeProvision(ctx context.Context, hostname strin
|
||||
logger.Infof("error validating tailscale IngressClass: %v.", err)
|
||||
return false, nil
|
||||
}
|
||||
// Get and validate ProxyGroup readiness
|
||||
|
||||
// We only act on services that are annotated as using a proxy group.
|
||||
pgName := ing.Annotations[AnnotationProxyGroup]
|
||||
if pgName == "" {
|
||||
logger.Infof("[unexpected] no ProxyGroup annotation, skipping Tailscale Service provisioning")
|
||||
return false, nil
|
||||
}
|
||||
logger = logger.With("ProxyGroup", pgName)
|
||||
|
||||
logger = logger.With("ProxyGroup", pgName)
|
||||
if !tsoperator.ProxyGroupAvailable(pg) {
|
||||
logger.Infof("ProxyGroup is not (yet) ready")
|
||||
return false, nil
|
||||
@ -685,9 +685,10 @@ func (r *HAIngressReconciler) validateIngress(ctx context.Context, ing *networki
|
||||
// It is invalid to have multiple Ingress resources for the same Tailscale Service in one cluster.
|
||||
ingList := &networkingv1.IngressList{}
|
||||
if err := r.List(ctx, ingList); err != nil {
|
||||
errs = append(errs, fmt.Errorf("[unexpected] error listing Ingresses: %w", err))
|
||||
errs = append(errs, fmt.Errorf("failed to list ingresses: %w", err))
|
||||
return errors.Join(errs...)
|
||||
}
|
||||
|
||||
for _, i := range ingList.Items {
|
||||
if r.shouldExpose(&i) && hostnameForIngress(&i) == hostname && i.UID != ing.UID {
|
||||
errs = append(errs, fmt.Errorf("found duplicate Ingress %q for hostname %q - multiple Ingresses for the same hostname in the same cluster are not allowed", client.ObjectKeyFromObject(&i), hostname))
|
||||
@ -876,14 +877,16 @@ func ownerAnnotations(operatorID string, svc *tailscale.VIPService) (map[string]
|
||||
}
|
||||
if svc == nil {
|
||||
c := ownerAnnotationValue{OwnerRefs: []OwnerRef{ref}}
|
||||
json, err := json.Marshal(c)
|
||||
data, err := json.Marshal(c)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("[unexpected] unable to marshal Tailscale Service's owner annotation contents: %w, please report this", err)
|
||||
return nil, fmt.Errorf("failed to marshal Tailscale Service's owner annotation contents: %w", err)
|
||||
}
|
||||
|
||||
return map[string]string{
|
||||
ownerAnnotation: string(json),
|
||||
ownerAnnotation: string(data),
|
||||
}, nil
|
||||
}
|
||||
|
||||
o, err := parseOwnerAnnotation(svc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@ -1477,9 +1477,10 @@ func HAIngressesFromSecret(cl client.Client, logger *zap.SugaredLogger) handler.
|
||||
return func(ctx context.Context, o client.Object) []reconcile.Request {
|
||||
secret, ok := o.(*corev1.Secret)
|
||||
if !ok {
|
||||
logger.Infof("[unexpected] Secret handler triggered for an object that is not a Secret")
|
||||
logger.Warn("Secret handler triggered for an object that is not a Secret")
|
||||
return nil
|
||||
}
|
||||
|
||||
if isTLSSecret(secret) {
|
||||
return []reconcile.Request{
|
||||
{
|
||||
@ -1516,15 +1517,16 @@ func HAIngressesFromSecret(cl client.Client, logger *zap.SugaredLogger) handler.
|
||||
}
|
||||
}
|
||||
|
||||
// HAServiceFromSecret returns a handler that returns reconcile requests for
|
||||
// HAServicesFromSecret returns a handler that returns reconcile requests for
|
||||
// all HA Services that should be reconciled in response to a Secret event.
|
||||
func HAServicesFromSecret(cl client.Client, logger *zap.SugaredLogger) handler.MapFunc {
|
||||
return func(ctx context.Context, o client.Object) []reconcile.Request {
|
||||
secret, ok := o.(*corev1.Secret)
|
||||
if !ok {
|
||||
logger.Infof("[unexpected] Secret handler triggered for an object that is not a Secret")
|
||||
logger.Warn("Secret handler triggered for an object that is not a Secret")
|
||||
return nil
|
||||
}
|
||||
|
||||
if !isPGStateSecret(secret) {
|
||||
return nil
|
||||
}
|
||||
@ -1556,9 +1558,10 @@ func kubeAPIServerPGsFromSecret(cl client.Client, logger *zap.SugaredLogger) han
|
||||
return func(ctx context.Context, o client.Object) []reconcile.Request {
|
||||
secret, ok := o.(*corev1.Secret)
|
||||
if !ok {
|
||||
logger.Infof("[unexpected] Secret handler triggered for an object that is not a Secret")
|
||||
logger.Warn("Secret handler triggered for an object that is not a Secret")
|
||||
return nil
|
||||
}
|
||||
|
||||
if secret.ObjectMeta.Labels[kubetypes.LabelManaged] != "true" ||
|
||||
secret.ObjectMeta.Labels[LabelParentType] != "proxygroup" {
|
||||
return nil
|
||||
@ -1594,9 +1597,10 @@ func egressSvcsFromEgressProxyGroup(cl client.Client, logger *zap.SugaredLogger)
|
||||
return func(ctx context.Context, o client.Object) []reconcile.Request {
|
||||
pg, ok := o.(*tsapi.ProxyGroup)
|
||||
if !ok {
|
||||
logger.Infof("[unexpected] ProxyGroup handler triggered for an object that is not a ProxyGroup")
|
||||
logger.Warn("ProxyGroup handler triggered for an object that is not a ProxyGroup")
|
||||
return nil
|
||||
}
|
||||
|
||||
if pg.Spec.Type != tsapi.ProxyGroupTypeEgress {
|
||||
return nil
|
||||
}
|
||||
@ -1624,9 +1628,10 @@ func ingressesFromIngressProxyGroup(cl client.Client, logger *zap.SugaredLogger)
|
||||
return func(ctx context.Context, o client.Object) []reconcile.Request {
|
||||
pg, ok := o.(*tsapi.ProxyGroup)
|
||||
if !ok {
|
||||
logger.Infof("[unexpected] ProxyGroup handler triggered for an object that is not a ProxyGroup")
|
||||
logger.Warn("ProxyGroup handler triggered for an object that is not a ProxyGroup")
|
||||
return nil
|
||||
}
|
||||
|
||||
if pg.Spec.Type != tsapi.ProxyGroupTypeIngress {
|
||||
return nil
|
||||
}
|
||||
@ -1654,9 +1659,10 @@ func epsFromExternalNameService(cl client.Client, logger *zap.SugaredLogger, ns
|
||||
return func(ctx context.Context, o client.Object) []reconcile.Request {
|
||||
svc, ok := o.(*corev1.Service)
|
||||
if !ok {
|
||||
logger.Infof("[unexpected] Service handler triggered for an object that is not a Service")
|
||||
logger.Warn("Service handler triggered for an object that is not a Service")
|
||||
return nil
|
||||
}
|
||||
|
||||
if !isEgressSvcForProxyGroup(svc) {
|
||||
return nil
|
||||
}
|
||||
@ -1683,9 +1689,10 @@ func podsFromEgressEps(cl client.Client, logger *zap.SugaredLogger, ns string) h
|
||||
return func(ctx context.Context, o client.Object) []reconcile.Request {
|
||||
eps, ok := o.(*discoveryv1.EndpointSlice)
|
||||
if !ok {
|
||||
logger.Infof("[unexpected] EndpointSlice handler triggered for an object that is not a EndpointSlice")
|
||||
logger.Warn("EndpointSlice handler triggered for an object that is not a EndpointSlice")
|
||||
return nil
|
||||
}
|
||||
|
||||
if eps.Labels[labelProxyGroup] == "" {
|
||||
return nil
|
||||
}
|
||||
@ -1722,18 +1729,21 @@ func proxyClassesWithServiceMonitor(cl client.Client, logger *zap.SugaredLogger)
|
||||
return func(ctx context.Context, o client.Object) []reconcile.Request {
|
||||
crd, ok := o.(*apiextensionsv1.CustomResourceDefinition)
|
||||
if !ok {
|
||||
logger.Debugf("[unexpected] ServiceMonitor CRD handler received an object that is not a CustomResourceDefinition")
|
||||
logger.Warn("ServiceMonitor CRD handler received an object that is not a CustomResourceDefinition")
|
||||
return nil
|
||||
}
|
||||
|
||||
if crd.Name != serviceMonitorCRD {
|
||||
logger.Debugf("[unexpected] ServiceMonitor CRD handler received an unexpected CRD %q", crd.Name)
|
||||
logger.Warnf("ServiceMonitor CRD handler received an unexpected CRD %q", crd.Name)
|
||||
return nil
|
||||
}
|
||||
|
||||
pcl := &tsapi.ProxyClassList{}
|
||||
if err := cl.List(ctx, pcl); err != nil {
|
||||
logger.Debugf("[unexpected] error listing ProxyClasses: %v", err)
|
||||
logger.Errorf("failed to list ProxyClass resources: %v", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
reqs := make([]reconcile.Request, 0)
|
||||
for _, pc := range pcl.Items {
|
||||
if pc.Spec.Metrics != nil && pc.Spec.Metrics.ServiceMonitor != nil && pc.Spec.Metrics.ServiceMonitor.Enable {
|
||||
@ -1742,6 +1752,7 @@ func proxyClassesWithServiceMonitor(cl client.Client, logger *zap.SugaredLogger)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return reqs
|
||||
}
|
||||
}
|
||||
@ -1751,9 +1762,10 @@ func crdTransformer(log *zap.SugaredLogger) toolscache.TransformFunc {
|
||||
return func(o any) (any, error) {
|
||||
crd, ok := o.(*apiextensionsv1.CustomResourceDefinition)
|
||||
if !ok {
|
||||
log.Infof("[unexpected] CRD transformer called for a non-CRD type")
|
||||
log.Warn("CRD transformer called for a non-CRD type")
|
||||
return crd, nil
|
||||
}
|
||||
|
||||
crd.Spec = apiextensionsv1.CustomResourceDefinitionSpec{}
|
||||
return crd, nil
|
||||
}
|
||||
|
||||
@ -26,6 +26,7 @@
|
||||
"k8s.io/client-go/tools/record"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
|
||||
tsoperator "tailscale.com/k8s-operator"
|
||||
tsapi "tailscale.com/k8s-operator/apis/v1alpha1"
|
||||
"tailscale.com/tstime"
|
||||
@ -170,10 +171,11 @@ func (pcr *ProxyClassReconciler) validate(ctx context.Context, pc *tsapi.ProxyCl
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if pc.Spec.Metrics != nil && pc.Spec.Metrics.ServiceMonitor != nil && pc.Spec.Metrics.ServiceMonitor.Enable {
|
||||
found, err := hasServiceMonitorCRD(ctx, pcr.Client)
|
||||
if err != nil {
|
||||
pcr.logger.Infof("[unexpected]: error retrieving %q CRD: %v", serviceMonitorCRD, err)
|
||||
pcr.logger.Errorf("error retrieving %q CRD: %v", serviceMonitorCRD, err)
|
||||
// best effort validation - don't error out here
|
||||
} else if !found {
|
||||
msg := fmt.Sprintf("ProxyClass defines that a ServiceMonitor custom resource should be created, but %q CRD was not found", serviceMonitorCRD)
|
||||
|
||||
@ -19,6 +19,7 @@
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
tsapi "tailscale.com/k8s-operator/apis/v1alpha1"
|
||||
"tailscale.com/kube/egressservices"
|
||||
"tailscale.com/kube/ingressservices"
|
||||
@ -74,10 +75,10 @@ func pgStatefulSet(pg *tsapi.ProxyGroup, namespace, image, tsFirewallMode string
|
||||
}
|
||||
// Validate some base assumptions.
|
||||
if len(ss.Spec.Template.Spec.InitContainers) != 1 {
|
||||
return nil, fmt.Errorf("[unexpected] base proxy config had %d init containers instead of 1", len(ss.Spec.Template.Spec.InitContainers))
|
||||
return nil, fmt.Errorf("base proxy config had %d init containers instead of 1", len(ss.Spec.Template.Spec.InitContainers))
|
||||
}
|
||||
if len(ss.Spec.Template.Spec.Containers) != 1 {
|
||||
return nil, fmt.Errorf("[unexpected] base proxy config had %d containers instead of 1", len(ss.Spec.Template.Spec.Containers))
|
||||
return nil, fmt.Errorf("base proxy config had %d containers instead of 1", len(ss.Spec.Template.Spec.Containers))
|
||||
}
|
||||
|
||||
// StatefulSet config.
|
||||
|
||||
@ -783,7 +783,7 @@ func (r *tailscaleSTSReconciler) reconcileSTS(ctx context.Context, logger *zap.S
|
||||
// No need to error out if now or in future we end up in a
|
||||
// situation where app info cannot be determined for one of the
|
||||
// many proxy configurations that the operator can produce.
|
||||
logger.Error("[unexpected] unable to determine proxy type")
|
||||
logger.Error("unable to determine proxy type")
|
||||
} else {
|
||||
container.Env = append(container.Env, corev1.EnvVar{
|
||||
Name: "TS_INTERNAL_APP",
|
||||
@ -1321,7 +1321,7 @@ func proxyCapVer(sec *corev1.Secret, podUID string, log *zap.SugaredLogger) tail
|
||||
}
|
||||
capVer, err := strconv.Atoi(string(sec.Data[kubetypes.KeyCapVer]))
|
||||
if err != nil {
|
||||
log.Infof("[unexpected]: unexpected capability version in proxy's state Secret, expected an integer, got %q", string(sec.Data[kubetypes.KeyCapVer]))
|
||||
log.Warnf("unexpected capability version in proxy's state Secret, expected an integer, got %q", string(sec.Data[kubetypes.KeyCapVer]))
|
||||
return tailcfg.CapabilityVersion(-1)
|
||||
}
|
||||
if !strings.EqualFold(podUID, string(sec.Data[kubetypes.KeyPodUID])) {
|
||||
|
||||
@ -99,7 +99,6 @@ func (r *HAServiceReconciler) Reconcile(ctx context.Context, req reconcile.Reque
|
||||
|
||||
pgName := svc.Annotations[AnnotationProxyGroup]
|
||||
if pgName == "" {
|
||||
logger.Infof("[unexpected] no ProxyGroup annotation, skipping Tailscale Service provisioning")
|
||||
return res, nil
|
||||
}
|
||||
|
||||
@ -674,7 +673,7 @@ func (r *HAServiceReconciler) maybeUpdateAdvertiseServicesConfig(ctx context.Con
|
||||
case shouldBeAdvertised:
|
||||
replicaName, ok := strings.CutSuffix(secret.Name, "-config")
|
||||
if !ok {
|
||||
logger.Infof("[unexpected] unable to determine replica name from config Secret name %q, unable to determine if backend routing has been configured", secret.Name)
|
||||
logger.Warnf("unable to determine replica name from config Secret name %q, unable to determine if backend routing has been configured", secret.Name)
|
||||
return nil
|
||||
}
|
||||
ready, err := r.backendRoutesSetup(ctx, serviceName.String(), replicaName, cfg, logger)
|
||||
@ -825,7 +824,7 @@ func (r *HAServiceReconciler) validateService(ctx context.Context, svc *corev1.S
|
||||
}
|
||||
svcList := &corev1.ServiceList{}
|
||||
if err := r.List(ctx, svcList); err != nil {
|
||||
errs = append(errs, fmt.Errorf("[unexpected] error listing Services: %w", err))
|
||||
errs = append(errs, fmt.Errorf("error listing Services: %w", err))
|
||||
return errors.Join(errs...)
|
||||
}
|
||||
svcName := nameForService(svc)
|
||||
|
||||
@ -468,7 +468,7 @@ func retrieveClusterDomain(namespace string, logger *zap.SugaredLogger) string {
|
||||
if err != nil {
|
||||
// Vast majority of clusters use the cluster.local domain, so it
|
||||
// is probably better to fall back to that than error out.
|
||||
logger.Infof("[unexpected] error parsing /etc/resolv.conf to determine cluster domain, defaulting to 'cluster.local'.")
|
||||
logger.Warn("error parsing /etc/resolv.conf to determine cluster domain, defaulting to 'cluster.local'.")
|
||||
return defaultClusterDomain
|
||||
}
|
||||
return clusterDomainFromResolverConf(conf, namespace, logger)
|
||||
@ -480,17 +480,17 @@ func retrieveClusterDomain(namespace string, logger *zap.SugaredLogger) string {
|
||||
// If the domains don't match the expected structure or an error is encountered, it defaults to 'cluster.local' domain.
|
||||
func clusterDomainFromResolverConf(conf *resolvconffile.Config, namespace string, logger *zap.SugaredLogger) string {
|
||||
if len(conf.SearchDomains) < 3 {
|
||||
logger.Infof("[unexpected] resolver config contains only %d search domains, at least three expected.\nDefaulting cluster domain to 'cluster.local'.")
|
||||
logger.Warnf(" resolver config contains only %d search domains, at least three expected.\nDefaulting cluster domain to 'cluster.local'.", len(conf.SearchDomains))
|
||||
return defaultClusterDomain
|
||||
}
|
||||
first := conf.SearchDomains[0]
|
||||
if !strings.HasPrefix(string(first), namespace+".svc") {
|
||||
logger.Infof("[unexpected] first search domain in resolver config is %s; expected %s.\nDefaulting cluster domain to 'cluster.local'.", first, namespace+".svc.<cluster-domain>")
|
||||
logger.Warnf("first search domain in resolver config is %s; expected %s.\nDefaulting cluster domain to 'cluster.local'.", first, namespace+".svc.<cluster-domain>")
|
||||
return defaultClusterDomain
|
||||
}
|
||||
second := conf.SearchDomains[1]
|
||||
if !strings.HasPrefix(string(second), "svc") {
|
||||
logger.Infof("[unexpected] second search domain in resolver config is %s; expected 'svc.<cluster-domain>'.\nDefaulting cluster domain to 'cluster.local'.", second)
|
||||
logger.Warnf("second search domain in resolver config is %s; expected 'svc.<cluster-domain>'.\nDefaulting cluster domain to 'cluster.local'.", second)
|
||||
return defaultClusterDomain
|
||||
}
|
||||
// Trim the trailing dot for backwards compatibility purposes as the
|
||||
@ -499,7 +499,7 @@ func clusterDomainFromResolverConf(conf *resolvconffile.Config, namespace string
|
||||
probablyClusterDomain := strings.TrimPrefix(second.WithoutTrailingDot(), "svc.")
|
||||
third := conf.SearchDomains[2]
|
||||
if !strings.EqualFold(third.WithoutTrailingDot(), probablyClusterDomain) {
|
||||
logger.Infof("[unexpected] expected resolver config to contain serch domains <namespace>.svc.<cluster-domain>, svc.<cluster-domain>, <cluster-domain>; got %s %s %s\n. Defaulting cluster domain to 'cluster.local'.", first, second, third)
|
||||
logger.Warnf("expected resolver config to contain serch domains <namespace>.svc.<cluster-domain>, svc.<cluster-domain>, <cluster-domain>; got %s %s %s\n. Defaulting cluster domain to 'cluster.local'.", first, second, third)
|
||||
return defaultClusterDomain
|
||||
}
|
||||
logger.Infof("Cluster domain %q extracted from resolver config", probablyClusterDomain)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user