diff --git a/README.md b/README.md index efa49db..cb897cf 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,11 @@ external-lb ========== -Rancher service facilitating integration of rancher with external load balancers. This service updates external LB with services created in Rancher that ask to be load balanced using an external LB. +Rancher service facilitating integration of rancher with external load balancers. This service updates external LB with services created in Rancher that ask to be load balanced using an external LB. Initial version comes with f5 BIG-IP support; but a pluggable provider model makes it easy to implement other providers later. Design ========== -* The external-lb gets deployed as a Rancher service containerized app. +* The external-lb gets deployed as a Rancher service containerized app. * It enables any other service to be registered to external LB if the service has exposed a public port and has the label 'io.rancher.service.external_lb_endpoint' @@ -22,6 +22,8 @@ The following environment variables are used to configure global options. |----------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------| | POLL_INTERVAL | Value in milliseconds to check for rancher metadata updates | `1000` | | FORCE_UPDATE_INTERVAL | Value in minutes to force a resource poll. Increasing this value may be required if you run into api limits enforced by your cloud providor | `1` | +| SERVICE_LABEL_ENDPOINT | Which label to search for elb names to update. Useful to customize if a single rancher env spans disparate cloud provider accounts, and multiple aws-elb services are required to access each one | `io.rancher.service.external_lb.endpoint` | +| RESTRICT_SERVICE_TO_SELF_STACK | Limit service registration to those running in the same stack as the external-lb service | 'false' | Contact ======== diff --git a/main.go b/main.go index f309eb8..ac7cad9 100644 --- a/main.go +++ b/main.go @@ -19,12 +19,14 @@ import ( ) const ( - DefaultPollInterval = "1000" - DefaultForceUpdateInterval = "1" - DefaultLBTargetRancherSuffix = "rancher.internal" - EnvVarPollInterval = "POLL_INTERVAL" - EnvVarForceUpdateInterval = "FORCE_UPDATE_INTERVAL" - EnvVarLBTargetRancherSuffix = "LB_TARGET_RANCHER_SUFFIX" + DefaultPollInterval = "1000" + DefaultForceUpdateInterval = "1" + DefaultLBTargetRancherSuffix = "rancher.internal" + EnvVarPollInterval = "POLL_INTERVAL" + EnvVarForceUpdateInterval = "FORCE_UPDATE_INTERVAL" + EnvVarLBTargetRancherSuffix = "LB_TARGET_RANCHER_SUFFIX" + EnvVarServiceLabelEndpoint = "SERVICE_LABEL_ENDPOINT" + EnvVarRestrictServiceToSelfStack = "RESTRICT_SERVICE_TO_SELF_STACK" ) var ( @@ -37,13 +39,15 @@ var ( m *metadata.MetadataClient c *CattleClient - targetPoolSuffix string - metadataLBConfigsCached = make(map[string]model.LBConfig) - - forceUpdateInterval float64 - pollInterval float64 - p string - i string + targetPoolSuffix string + serviceLabelEndpoint string + restrictServiceToSelfStack bool + metadataLBConfigsCached = make(map[string]model.LBConfig) + forceUpdateInterval float64 + pollInterval float64 + p string + i string + r string ) func setEnv() { @@ -54,6 +58,27 @@ func setEnv() { var err error + // optionally restrict the service to those running in same stack as external-lb + r = os.Getenv(EnvVarRestrictServiceToSelfStack) + if len(r) == 0 { + logrus.Info(EnvVarRestrictServiceToSelfStack + " is not set") + restrictServiceToSelfStack = false + } else { + restrictServiceToSelfStack, err = strconv.ParseBool(r) + if err != nil { + logrus.Fatalf("Failed to initialize restrictServiceToSelfStack: %v", err) + } + logrus.Info(EnvVarRestrictServiceToSelfStack + " is set to: " + strconv.FormatBool(restrictServiceToSelfStack)) + } + + serviceLabelEndpoint = os.Getenv(EnvVarServiceLabelEndpoint) + if len(serviceLabelEndpoint) == 0 { + logrus.Info(EnvVarServiceLabelEndpoint + " is not set") + serviceLabelEndpoint = "" + } else { + logrus.Info(EnvVarServiceLabelEndpoint + " is set to: " + serviceLabelEndpoint) + } + // initialize polling and forceUpdate intervals i = os.Getenv(EnvVarForceUpdateInterval) if i == "" { @@ -147,7 +172,7 @@ func main() { if update || updateForced { // get records from metadata - metadataLBConfigs, err := m.GetMetadataLBConfigs(targetPoolSuffix) + metadataLBConfigs, err := m.GetMetadataLBConfigs(targetPoolSuffix, serviceLabelEndpoint, restrictServiceToSelfStack) if err != nil { logrus.Errorf("Failed to get LB configs from metadata: %v", err) continue diff --git a/metadata/metadata.go b/metadata/metadata.go index cbadf14..b011996 100644 --- a/metadata/metadata.go +++ b/metadata/metadata.go @@ -10,9 +10,9 @@ import ( ) const ( - metadataURLTemplate = "http://%v/2015-12-19" - serviceLabelEndpoint = "io.rancher.service.external_lb.endpoint" - serviceLabelEndpointLegacy = "io.rancher.service.external_lb_endpoint" + metadataURLTemplate = "http://%v/2015-12-19" + serviceLabelEndpointLegacy = "io.rancher.service.external_lb_endpoint" + DefaultServiceLabelEndpoint = "io.rancher.service.external_lb.endpoint" // DefaultMetadataAddress specifies the default value to use if nothing is specified DefaultMetadataAddress = "169.254.169.250" @@ -70,9 +70,13 @@ func (m *MetadataClient) GetVersion() (string, error) { } // GetMetadataLBConfigs ... -func (m *MetadataClient) GetMetadataLBConfigs(targetPoolSuffix string) (map[string]model.LBConfig, error) { +func (m *MetadataClient) GetMetadataLBConfigs(targetPoolSuffix string, serviceLabelEndpoint string, restrictServiceToSelfStack bool) (map[string]model.LBConfig, error) { + if serviceLabelEndpoint == "" { + serviceLabelEndpoint = DefaultServiceLabelEndpoint + } lbConfigs := make(map[string]model.LBConfig) services, err := m.MetadataClient.GetServices() + selfStack, err := m.MetadataClient.GetSelfStack() if err != nil { logrus.Infof("Error reading services: %v", err) } else { @@ -94,6 +98,15 @@ func (m *MetadataClient) GetMetadataLBConfigs(targetPoolSuffix string) (map[stri continue } + // Skip the service if it does not exist in the desired stack (optional) + logrus.Debugf("Service %s is running in stack %s", service.Name, service.StackName) + logrus.Debugf("external-lb is running in stack %s", selfStack.Name) + if restrictServiceToSelfStack && (service.StackName != selfStack.Name) { + logrus.Debugf("Skipping service %s as it is running in a different stack %s than external-lb: %s", + service.Name, service.StackName, selfStack.Name) + continue + } + // get the service port if len(service.Ports) == 0 { logrus.Warnf("Skipping LB configuration for service %s: "+ diff --git a/providers/elbv1/aws_elbv1.go b/providers/elbv1/aws_elbv1.go index d701985..65b6c80 100644 --- a/providers/elbv1/aws_elbv1.go +++ b/providers/elbv1/aws_elbv1.go @@ -120,6 +120,7 @@ func (p *AWSELBv1Provider) GetLBConfigs() ([]model.LBConfig, error) { } for _, lb := range allLb { + if _, ok := lbTags[*lb.LoadBalancerName]; !ok { continue } @@ -128,6 +129,13 @@ func (p *AWSELBv1Provider) GetLBConfigs() ([]model.LBConfig, error) { var targetPoolName, servicePort string var ok bool + + logrus.Debugf("Working on lb %s with VPCId: %s", *lb.LoadBalancerName, *lb.VPCId) + if *lb.VPCId != p.vpcID { + logrus.Debugf("Skipping LB whose vpc %s does not match our vpc %s", *lb.VPCId, p.vpcID) + continue + } + if targetPoolName, ok = tags[TagNameTargetPool]; !ok { logrus.Debugf("Skipping LB without targetPool tag: %s", *lb.LoadBalancerName) continue