Repository: traefik/traefik
File: pkg/provider/configuration.go (Go)

Code before:
	defaultFuncMap := sprig.TxtFuncMap()
	defaultFuncMap["normalize"] = Normalize

	for k, fn := range funcMap {
		defaultFuncMap[k] = fn
	}

	return template.New("defaultRule").Funcs(defaultFuncMap).Parse(defaultRule)
}

// BuildTCPRouterConfiguration builds a router configuration.
func BuildTCPRouterConfiguration(ctx context.Context, configuration *dynamic.TCPConfiguration) {
	for routerName, router := range configuration.Routers {
		loggerRouter := log.FromContext(ctx).WithField(log.RouterName, routerName)
		if len(router.Rule) == 0 {
			delete(configuration.Routers, routerName)
			loggerRouter.Errorf("Empty rule")
			continue
		}

		if router.Service == "" {
			if len(configuration.Services) > 1 {
				delete(configuration.Routers, routerName)
				loggerRouter.
					Errorf("Router %s cannot be linked automatically with multiples Services : %q",
						routerName, reflect.ValueOf(configuration.Services).MapKeys())
				continue
			}

			for serviceName := range configuration.Services {
				router.Service = serviceName
			}
		}
	}
}

// BuildUDPRouterConfiguration builds a router configuration.
func BuildUDPRouterConfiguration(ctx context.Context, configuration *dynamic.UDPConfiguration) {
	for routerName, router := range configuration.Routers {
		loggerRouter := log.FromContext(ctx).WithField(log.RouterName, routerName)
		if router.Service != "" {
			continue
		}

		if len(configuration.Services) > 1 {
			delete(configuration.Routers, routerName)
			loggerRouter.
				Errorf("Router %s cannot be linked automatically with multiples Services : %q",
					routerName, reflect.ValueOf(configuration.Services).MapKeys())
			continue
		}

Review comment (suggestion):
@mloiseleur While using `reflect` here looks pretty handy, it is not common for us to use reflection in such simple cases. To be consistent with the codebase, I suggest creating the service names slice instead.

Code after:
func MakeDefaultRuleTemplate(defaultRule string, funcMap template.FuncMap) (*template.Template, error) {
	defaultFuncMap := sprig.TxtFuncMap()
	defaultFuncMap["normalize"] = Normalize

	for k, fn := range funcMap {
		defaultFuncMap[k] = fn
	}

	return template.New("defaultRule").Funcs(defaultFuncMap).Parse(defaultRule)
}

// BuildTCPRouterConfiguration builds a router configuration.
func BuildTCPRouterConfiguration(ctx context.Context, configuration *dynamic.TCPConfiguration) {
	for routerName, router := range configuration.Routers {
		loggerRouter := log.FromContext(ctx).WithField(log.RouterName, routerName)
		if len(router.Rule) == 0 {
			delete(configuration.Routers, routerName)
			loggerRouter.Errorf("Empty rule")
			continue
		}

		if router.Service == "" {
			if len(configuration.Services) > 1 {
				delete(configuration.Routers, routerName)
				loggerRouter.
					Errorf("Router %s cannot be linked automatically with multiple Services: %q", routerName, maps.Keys(configuration.Services))
				continue
			}

			for serviceName := range configuration.Services {
				router.Service = serviceName
			}
		}
	}
}

// BuildUDPRouterConfiguration builds a router configuration.
func BuildUDPRouterConfiguration(ctx context.Context, configuration *dynamic.UDPConfiguration) {
	for routerName, router := range configuration.Routers {
		loggerRouter := log.FromContext(ctx).WithField(log.RouterName, routerName)
		if router.Service != "" {
			continue
		}

		if len(configuration.Services) > 1 {
			delete(configuration.Routers, routerName)
			loggerRouter.
				Errorf("Router %s cannot be linked automatically with multiple Services: %q", routerName, maps.Keys(configuration.Services))
			continue
		}