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:
David Bond 2026-06-11 14:48:48 +01:00 committed by GitHub
parent be44e66e99
commit 7fb6751ddd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 126 additions and 72 deletions

View File

@ -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

View File

@ -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

View File

@ -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
}

View File

@ -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",

View File

@ -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

View File

@ -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

View File

@ -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
}

View File

@ -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)

View File

@ -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.

View File

@ -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])) {

View File

@ -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)

View File

@ -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)