Skip to content

Commit a3cf5f6

Browse files
author
Daniel Kang
authored
Merge pull request #22 from coldbrewcloud/logging
Container logging support
2 parents af86fba + bc6eeb2 commit a3cf5f6

13 files changed

Lines changed: 228 additions & 23 deletions

File tree

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.2.0
1+
1.3.0

aws/client.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"github.com/coldbrewcloud/coldbrew-cli/aws/ecs"
1111
"github.com/coldbrewcloud/coldbrew-cli/aws/elb"
1212
"github.com/coldbrewcloud/coldbrew-cli/aws/iam"
13+
"github.com/coldbrewcloud/coldbrew-cli/aws/logs"
1314
"github.com/coldbrewcloud/coldbrew-cli/aws/sns"
1415
)
1516

@@ -24,6 +25,7 @@ type Client struct {
2425
ecrClient *ecr.Client
2526
iamClient *iam.Client
2627
snsClient *sns.Client
28+
logsClient *logs.Client
2729
}
2830

2931
func NewClient(region, accessKey, secretKey string) *Client {
@@ -86,3 +88,10 @@ func (c *Client) SNS() *sns.Client {
8688
}
8789
return c.snsClient
8890
}
91+
92+
func (c *Client) CloudWatchLogs() *logs.Client {
93+
if c.logsClient == nil {
94+
c.logsClient = logs.New(c.session, c.config)
95+
}
96+
return c.logsClient
97+
}

aws/consts.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,12 @@ const (
1111
AWSRegionAPSouthEast1 = "ap-southeast-1"
1212
AWSRegionAPSouthEast2 = "ap-southeast-2"
1313
AWSRegionSAEast1 = "sa-east-1"
14+
15+
ECSTaskDefinitionLogDriverJSONFile = "json-file"
16+
ECSTaskDefinitionLogDriverAWSLogs = "awslogs"
17+
ECSTaskDefinitionLogDriverSyslog = "syslog"
18+
ECSTaskDefinitionLogDriverJournald = "journald"
19+
ECSTaskDefinitionLogDriverGelf = "gelf"
20+
ECSTaskDefinitionLogDriverFluentd = "fluentd"
21+
ECSTaskDefinitionLogDriverSplunk = "splunk"
1422
)

aws/ecs/client.go

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ func (c *Client) DeleteCluster(clusterName string) error {
7171
return err
7272
}
7373

74-
func (c *Client) UpdateTaskDefinition(taskDefinitionName, image, taskContainerName string, cpu, memory uint64, envs map[string]string, portMappings []PortMapping, cloudWatchLogs bool) (*_ecs.TaskDefinition, error) {
74+
func (c *Client) UpdateTaskDefinition(taskDefinitionName, image, taskContainerName string, cpu, memory uint64, envs map[string]string, portMappings []PortMapping, logDriver string, logDriverOptions map[string]string) (*_ecs.TaskDefinition, error) {
7575
if taskDefinitionName == "" {
7676
return nil, errors.New("taskDefinitionName is empty")
7777
}
@@ -96,14 +96,10 @@ func (c *Client) UpdateTaskDefinition(taskDefinitionName, image, taskContainerNa
9696
Family: _aws.String(taskDefinitionName),
9797
}
9898

99-
// TODO: move this out of this function
100-
if cloudWatchLogs {
99+
if logDriver != "" {
101100
params.ContainerDefinitions[0].LogConfiguration = &_ecs.LogConfiguration{
102-
LogDriver: _aws.String(_ecs.LogDriverAwslogs),
103-
Options: _aws.StringMap(map[string]string{
104-
"awslogs-group": "coldbrewcloud-deploy-logs",
105-
"awslogs-region": c.awsRegion,
106-
}),
101+
LogDriver: _aws.String(logDriver),
102+
Options: _aws.StringMap(logDriverOptions),
107103
}
108104
}
109105

aws/logs/client.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package logs
2+
3+
import (
4+
_aws "github.com/aws/aws-sdk-go/aws"
5+
"github.com/aws/aws-sdk-go/aws/session"
6+
_logs "github.com/aws/aws-sdk-go/service/cloudwatchlogs"
7+
)
8+
9+
type Client struct {
10+
svc *_logs.CloudWatchLogs
11+
awsRegion string
12+
}
13+
14+
func New(session *session.Session, config *_aws.Config) *Client {
15+
return &Client{
16+
awsRegion: *config.Region,
17+
svc: _logs.New(session, config),
18+
}
19+
}
20+
21+
func (c *Client) CreateGroup(groupName string) error {
22+
params := &_logs.CreateLogGroupInput{
23+
LogGroupName: _aws.String(groupName),
24+
}
25+
26+
_, err := c.svc.CreateLogGroup(params)
27+
if err != nil {
28+
return err
29+
}
30+
31+
return nil
32+
}
33+
34+
func (c *Client) ListGroups(groupNamePrefix string) ([]*_logs.LogGroup, error) {
35+
var nextToken *string
36+
groups := []*_logs.LogGroup{}
37+
38+
for {
39+
params := &_logs.DescribeLogGroupsInput{
40+
LogGroupNamePrefix: _aws.String(groupNamePrefix),
41+
NextToken: nextToken,
42+
}
43+
44+
res, err := c.svc.DescribeLogGroups(params)
45+
if err != nil {
46+
return nil, err
47+
}
48+
49+
groups = append(groups, res.LogGroups...)
50+
51+
if res.NextToken == nil {
52+
break
53+
} else {
54+
nextToken = res.NextToken
55+
}
56+
}
57+
58+
return groups, nil
59+
}

commands/deploy/aws_ecs.go

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@ import (
55
"fmt"
66
"math"
77

8+
"github.com/coldbrewcloud/coldbrew-cli/aws"
89
"github.com/coldbrewcloud/coldbrew-cli/aws/ecs"
910
"github.com/coldbrewcloud/coldbrew-cli/console"
1011
"github.com/coldbrewcloud/coldbrew-cli/core"
12+
"github.com/coldbrewcloud/coldbrew-cli/utils"
1113
"github.com/coldbrewcloud/coldbrew-cli/utils/conv"
1214
)
1315

@@ -31,7 +33,30 @@ func (c *Command) updateECSTaskDefinition(dockerImageFullURI string) (string, er
3133
return "", err
3234
}
3335
memory /= 1000 * 1000
34-
useCloudWatchLogs := false
36+
37+
// logging
38+
loggingDriver := conv.S(c.conf.Logging.Driver)
39+
if c.conf.Logging.Options == nil {
40+
c.conf.Logging.Options = make(map[string]string)
41+
}
42+
switch loggingDriver {
43+
case aws.ECSTaskDefinitionLogDriverAWSLogs:
44+
// test if group needs to be created
45+
awsLogsGroupName, ok := c.conf.Logging.Options["awslogs-group"]
46+
if !ok || utils.IsBlank(awsLogsGroupName) {
47+
awsLogsGroupName = core.DefaultCloudWatchLogsGroupName(conv.S(c.conf.Name), conv.S(c.conf.ClusterName))
48+
c.conf.Logging.Options["awslogs-group"] = awsLogsGroupName
49+
}
50+
if err := c.PrepareCloudWatchLogsGroup(awsLogsGroupName); err != nil {
51+
return "", err
52+
}
53+
54+
// assign region if not provided
55+
awsLogsRegionName, ok := c.conf.Logging.Options["awslogs-region"]
56+
if !ok || utils.IsBlank(awsLogsRegionName) {
57+
c.conf.Logging.Options["awslogs-region"] = conv.S(c.globalFlags.AWSRegion)
58+
}
59+
}
3560

3661
console.UpdatingResource("Updating ECS Task Definition", ecsTaskDefinitionName, false)
3762
ecsTaskDef, err := c.awsClient.ECS().UpdateTaskDefinition(
@@ -42,7 +67,7 @@ func (c *Command) updateECSTaskDefinition(dockerImageFullURI string) (string, er
4267
memory,
4368
c.conf.Env,
4469
portMappings,
45-
useCloudWatchLogs)
70+
loggingDriver, c.conf.Logging.Options)
4671
if err != nil {
4772
return "", fmt.Errorf("Failed to update ECS Task Definition [%s]: %s", ecsTaskDefinitionName, err.Error())
4873
}
@@ -136,3 +161,25 @@ func (c *Command) updateECSService(ecsClusterName, ecsServiceName, ecsTaskDefini
136161

137162
return nil
138163
}
164+
165+
func (c *Command) PrepareCloudWatchLogsGroup(groupName string) error {
166+
groups, err := c.awsClient.CloudWatchLogs().ListGroups(groupName)
167+
if err != nil {
168+
return fmt.Errorf("Failed to list CloudWatch Logs Group [%s]: %s", groupName, err.Error())
169+
}
170+
171+
for _, group := range groups {
172+
if conv.S(group.LogGroupName) == groupName {
173+
// log group exists; return with no error
174+
return nil
175+
}
176+
}
177+
178+
// log group does not exist; create a new group
179+
console.AddingResource("Creating CloudWatch Logs Group", groupName, false)
180+
if err := c.awsClient.CloudWatchLogs().CreateGroup(groupName); err != nil {
181+
return fmt.Errorf("Failed to create CloudWatch Logs Group [%s]: %s", groupName, err.Error())
182+
}
183+
184+
return nil
185+
}

config/config.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ type Config struct {
99
Units *uint16 `json:"units,omitempty" yaml:"units,omitempty"`
1010
Env map[string]string `json:"env,omitempty" yaml:"env,omitempty"`
1111
LoadBalancer ConfigLoadBalancer `json:"load_balancer" yaml:"load_balancer"`
12+
Logging ConfigLogging `json:"logging" yaml:"logging"`
1213
AWS ConfigAWS `json:"aws" yaml:"aws"`
1314
Docker ConfigDocker `json:"docker" yaml:"docker"`
1415
}
@@ -29,6 +30,11 @@ type ConfigLoadBalancerHealthCheck struct {
2930
UnhealthyLimit *uint16 `json:"unhealthy_limit,omitempty" yaml:"unhealthy_limit,omitempty"`
3031
}
3132

33+
type ConfigLogging struct {
34+
Driver *string `json:"driver,omitempty" yaml:"driver,omitempty"`
35+
Options map[string]string `json:"options" yaml:"options"`
36+
}
37+
3238
type ConfigAWS struct {
3339
ELBLoadBalancerName *string `json:"elb_name,omitempty" yaml:"elb_name,omitempty"`
3440
ELBTargetGroupName *string `json:"elb_target_group_name,omitempty" yaml:"elb_target_group_name,omitempty"`

config/config_test.go

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
package config
22

3-
import (
4-
"github.com/coldbrewcloud/coldbrew-cli/utils/conv"
5-
)
3+
import "github.com/coldbrewcloud/coldbrew-cli/utils/conv"
64

75
const refConfigYAML = `
86
name: echo
@@ -29,6 +27,12 @@ load_balancer:
2927
healthy_limit: 5
3028
unhealthy_limit: 2
3129
30+
logging:
31+
driver: json-file
32+
options:
33+
logopt1: value1
34+
logopt2: value2
35+
3236
aws:
3337
elb_name: echo-lb
3438
elb_target_group_name: echo-target
@@ -65,6 +69,13 @@ const refConfigJSON = `
6569
"unhealthy_limit": 2
6670
}
6771
},
72+
"logging": {
73+
"driver": "json-file",
74+
"options": {
75+
"logopt1": "value1",
76+
"logopt2": "value2"
77+
}
78+
},
6879
"aws": {
6980
"elb_name": "echo-lb",
7081
"elb_target_group_name": "echo-target",
@@ -101,6 +112,13 @@ var refConfig = &Config{
101112
UnhealthyLimit: conv.U16P(2),
102113
},
103114
},
115+
Logging: ConfigLogging{
116+
Driver: conv.SP("json-file"),
117+
Options: map[string]string{
118+
"logopt1": "value1",
119+
"logopt2": "value2",
120+
},
121+
},
104122
AWS: ConfigAWS{
105123
ELBLoadBalancerName: conv.SP("echo-lb"),
106124
ELBTargetGroupName: conv.SP("echo-target"),

config/default_config.go

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,24 @@ func DefaultConfig(appName string) *Config {
1919
conf.Env = make(map[string]string)
2020

2121
// load balancer
22-
conf.LoadBalancer.Enabled = conv.BP(false)
23-
conf.LoadBalancer.Port = conv.U16P(80)
22+
{
23+
conf.LoadBalancer.Enabled = conv.BP(false)
24+
conf.LoadBalancer.Port = conv.U16P(80)
25+
26+
// health check
27+
conf.LoadBalancer.HealthCheck.Path = conv.SP("/")
28+
conf.LoadBalancer.HealthCheck.Status = conv.SP("200-299")
29+
conf.LoadBalancer.HealthCheck.Interval = conv.SP("15s")
30+
conf.LoadBalancer.HealthCheck.Timeout = conv.SP("10s")
31+
conf.LoadBalancer.HealthCheck.HealthyLimit = conv.U16P(3)
32+
conf.LoadBalancer.HealthCheck.UnhealthyLimit = conv.U16P(3)
33+
}
2434

25-
// health check
26-
conf.LoadBalancer.HealthCheck.Path = conv.SP("/")
27-
conf.LoadBalancer.HealthCheck.Status = conv.SP("200-299")
28-
conf.LoadBalancer.HealthCheck.Interval = conv.SP("15s")
29-
conf.LoadBalancer.HealthCheck.Timeout = conv.SP("10s")
30-
conf.LoadBalancer.HealthCheck.HealthyLimit = conv.U16P(3)
31-
conf.LoadBalancer.HealthCheck.UnhealthyLimit = conv.U16P(3)
35+
// logging
36+
{
37+
conf.Logging.Driver = nil
38+
conf.Logging.Options = make(map[string]string)
39+
}
3240

3341
// AWS
3442
{

config/load.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,18 @@ func (c *Config) Defaults(source *Config) {
7676
defU16(&c.LoadBalancer.HealthCheck.HealthyLimit, source.LoadBalancer.HealthCheck.HealthyLimit)
7777
defU16(&c.LoadBalancer.HealthCheck.UnhealthyLimit, source.LoadBalancer.HealthCheck.UnhealthyLimit)
7878

79+
// logging
80+
if conv.S(c.Logging.Driver) == "" {
81+
// logging option is copied only when logging driver was copied
82+
defS(&c.Logging.Driver, source.Logging.Driver)
83+
if source.Logging.Options != nil {
84+
c.Logging.Options = make(map[string]string)
85+
for k, v := range source.Logging.Options {
86+
c.Logging.Options[k] = v
87+
}
88+
}
89+
}
90+
7991
// AWS
8092
defS(&c.AWS.ELBLoadBalancerName, source.AWS.ELBLoadBalancerName)
8193
defS(&c.AWS.ELBTargetGroupName, source.AWS.ELBTargetGroupName)

0 commit comments

Comments
 (0)