Skip to content

Commit

Permalink
Make the hostname assigned to tags configurable by Operators.
Browse files Browse the repository at this point in the history
This adds a `tagTemplate` to the `config-network` ConfigMap so that (similar to
`domainTemplate`) Operators may configure how hostnames are assigned to tags.

This change just makes it configurable, a subsequent change will change the default
value to `{{.Tag}}-{{.Name}}` to reduce the likelihood of naming collisions with
BYO-revision-names

Progress towards: #4206
  • Loading branch information
mattmoor committed Jun 7, 2019
1 parent a876674 commit 592e69f
Show file tree
Hide file tree
Showing 13 changed files with 205 additions and 81 deletions.
6 changes: 6 additions & 0 deletions config/config-network.yaml
Expand Up @@ -104,6 +104,12 @@ data:
# and you have an annotation {"sub":"foo"}, then the generated template would be {Name}-{Namespace}.foo.{Domain}
domainTemplate: "{{.Name}}.{{.Namespace}}.{{.Domain}}"
# tagTemplate specifies the golang text template string to use
# when constructing the DNS name for "tags" within the traffic blocks
# of Routes and Configuration. This is used in conjunction with the
# domainTemplate above to determine the full URL for the tag.
tagTemplate: "{{.Name}}-{{.Tag}}"
# Controls whether TLS certificates are automatically provisioned and
# installed in the Knative ingress to terminate external TLS connection.
# 1. Enabled: enabling auto-TLS feature.
Expand Down
55 changes: 53 additions & 2 deletions pkg/network/network.go
Expand Up @@ -20,6 +20,7 @@ import (
"bytes"
"errors"
"fmt"
"io/ioutil"
"net"
"net/http"
"net/url"
Expand Down Expand Up @@ -68,6 +69,11 @@ const (
// Knative service's DNS name.
DomainTemplateKey = "domainTemplate"

// TagTemplateKey is the name of the configuration entry that
// specifies the golang template string to use to construct the
// hostname for a Route's tag.
TagTemplateKey = "tagTemplate"

// Since K8s 1.8, prober requests have
// User-Agent = "kube-probe/{major-version}.{minor-version}".
kubeProbeUAPrefix = "kube-probe/"
Expand Down Expand Up @@ -95,6 +101,10 @@ var (
// constructing the Knative Route's Domain(host)
DefaultDomainTemplate = "{{.Name}}.{{.Namespace}}.{{.Domain}}"

// DefaultTagTemplate is the default golang template to use when
// constructing the Knative Route's tag names.
DefaultTagTemplate = "{{.Name}}-{{.Tag}}"

// AutoTLSKey is the name of the configuration entry
// that specifies enabling auto-TLS or not.
AutoTLSKey = "autoTLS"
Expand All @@ -115,6 +125,13 @@ type DomainTemplateValues struct {
Annotations map[string]string
}

// TagTemplateValues are the available properties people can choose from
// in their Route's "TagTemplate" golang template sting.
type TagTemplateValues struct {
Name string
Tag string
}

// Config contains the networking configuration defined in the
// network config map.
type Config struct {
Expand All @@ -129,6 +146,10 @@ type Config struct {
// Route's domain (host) for the Service.
DomainTemplate string

// TagTemplate is the golang text template to use to generate the
// Route's tag hostnames.
TagTemplate string

// AutoTLS specifies if auto-TLS is enabled or not.
AutoTLS bool

Expand Down Expand Up @@ -203,13 +224,28 @@ func NewConfigFromConfigMap(configMap *corev1.ConfigMap) (*Config, error) {
if err != nil {
return nil, err
}
if err := checkTemplate(t); err != nil {
if err := checkDomainTemplate(t); err != nil {
return nil, err
}

nc.DomainTemplate = dt
}

// Blank TagTemplate makes no sense so use our default
if tt, ok := configMap.Data[TagTemplateKey]; !ok {
nc.TagTemplate = DefaultTagTemplate
} else {
t, err := template.New("tag-template").Parse(tt)
if err != nil {
return nil, err
}
if err := checkTagTemplate(t); err != nil {
return nil, err
}

nc.TagTemplate = tt
}

nc.AutoTLS = strings.ToLower(configMap.Data[AutoTLSKey]) == "enabled"

switch strings.ToLower(configMap.Data[HTTPProtocolKey]) {
Expand All @@ -234,7 +270,7 @@ func (c *Config) GetDomainTemplate() *template.Template {
c.DomainTemplate))
}

func checkTemplate(t *template.Template) error {
func checkDomainTemplate(t *template.Template) error {
// To a test run of applying the template, and see if the
// result is a valid URL.
data := DomainTemplateValues{
Expand Down Expand Up @@ -264,6 +300,21 @@ func checkTemplate(t *template.Template) error {
return nil
}

func (c *Config) GetTagTemplate() *template.Template {
return template.Must(template.New("tag-template").Parse(
c.TagTemplate))
}

func checkTagTemplate(t *template.Template) error {
// To a test run of applying the template, and see if we
// produce a result without error.
data := TagTemplateValues{
Name: "foo",
Tag: "v2",
}
return t.Execute(ioutil.Discard, data)
}

// IsKubeletProbe returns true if the request is a kubernetes probe.
func IsKubeletProbe(r *http.Request) bool {
return strings.HasPrefix(r.Header.Get("User-Agent"), kubeProbeUAPrefix) ||
Expand Down
14 changes: 14 additions & 0 deletions pkg/network/network_test.go
Expand Up @@ -59,6 +59,7 @@ func TestConfiguration(t *testing.T) {
IstioOutboundIPRanges: "*",
DefaultClusterIngressClass: "istio.ingress.networking.knative.dev",
DomainTemplate: DefaultDomainTemplate,
TagTemplate: DefaultTagTemplate,
HTTPProtocol: HTTPEnabled,
},
config: &corev1.ConfigMap{
Expand All @@ -85,6 +86,7 @@ func TestConfiguration(t *testing.T) {
wantConfig: &Config{
DefaultClusterIngressClass: "istio.ingress.networking.knative.dev",
DomainTemplate: DefaultDomainTemplate,
TagTemplate: DefaultTagTemplate,
HTTPProtocol: HTTPEnabled,
},
config: &corev1.ConfigMap{
Expand Down Expand Up @@ -162,6 +164,7 @@ func TestConfiguration(t *testing.T) {
wantConfig: &Config{
DefaultClusterIngressClass: "istio.ingress.networking.knative.dev",
DomainTemplate: DefaultDomainTemplate,
TagTemplate: DefaultTagTemplate,
HTTPProtocol: HTTPEnabled,
},
config: &corev1.ConfigMap{
Expand All @@ -179,6 +182,7 @@ func TestConfiguration(t *testing.T) {
wantConfig: &Config{
DefaultClusterIngressClass: "istio.ingress.networking.knative.dev",
DomainTemplate: DefaultDomainTemplate,
TagTemplate: DefaultTagTemplate,
HTTPProtocol: HTTPEnabled,
},
config: &corev1.ConfigMap{
Expand All @@ -196,6 +200,7 @@ func TestConfiguration(t *testing.T) {
wantConfig: &Config{
DefaultClusterIngressClass: "istio.ingress.networking.knative.dev",
DomainTemplate: DefaultDomainTemplate,
TagTemplate: DefaultTagTemplate,
HTTPProtocol: HTTPEnabled,
},
config: &corev1.ConfigMap{
Expand All @@ -214,6 +219,7 @@ func TestConfiguration(t *testing.T) {
IstioOutboundIPRanges: "10.10.10.0/24",
DefaultClusterIngressClass: "istio.ingress.networking.knative.dev",
DomainTemplate: DefaultDomainTemplate,
TagTemplate: DefaultTagTemplate,
HTTPProtocol: HTTPEnabled,
},
config: &corev1.ConfigMap{
Expand All @@ -232,6 +238,7 @@ func TestConfiguration(t *testing.T) {
IstioOutboundIPRanges: "10.10.10.0/24,10.240.10.0/14,192.192.10.0/16",
DefaultClusterIngressClass: "istio.ingress.networking.knative.dev",
DomainTemplate: DefaultDomainTemplate,
TagTemplate: DefaultTagTemplate,
HTTPProtocol: HTTPEnabled,
},
config: &corev1.ConfigMap{
Expand All @@ -250,6 +257,7 @@ func TestConfiguration(t *testing.T) {
IstioOutboundIPRanges: "*",
DefaultClusterIngressClass: "istio.ingress.networking.knative.dev",
DomainTemplate: DefaultDomainTemplate,
TagTemplate: DefaultTagTemplate,
HTTPProtocol: HTTPEnabled,
},
config: &corev1.ConfigMap{
Expand All @@ -268,6 +276,7 @@ func TestConfiguration(t *testing.T) {
IstioOutboundIPRanges: "*",
DefaultClusterIngressClass: "foo-ingress",
DomainTemplate: DefaultDomainTemplate,
TagTemplate: DefaultTagTemplate,
HTTPProtocol: HTTPEnabled,
},
config: &corev1.ConfigMap{
Expand All @@ -287,6 +296,7 @@ func TestConfiguration(t *testing.T) {
IstioOutboundIPRanges: "*",
DefaultClusterIngressClass: "foo-ingress",
DomainTemplate: nonDefaultDomainTemplate,
TagTemplate: DefaultTagTemplate,
HTTPProtocol: HTTPEnabled,
},
config: &corev1.ConfigMap{
Expand Down Expand Up @@ -381,6 +391,7 @@ func TestConfiguration(t *testing.T) {
IstioOutboundIPRanges: "*",
DefaultClusterIngressClass: "istio.ingress.networking.knative.dev",
DomainTemplate: DefaultDomainTemplate,
TagTemplate: DefaultTagTemplate,
AutoTLS: true,
HTTPProtocol: HTTPEnabled,
},
Expand All @@ -401,6 +412,7 @@ func TestConfiguration(t *testing.T) {
IstioOutboundIPRanges: "*",
DefaultClusterIngressClass: "istio.ingress.networking.knative.dev",
DomainTemplate: DefaultDomainTemplate,
TagTemplate: DefaultTagTemplate,
AutoTLS: false,
HTTPProtocol: HTTPEnabled,
},
Expand All @@ -421,6 +433,7 @@ func TestConfiguration(t *testing.T) {
IstioOutboundIPRanges: "*",
DefaultClusterIngressClass: "istio.ingress.networking.knative.dev",
DomainTemplate: DefaultDomainTemplate,
TagTemplate: DefaultTagTemplate,
AutoTLS: true,
HTTPProtocol: HTTPDisabled,
},
Expand All @@ -442,6 +455,7 @@ func TestConfiguration(t *testing.T) {
IstioOutboundIPRanges: "*",
DefaultClusterIngressClass: "istio.ingress.networking.knative.dev",
DomainTemplate: DefaultDomainTemplate,
TagTemplate: DefaultTagTemplate,
AutoTLS: true,
HTTPProtocol: HTTPRedirected,
},
Expand Down
16 changes: 16 additions & 0 deletions pkg/network/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

36 changes: 27 additions & 9 deletions pkg/reconciler/route/domains/domains.go
Expand Up @@ -35,7 +35,11 @@ func GetAllDomainsAndTags(ctx context.Context, r *v1alpha1.Route, names []string
domainTagMap := make(map[string]string)

for _, name := range names {
subDomain, err := DomainNameFromTemplate(ctx, r, SubdomainName(r, name))
hostname, err := HostnameFromTemplate(ctx, r.Name, name)
if err != nil {
return nil, err
}
subDomain, err := DomainNameFromTemplate(ctx, r, hostname)
if err != nil {
return nil, err
}
Expand All @@ -44,14 +48,6 @@ func GetAllDomainsAndTags(ctx context.Context, r *v1alpha1.Route, names []string
return domainTagMap, nil
}

// SubdomainName generates a name which represents the subdomain of a route
func SubdomainName(r *v1alpha1.Route, suffix string) string {
if suffix == "" {
return r.Name
}
return fmt.Sprintf("%s-%s", r.Name, suffix)
}

// DomainNameFromTemplate generates domain name base on the template specified in the `config-network` ConfigMap.
// name is the "subdomain" which will be referred as the "name" in the template
func DomainNameFromTemplate(ctx context.Context, r *v1alpha1.Route, name string) (string, error) {
Expand All @@ -76,6 +72,28 @@ func DomainNameFromTemplate(ctx context.Context, r *v1alpha1.Route, name string)
return buf.String(), nil
}

// HostnameFromTemplate generates domain name base on the template specified in the `config-network` ConfigMap.
// name is the "subdomain" which will be referred as the "name" in the template
func HostnameFromTemplate(ctx context.Context, name string, tag string) (string, error) {
if tag == "" {
return name, nil
}
// These are the available properties they can choose from.
// We could add more over time - e.g. RevisionName if we thought that
// might be of interest to people.
data := network.TagTemplateValues{
Name: name,
Tag: tag,
}

networkConfig := config.FromContext(ctx).Network
buf := bytes.Buffer{}
if err := networkConfig.GetTagTemplate().Execute(&buf, data); err != nil {
return "", fmt.Errorf("error executing the TagTemplate: %v", err)
}
return buf.String(), nil
}

// URL generates the a string representation of a URL.
func URL(scheme, fqdn string) *apis.URL {
return &apis.URL{
Expand Down

0 comments on commit 592e69f

Please sign in to comment.