Skip to content
This repository was archived by the owner on Oct 23, 2024. It is now read-only.

Commit

Permalink
translator: make edgelb pool name optional
Browse files Browse the repository at this point in the history
Signed-off-by: Bruno Custodio <[email protected]>
  • Loading branch information
Bruno Custodio authored and pires committed Jan 10, 2019
1 parent 86f6266 commit a54f0ee
Show file tree
Hide file tree
Showing 15 changed files with 191 additions and 78 deletions.
12 changes: 8 additions & 4 deletions docs/usage/10-provisioning-services.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,21 @@ In particular, exposing UDP or SCTP services is **NOT** supported.
=== Using `dklb` to provision a Kubernetes service

To expose a TCP application running on MKE to either inside or outside the DC/OS cluster, a Kubernetes https://kubernetes.io/docs/concepts/services-networking/service/[`Service`] resource of type https://kubernetes.io/docs/concepts/services-networking/service/#loadbalancer[`LoadBalancer`] must be created.
Furthermore, and in order for `dklb` to provision said service using EdgeLB, the service must be https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/[annotated] with the following annotation:
`dklb` will react to this event by provisioning an EdgeLB pool (henceforth referred to as the _target EdgeLB pool_) for the `Service` resource based on its specification.

=== Customizing the name of the EdgeLB pool

By default, `dklb` uses the MKE cluster's name and the `Service` resource's namespace and name to compute the name of the target EdgeLB pool.
To specify a custom name for said EdgeLB pool, one may https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/[annotate] the `Service` resource with the following annotation:

[source,text]
----
kubernetes.dcos.io/edgelb-pool-name: "<edgelb-pool-name>"
----

This annotation lets `dklb` know about the EdgeLB pool it should use to provision the service (henceforth referred to as the _target EdgeLB pool_).
Depending on whether the target EdgeLB pool exists or not, `dklb` will create or update it in order to expose all ports defined in the `Service` resource.
Depending on whether the "<edgelb-pool-name>" EdgeLB pool exists or not, `dklb` will create or update it in order to expose all ports defined in the `Service` resource.

IMPORTANT: One must not remove or change the value of this annotation at any time after the `Service` resource is created.
IMPORTANT: One must not remove or change the value of this annotation at any time after it is added to a given `Service` resource.

=== Intra-DC/OS vs external exposure

Expand Down
2 changes: 1 addition & 1 deletion pkg/controllers/ingress.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ func (c *IngressController) processQueueItem(workItem WorkItem) error {
er := kubernetesutil.NewEventRecorderForNamespace(c.kubeClient, ingress.Namespace)

// Compute the set of options that will be used to translate the Ingress resource into an EdgeLB pool.
options, err := translator.ComputeIngressTranslationOptions(ingress)
options, err := translator.ComputeIngressTranslationOptions(c.clusterName, ingress)
if err != nil {
// Emit an event and log an error, but do not re-enqueue as the resource's spec was found to be invalid.
er.Eventf(ingress, corev1.EventTypeWarning, constants.ReasonInvalidAnnotations, "the resource's annotations are not valid: %v", err)
Expand Down
2 changes: 1 addition & 1 deletion pkg/controllers/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ func (c *ServiceController) processQueueItem(workItem WorkItem) error {
er := kubernetesutil.NewEventRecorderForNamespace(c.kubeClient, service.Namespace)

// Compute the set of options that will be used to translate the Service resource into an EdgeLB pool.
options, err := translator.ComputeServiceTranslationOptions(service)
options, err := translator.ComputeServiceTranslationOptions(c.clusterName, service)
if err != nil {
// Emit an event and log an error, but do not re-enqueue as the resource's spec was found to be invalid.
er.Eventf(service, corev1.EventTypeWarning, constants.ReasonInvalidAnnotations, "the resource's annotations are not valid: %v", err)
Expand Down
13 changes: 6 additions & 7 deletions pkg/translator/base_options.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,16 @@ type BaseTranslationOptions struct {

// parseBaseTranslationOptions attempts to compute base, common translation options from the specified set of annotations.
// In case options cannot be computed or are invalid, the error message MUST be suitable to be used as the message for a Kubernetes event associated with the resource.
func parseBaseTranslationOptions(annotations map[string]string) (*BaseTranslationOptions, error) {
func parseBaseTranslationOptions(clusterName, namespace, name string, annotations map[string]string) (*BaseTranslationOptions, error) {
// Create a "BaseTranslationOptions" struct to hold the computed options.
res := &BaseTranslationOptions{}

// Parse the name of the target EdgeLB pool.
// This annotation is MANDATORY.
v, exists := annotations[constants.EdgeLBPoolNameAnnotationKey]
if !exists || v == "" {
return nil, fmt.Errorf("required annotation %q has not been provided", constants.EdgeLBPoolNameAnnotationKey)
// Parse or compute the name of the target EdgeLB pool.
if v, exists := annotations[constants.EdgeLBPoolNameAnnotationKey]; !exists || v == "" {
res.EdgeLBPoolName = computeEdgeLBPoolName(clusterName, namespace, name)
} else {
res.EdgeLBPoolName = v
}
res.EdgeLBPoolName = v

// Parse the role of the target EdgeLB pool.
if v, exists := annotations[constants.EdgeLBPoolRoleAnnotationKey]; !exists || v == "" {
Expand Down
21 changes: 21 additions & 0 deletions pkg/translator/base_options_utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package translator

import (
"fmt"

"github.com/mesosphere/dklb/pkg/util/strings"
)

const (
// edgeLBPoolNameComponentSeparator is the string used as to separate the components of an EdgeLB pool's name.
// "--" is chosen as the value since the name of an EdgeLB pool must match the "^[a-z0-9]([a-z0-9-]*[a-z0-9])?$" regular expression.
edgeLBPoolNameComponentSeparator = "--"
// edgeLBPoolNameFormatString is the format string used to compute the name of an EdgeLB pool corresponding to a given Kubernetes resource.
// The resulting name is of the form "<cluster-name>--<namespace>--<name>".
edgeLBPoolNameFormatString = "%s" + edgeLBPoolNameComponentSeparator + "%s" + edgeLBPoolNameComponentSeparator + "%s"
)

// computeEdgeLBPoolName computes the name of the EdgeLB pool that corresponds to the Kubernetes resource corresponding to the provided coordinates.
func computeEdgeLBPoolName(clusterName, namespace, name string) string {
return fmt.Sprintf(edgeLBPoolNameFormatString, strings.ReplaceForwardSlashes(clusterName, edgeLBPoolNameComponentSeparator), namespace, name)
}
4 changes: 2 additions & 2 deletions pkg/translator/ingress_options.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ type IngressTranslationOptions struct {

// ComputeIngressTranslationOptions computes the set of options to use for "translating" the specified Ingress resource into an EdgeLB pool.
// In case options cannot be computed or are invalid, the error message MUST be suitable to be used as the message for a Kubernetes event associated with the resource.
func ComputeIngressTranslationOptions(obj *extsv1beta1.Ingress) (*IngressTranslationOptions, error) {
func ComputeIngressTranslationOptions(clusterName string, obj *extsv1beta1.Ingress) (*IngressTranslationOptions, error) {
// Create an "IngressTranslationOptions" struct to hold the computed options.
res := &IngressTranslationOptions{}
var annotations map[string]string
Expand All @@ -33,7 +33,7 @@ func ComputeIngressTranslationOptions(obj *extsv1beta1.Ingress) (*IngressTransla
}

// Parse base translation options.
b, err := parseBaseTranslationOptions(annotations)
b, err := parseBaseTranslationOptions(clusterName, obj.Namespace, obj.Name, annotations)
if err != nil {
return nil, err
}
Expand Down
42 changes: 24 additions & 18 deletions pkg/translator/ingress_options_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,28 @@ func TestComputeIngressTranslationOptions(t *testing.T) {
options *translator.IngressTranslationOptions
error error
}{
// Test computing options for an Ingress resource without the required annotations.
// Make sure an error is returned.
// Test computing options for an Ingress resource without any annotations.
// Make sure the name of the EdgeLB pool is computed as expected, and that the default values are used everywhere else.
{
description: "compute options for an Ingress resource without the required annotations",
description: "compute options for an Ingress resource without any annotations",
annotations: map[string]string{},
options: nil,
error: fmt.Errorf("required annotation %q has not been provided", constants.EdgeLBPoolNameAnnotationKey),
options: &translator.IngressTranslationOptions{
BaseTranslationOptions: translator.BaseTranslationOptions{
EdgeLBPoolName: "dev--kubernetes01--foo--bar",
EdgeLBPoolRole: translator.DefaultEdgeLBPoolRole,
EdgeLBPoolCpus: translator.DefaultEdgeLBPoolCpus,
EdgeLBPoolMem: translator.DefaultEdgeLBPoolMem,
EdgeLBPoolSize: translator.DefaultEdgeLBPoolSize,
EdgeLBPoolCreationStrategy: translator.DefaultEdgeLBPoolCreationStrategy,
},
EdgeLBPoolPort: translator.DefaultEdgeLBPoolPort,
},
error: nil,
},
// Test computing options for an Ingress resource with just the required annotations.
// Test computing options for an Ingress resource specifying the name of the target EdgeLB pool.
// Make sure the name of the EdgeLB pool is captured as expected, and that the default values are used everywhere else.
{
description: "compute options for an Ingress resource with just the required annotations",
description: "compute options for an Ingress resource specifying the name of the target EdgeLB pool",
annotations: map[string]string{
constants.EdgeLBPoolNameAnnotationKey: "foo",
},
Expand All @@ -49,16 +59,15 @@ func TestComputeIngressTranslationOptions(t *testing.T) {
error: nil,
},
// Test computing options for an Ingress resource defining a custom frontend bind port.
// Make sure the name of the EdgeLB pool and the frontend bind port are captured as expected, and that the default values are used everywhere else.
// Make sure the frontend bind port is captured as expected, and that the default values are used everywhere else.
{
description: "compute options for an Ingress resource defining a custom frontend bind port",
annotations: map[string]string{
constants.EdgeLBPoolNameAnnotationKey: "foo",
constants.EdgeLBPoolPortKey: "14708",
constants.EdgeLBPoolPortKey: "14708",
},
options: &translator.IngressTranslationOptions{
BaseTranslationOptions: translator.BaseTranslationOptions{
EdgeLBPoolName: "foo",
EdgeLBPoolName: "dev--kubernetes01--foo--bar",
EdgeLBPoolRole: translator.DefaultEdgeLBPoolRole,
EdgeLBPoolCpus: translator.DefaultEdgeLBPoolCpus,
EdgeLBPoolMem: translator.DefaultEdgeLBPoolMem,
Expand All @@ -74,8 +83,7 @@ func TestComputeIngressTranslationOptions(t *testing.T) {
{
description: "compute options for an Ingress resource defining an invalid value for the frontend bind port",
annotations: map[string]string{
constants.EdgeLBPoolNameAnnotationKey: "foo",
constants.EdgeLBPoolPortKey: "74511",
constants.EdgeLBPoolPortKey: "74511",
},
options: nil,
error: fmt.Errorf("%d is not a valid port number", 74511),
Expand Down Expand Up @@ -113,8 +121,7 @@ func TestComputeIngressTranslationOptions(t *testing.T) {
{
description: "compute options for an Ingress resource with a custom but invalid port mapping",
annotations: map[string]string{
constants.EdgeLBPoolNameAnnotationKey: "foo",
constants.EdgeLBPoolPortKey: "74511",
constants.EdgeLBPoolPortKey: "74511",
},
options: nil,
error: fmt.Errorf("%d is not a valid port number", 74511),
Expand All @@ -124,8 +131,7 @@ func TestComputeIngressTranslationOptions(t *testing.T) {
{
description: "compute options for a Service resource having an invalid port mapping",
annotations: map[string]string{
constants.EdgeLBPoolNameAnnotationKey: "foo",
constants.EdgeLBPoolPortKey: "foo",
constants.EdgeLBPoolPortKey: "foo",
},
options: nil,
error: fmt.Errorf("failed to parse %q as the frontend bind port to use: %v", "foo", "strconv.Atoi: parsing \"foo\": invalid syntax"),
Expand All @@ -137,7 +143,7 @@ func TestComputeIngressTranslationOptions(t *testing.T) {
// Create a dummy Ingress resource containing the annotations for the current test.
r := ingresstestutil.DummyIngressResource("foo", "bar", ingresstestutil.WithAnnotations(test.annotations))
// Compute the translation options for the resource.
o, err := translator.ComputeIngressTranslationOptions(r)
o, err := translator.ComputeIngressTranslationOptions(testClusterName, r)
if err != nil {
// Make sure the error matches the expected one.
assert.EqualError(t, err, test.error.Error())
Expand Down
4 changes: 2 additions & 2 deletions pkg/translator/service_options.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ type ServiceTranslationOptions struct {

// ComputeServiceTranslationOptions computes the set of options to use for "translating" the specified Service resource into an EdgeLB pool.
// In case options cannot be computed or are invalid, the error message MUST be suitable to be used as the message for a Kubernetes event associated with the resource.
func ComputeServiceTranslationOptions(obj *corev1.Service) (*ServiceTranslationOptions, error) {
func ComputeServiceTranslationOptions(clusterName string, obj *corev1.Service) (*ServiceTranslationOptions, error) {
// Create an "ServiceTranslationOptions" struct to hold the computed options.
res := &ServiceTranslationOptions{
EdgeLBPoolPortMap: make(map[int32]int32, len(obj.Spec.Ports)),
Expand All @@ -35,7 +35,7 @@ func ComputeServiceTranslationOptions(obj *corev1.Service) (*ServiceTranslationO
}

// Parse base translation options.
b, err := parseBaseTranslationOptions(annotations)
b, err := parseBaseTranslationOptions(clusterName, obj.Namespace, obj.Name, annotations)
if err != nil {
return nil, err
}
Expand Down
Loading

0 comments on commit a54f0ee

Please sign in to comment.