Skip to content

Commit

Permalink
ECS Service Discovery feature - with service creation
Browse files Browse the repository at this point in the history
  • Loading branch information
wardviaene committed Mar 23, 2019
1 parent f607558 commit 21be384
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 11 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,8 @@ The defaults are set for the most common use cases, but can be changed by settin
| AUTOSCALING\_UP\_COOLDOWN | 5 | Cooldown period after scaling up |
| AUTOSCALING\_UP\_INTERVAL | 60 | Seconds between intervals to check resource usage before scaling, after a scaling up operation is detected |
| AUTOSCALING\_UP\_PERIOD | 5 | Periods to check before scaling |
| SERVICE\_DISCOVERY\_TTL | 60 | TTL for service discovery records |
| SERVICE_DISCOVERY_FAILURETHRESHOLD | 3 | Failure threshold for service discovery records |
| AWS\_RESOURCE\_CREATION\_ENABLED | yes | Let ecs-deploy create AWS IAM resources for you |

### Autoscaling Strategies
Expand Down
28 changes: 19 additions & 9 deletions provider/ecs/ecs.go
Original file line number Diff line number Diff line change
Expand Up @@ -696,18 +696,28 @@ func (e *ECS) CreateService(d service.Deploy) error {
// set ServiceRegistry
if d.ServiceRegistry != "" && strings.ToLower(d.ServiceProtocol) != "none" {
sd := ServiceDiscovery{}
serviceDiscoveryRegistryArn, err := sd.GetNamespaceArn(d.ServiceRegistry)
_, serviceDiscoveryNamespaceID, err := sd.getNamespaceArnAndId(d.ServiceRegistry)
if err != nil {
ecsLogger.Warningf("Could not apply ServiceRegistry Config: %s", err.Error())
} else {
ecsLogger.Debugf("Applying ServiceRegistry for %s with Arn %s", e.ServiceName, serviceDiscoveryRegistryArn)
input.SetServiceRegistries([]*ecs.ServiceRegistry{
{
ContainerName: aws.String(e.ServiceName),
ContainerPort: aws.Int64(d.ServicePort),
RegistryArn: aws.String(serviceDiscoveryRegistryArn),
},
})
serviceDiscoveryServiceArn, err := sd.getServiceArn(d.ServiceName, serviceDiscoveryNamespaceID)
if err != nil && strings.HasPrefix(err.Error(), "Service not found") {
// Service not found, create service in service registry
serviceDiscoveryServiceArn, err = sd.createService(d.ServiceName, serviceDiscoveryNamespaceID)
}
// check for error, else set service registry
if err != nil && !strings.HasPrefix(err.Error(), "Service not found") {
ecsLogger.Warningf("Could not get service from ServiceRegistry: %s", err.Error())
} else {
ecsLogger.Debugf("Applying ServiceRegistry for %s with Arn %s", e.ServiceName, serviceDiscoveryServiceArn)
input.SetServiceRegistries([]*ecs.ServiceRegistry{
{
ContainerName: aws.String(e.ServiceName),
ContainerPort: aws.Int64(d.ServicePort),
RegistryArn: aws.String(serviceDiscoveryServiceArn),
},
})
}
}
}

Expand Down
91 changes: 89 additions & 2 deletions provider/ecs/servicediscovery.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ package ecs

import (
"errors"
"strconv"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/servicediscovery"
"github.com/in4it/ecs-deploy/util"
"github.com/juju/loggo"
)

Expand All @@ -17,8 +19,9 @@ var serviceDiscoveryLogger = loggo.GetLogger("servicediscovery")
type ServiceDiscovery struct {
}

func (s *ServiceDiscovery) GetNamespaceArn(name string) (string, error) {
func (s *ServiceDiscovery) getNamespaceArnAndId(name string) (string, string, error) {
var result string
var id string
svc := servicediscovery.New(session.New())
input := &servicediscovery.ListNamespacesInput{}
pageNum := 0
Expand All @@ -28,6 +31,7 @@ func (s *ServiceDiscovery) GetNamespaceArn(name string) (string, error) {
for _, v := range page.Namespaces {
if aws.StringValue(v.Name) == name {
result = aws.StringValue(v.Arn)
id = aws.StringValue(v.Id)
}
}
return pageNum <= 100
Expand All @@ -41,7 +45,90 @@ func (s *ServiceDiscovery) GetNamespaceArn(name string) (string, error) {
}
}
if result == "" {
return result, errors.New("Namespace not found namespace=" + name)
return result, id, errors.New("Namespace not found namespace=" + name)
}
return result, id, nil
}
func (s *ServiceDiscovery) getServiceArn(serviceName, namespaceID string) (string, error) {
var result string
svc := servicediscovery.New(session.New())
input := &servicediscovery.ListServicesInput{
Filters: []*servicediscovery.ServiceFilter{
{
Name: aws.String("NAMESPACE_ID"),
Condition: aws.String("EQ"),
Values: aws.StringSlice([]string{namespaceID}),
},
},
}
pageNum := 0
err := svc.ListServicesPages(input,
func(page *servicediscovery.ListServicesOutput, lastPage bool) bool {
pageNum++
for _, v := range page.Services {
if aws.StringValue(v.Name) == serviceName {
result = aws.StringValue(v.Arn)
}
}
return pageNum <= 100
})

if err != nil {
if aerr, ok := err.(awserr.Error); ok {
ecsLogger.Errorf(aerr.Error())
} else {
ecsLogger.Errorf(err.Error())
}
}
if result == "" {
return result, errors.New("Service not found service=" + serviceName)
}
return result, nil
}
func (s *ServiceDiscovery) createService(serviceName, namespaceID string) (string, error) {
var (
ttl int64
failureThreshold int64
err error
output string
)
ttl, err = strconv.ParseInt(util.GetEnv("SERVICE_DISCOVERY_TTL", "60"), 10, 64)
if err != nil {
ttl = 60
}
failureThreshold, err = strconv.ParseInt(util.GetEnv("SERVICE_DISCOVERY_FAILURETHRESHOLD", "3"), 10, 64)
if err != nil {
failureThreshold = 3
}
svc := servicediscovery.New(session.New())
input := &servicediscovery.CreateServiceInput{
CreatorRequestId: aws.String(serviceName + "-" + util.RandStringBytesMaskImprSrc(8)),
Description: aws.String(serviceName),
Name: aws.String(serviceName),
NamespaceId: aws.String(namespaceID),
DnsConfig: &servicediscovery.DnsConfig{
DnsRecords: []*servicediscovery.DnsRecord{
{
TTL: aws.Int64(ttl),
Type: aws.String("SRV"),
},
},
},
HealthCheckCustomConfig: &servicediscovery.HealthCheckCustomConfig{
FailureThreshold: aws.Int64(failureThreshold),
},
}
result, err := svc.CreateService(input)
if err != nil {
if aerr, ok := err.(awserr.Error); ok {
ecsLogger.Errorf("%v", aerr.Error())
} else {
ecsLogger.Errorf("%v", err.Error())
}
return output, err
}

output = aws.StringValue(result.Service.Arn)

return output, nil
}

0 comments on commit 21be384

Please sign in to comment.