mirror of https://github.com/docker/compose.git
Apply linter recommendations
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
This commit is contained in:
parent
0a6d7b1c6d
commit
ec4615ae57
|
@ -132,7 +132,6 @@ func (a *aciAPIService) SecretsService() secrets.Service {
|
|||
return nil
|
||||
}
|
||||
|
||||
|
||||
type aciContainerService struct {
|
||||
ctx store.AciContext
|
||||
}
|
||||
|
|
|
@ -20,12 +20,13 @@ import (
|
|||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/docker/api/secrets"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/docker/api/compose"
|
||||
"github.com/docker/api/containers"
|
||||
"github.com/docker/api/context/cloud"
|
||||
"github.com/docker/api/secrets"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
@ -18,8 +18,8 @@ package compose
|
|||
|
||||
import (
|
||||
"context"
|
||||
"github.com/compose-spec/compose-go/cli"
|
||||
|
||||
"github.com/compose-spec/compose-go/cli"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
|
|
|
@ -18,14 +18,14 @@ package client
|
|||
|
||||
import (
|
||||
"context"
|
||||
"github.com/docker/api/secrets"
|
||||
|
||||
"github.com/docker/api/context/cloud"
|
||||
"github.com/docker/api/secrets"
|
||||
|
||||
"github.com/docker/api/backend"
|
||||
"github.com/docker/api/compose"
|
||||
"github.com/docker/api/containers"
|
||||
apicontext "github.com/docker/api/context"
|
||||
"github.com/docker/api/context/cloud"
|
||||
"github.com/docker/api/context/store"
|
||||
)
|
||||
|
||||
|
@ -71,7 +71,7 @@ func (c *Client) ComposeService() compose.Service {
|
|||
return c.bs.ComposeService()
|
||||
}
|
||||
|
||||
// ComposeService returns the backend service for the current context
|
||||
// SecretsService returns the backend service for the current context
|
||||
func (c *Client) SecretsService() secrets.Service {
|
||||
return c.bs.SecretsService()
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@ type Service interface {
|
|||
Convert(ctx context.Context, opts *cli.ProjectOptions) ([]byte, error)
|
||||
}
|
||||
|
||||
// PortPublisher hold status about published port
|
||||
type PortPublisher struct {
|
||||
URL string
|
||||
TargetPort int
|
||||
|
@ -44,11 +45,12 @@ type PortPublisher struct {
|
|||
Protocol string
|
||||
}
|
||||
|
||||
// ServiceStatus hold status about a service
|
||||
type ServiceStatus struct {
|
||||
ID string
|
||||
Name string
|
||||
Replicas int
|
||||
Desired int
|
||||
Ports []string
|
||||
LoadBalancers []PortPublisher
|
||||
ID string
|
||||
Name string
|
||||
Replicas int
|
||||
Desired int
|
||||
Ports []string
|
||||
Publishers []PortPublisher
|
||||
}
|
||||
|
|
|
@ -17,7 +17,10 @@
|
|||
package compose
|
||||
|
||||
const (
|
||||
// ProjectTag allow to track resource related to a compose project
|
||||
ProjectTag = "com.docker.compose.project"
|
||||
// NetworkTag allow to track resource related to a compose network
|
||||
NetworkTag = "com.docker.compose.network"
|
||||
// ServiceTag allow to track resource related to a compose service
|
||||
ServiceTag = "com.docker.compose.service"
|
||||
)
|
||||
|
|
|
@ -76,7 +76,7 @@ func getEcsAPIService(ecsCtx store.EcsContext) (*ecsAPIService, error) {
|
|||
return &ecsAPIService{
|
||||
ctx: ecsCtx,
|
||||
Region: ecsCtx.Region,
|
||||
SDK: NewSDK(sess),
|
||||
SDK: newSDK(sess),
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -46,11 +46,11 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
ParameterClusterName = "ParameterClusterName"
|
||||
ParameterVPCId = "ParameterVPCId"
|
||||
ParameterSubnet1Id = "ParameterSubnet1Id"
|
||||
ParameterSubnet2Id = "ParameterSubnet2Id"
|
||||
ParameterLoadBalancerARN = "ParameterLoadBalancerARN"
|
||||
parameterClusterName = "ParameterClusterName"
|
||||
parameterVPCId = "ParameterVPCId"
|
||||
parameterSubnet1Id = "ParameterSubnet1Id"
|
||||
parameterSubnet2Id = "ParameterSubnet2Id"
|
||||
parameterLoadBalancerARN = "ParameterLoadBalancerARN"
|
||||
)
|
||||
|
||||
func (b *ecsAPIService) Convert(ctx context.Context, opts *cli.ProjectOptions) ([]byte, error) {
|
||||
|
@ -62,12 +62,12 @@ func (b *ecsAPIService) Convert(ctx context.Context, opts *cli.ProjectOptions) (
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return Marshall(template)
|
||||
return marshall(template)
|
||||
}
|
||||
|
||||
// Convert a compose project into a CloudFormation template
|
||||
func (b *ecsAPIService) convert(project *types.Project) (*cloudformation.Template, error) {
|
||||
var checker compatibility.Checker = &FargateCompatibilityChecker{
|
||||
func (b *ecsAPIService) convert(project *types.Project) (*cloudformation.Template, error) { //nolint:gocyclo
|
||||
var checker compatibility.Checker = &fargateCompatibilityChecker{
|
||||
compatibility.AllowList{
|
||||
Supported: compatibleComposeAttributes,
|
||||
},
|
||||
|
@ -86,12 +86,12 @@ func (b *ecsAPIService) convert(project *types.Project) (*cloudformation.Templat
|
|||
|
||||
template := cloudformation.NewTemplate()
|
||||
template.Description = "CloudFormation template created by Docker for deploying applications on Amazon ECS"
|
||||
template.Parameters[ParameterClusterName] = cloudformation.Parameter{
|
||||
template.Parameters[parameterClusterName] = cloudformation.Parameter{
|
||||
Type: "String",
|
||||
Description: "Name of the ECS cluster to deploy to (optional)",
|
||||
}
|
||||
|
||||
template.Parameters[ParameterVPCId] = cloudformation.Parameter{
|
||||
template.Parameters[parameterVPCId] = cloudformation.Parameter{
|
||||
Type: "AWS::EC2::VPC::Id",
|
||||
Description: "ID of the VPC",
|
||||
}
|
||||
|
@ -103,28 +103,28 @@ func (b *ecsAPIService) convert(project *types.Project) (*cloudformation.Templat
|
|||
Description: "The list of SubnetIds, for at least two Availability Zones in the region in your VPC",
|
||||
}
|
||||
*/
|
||||
template.Parameters[ParameterSubnet1Id] = cloudformation.Parameter{
|
||||
template.Parameters[parameterSubnet1Id] = cloudformation.Parameter{
|
||||
Type: "AWS::EC2::Subnet::Id",
|
||||
Description: "SubnetId, for Availability Zone 1 in the region in your VPC",
|
||||
}
|
||||
template.Parameters[ParameterSubnet2Id] = cloudformation.Parameter{
|
||||
template.Parameters[parameterSubnet2Id] = cloudformation.Parameter{
|
||||
Type: "AWS::EC2::Subnet::Id",
|
||||
Description: "SubnetId, for Availability Zone 2 in the region in your VPC",
|
||||
}
|
||||
|
||||
template.Parameters[ParameterLoadBalancerARN] = cloudformation.Parameter{
|
||||
template.Parameters[parameterLoadBalancerARN] = cloudformation.Parameter{
|
||||
Type: "String",
|
||||
Description: "Name of the LoadBalancer to connect to (optional)",
|
||||
}
|
||||
|
||||
// Create Cluster is `ParameterClusterName` parameter is not set
|
||||
template.Conditions["CreateCluster"] = cloudformation.Equals("", cloudformation.Ref(ParameterClusterName))
|
||||
template.Conditions["CreateCluster"] = cloudformation.Equals("", cloudformation.Ref(parameterClusterName))
|
||||
|
||||
cluster := createCluster(project, template)
|
||||
|
||||
networks := map[string]string{}
|
||||
for _, net := range project.Networks {
|
||||
networks[net.Name] = convertNetwork(project, net, cloudformation.Ref(ParameterVPCId), template)
|
||||
networks[net.Name] = convertNetwork(project, net, cloudformation.Ref(parameterVPCId), template)
|
||||
}
|
||||
|
||||
for i, s := range project.Secrets {
|
||||
|
@ -175,9 +175,6 @@ func (b *ecsAPIService) convert(project *types.Project) (*cloudformation.Templat
|
|||
template.Resources[taskDefinition] = definition
|
||||
|
||||
var healthCheck *cloudmap.Service_HealthCheckConfig
|
||||
if service.HealthCheck != nil && !service.HealthCheck.Disable {
|
||||
// FIXME ECS only support HTTP(s) health checks, while Docker only support CMD
|
||||
}
|
||||
|
||||
serviceRegistry := createServiceRegistry(service, template, healthCheck)
|
||||
|
||||
|
@ -242,8 +239,8 @@ func (b *ecsAPIService) convert(project *types.Project) (*cloudformation.Templat
|
|||
AssignPublicIp: ecsapi.AssignPublicIpEnabled,
|
||||
SecurityGroups: serviceSecurityGroups,
|
||||
Subnets: []string{
|
||||
cloudformation.Ref(ParameterSubnet1Id),
|
||||
cloudformation.Ref(ParameterSubnet2Id),
|
||||
cloudformation.Ref(parameterSubnet1Id),
|
||||
cloudformation.Ref(parameterSubnet2Id),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -268,7 +265,7 @@ func (b *ecsAPIService) convert(project *types.Project) (*cloudformation.Templat
|
|||
|
||||
func createLogGroup(project *types.Project, template *cloudformation.Template) {
|
||||
retention := 0
|
||||
if v, ok := project.Extensions[ExtensionRetention]; ok {
|
||||
if v, ok := project.Extensions[extensionRetention]; ok {
|
||||
retention = v.(int)
|
||||
}
|
||||
logGroup := fmt.Sprintf("/docker-compose/%s", project.Name)
|
||||
|
@ -285,11 +282,11 @@ func computeRollingUpdateLimits(service types.ServiceConfig) (int, int, error) {
|
|||
return minPercent, maxPercent, nil
|
||||
}
|
||||
updateConfig := service.Deploy.UpdateConfig
|
||||
min, okMin := updateConfig.Extensions[ExtensionMinPercent]
|
||||
min, okMin := updateConfig.Extensions[extensionMinPercent]
|
||||
if okMin {
|
||||
minPercent = min.(int)
|
||||
}
|
||||
max, okMax := updateConfig.Extensions[ExtensionMaxPercent]
|
||||
max, okMax := updateConfig.Extensions[extensionMaxPercent]
|
||||
if okMax {
|
||||
maxPercent = max.(int)
|
||||
}
|
||||
|
@ -333,7 +330,7 @@ func getLoadBalancerSecurityGroups(project *types.Project, template *cloudformat
|
|||
securityGroups := []string{}
|
||||
for _, network := range project.Networks {
|
||||
if !network.Internal {
|
||||
net := convertNetwork(project, network, cloudformation.Ref(ParameterVPCId), template)
|
||||
net := convertNetwork(project, network, cloudformation.Ref(parameterVPCId), template)
|
||||
securityGroups = append(securityGroups, net)
|
||||
}
|
||||
}
|
||||
|
@ -354,7 +351,7 @@ func createLoadBalancer(project *types.Project, template *cloudformation.Templat
|
|||
// load balancer names are limited to 32 characters total
|
||||
loadBalancerName := fmt.Sprintf("%.32s", fmt.Sprintf("%sLoadBalancer", strings.Title(project.Name)))
|
||||
// Create PortPublisher if `ParameterLoadBalancerName` is not set
|
||||
template.Conditions["CreateLoadBalancer"] = cloudformation.Equals("", cloudformation.Ref(ParameterLoadBalancerARN))
|
||||
template.Conditions["CreateLoadBalancer"] = cloudformation.Equals("", cloudformation.Ref(parameterLoadBalancerARN))
|
||||
|
||||
loadBalancerType := getLoadBalancerType(project)
|
||||
securityGroups := []string{}
|
||||
|
@ -367,8 +364,8 @@ func createLoadBalancer(project *types.Project, template *cloudformation.Templat
|
|||
Scheme: elbv2.LoadBalancerSchemeEnumInternetFacing,
|
||||
SecurityGroups: securityGroups,
|
||||
Subnets: []string{
|
||||
cloudformation.Ref(ParameterSubnet1Id),
|
||||
cloudformation.Ref(ParameterSubnet2Id),
|
||||
cloudformation.Ref(parameterSubnet1Id),
|
||||
cloudformation.Ref(parameterSubnet2Id),
|
||||
},
|
||||
Tags: []tags.Tag{
|
||||
{
|
||||
|
@ -379,7 +376,7 @@ func createLoadBalancer(project *types.Project, template *cloudformation.Templat
|
|||
Type: loadBalancerType,
|
||||
AWSCloudFormationCondition: "CreateLoadBalancer",
|
||||
}
|
||||
return cloudformation.If("CreateLoadBalancer", cloudformation.Ref(loadBalancerName), cloudformation.Ref(ParameterLoadBalancerARN))
|
||||
return cloudformation.If("CreateLoadBalancer", cloudformation.Ref(loadBalancerName), cloudformation.Ref(parameterLoadBalancerARN))
|
||||
}
|
||||
|
||||
func createListener(service types.ServiceConfig, port types.ServicePortConfig, template *cloudformation.Template, targetGroupName string, loadBalancerARN string, protocol string) string {
|
||||
|
@ -427,7 +424,7 @@ func createTargetGroup(project *types.Project, service types.ServiceConfig, port
|
|||
Value: project.Name,
|
||||
},
|
||||
},
|
||||
VpcId: cloudformation.Ref(ParameterVPCId),
|
||||
VpcId: cloudformation.Ref(parameterVPCId),
|
||||
TargetType: elbv2.TargetTypeEnumIp,
|
||||
}
|
||||
return targetGroupName
|
||||
|
@ -462,7 +459,7 @@ func createServiceRegistry(service types.ServiceConfig, template *cloudformation
|
|||
|
||||
func createTaskExecutionRole(service types.ServiceConfig, err error, definition *ecs.TaskDefinition, template *cloudformation.Template) (string, error) {
|
||||
taskExecutionRole := fmt.Sprintf("%sTaskExecutionRole", normalizeResourceName(service.Name))
|
||||
policy, err := getPolicy(definition)
|
||||
policy := getPolicy(definition)
|
||||
if err != nil {
|
||||
return taskExecutionRole, err
|
||||
}
|
||||
|
@ -474,16 +471,16 @@ func createTaskExecutionRole(service types.ServiceConfig, err error, definition
|
|||
})
|
||||
}
|
||||
|
||||
if roles, ok := service.Extensions[ExtensionRole]; ok {
|
||||
if roles, ok := service.Extensions[extensionRole]; ok {
|
||||
rolePolicies = append(rolePolicies, iam.Role_Policy{
|
||||
PolicyDocument: roles,
|
||||
})
|
||||
}
|
||||
managedPolicies := []string{
|
||||
ECSTaskExecutionPolicy,
|
||||
ECRReadOnlyPolicy,
|
||||
ecsTaskExecutionPolicy,
|
||||
ecrReadOnlyPolicy,
|
||||
}
|
||||
if v, ok := service.Extensions[ExtensionManagedPolicies]; ok {
|
||||
if v, ok := service.Extensions[extensionManagedPolicies]; ok {
|
||||
for _, s := range v.([]interface{}) {
|
||||
managedPolicies = append(managedPolicies, s.(string))
|
||||
}
|
||||
|
@ -507,7 +504,7 @@ func createCluster(project *types.Project, template *cloudformation.Template) st
|
|||
},
|
||||
AWSCloudFormationCondition: "CreateCluster",
|
||||
}
|
||||
cluster := cloudformation.If("CreateCluster", cloudformation.Ref("Cluster"), cloudformation.Ref(ParameterClusterName))
|
||||
cluster := cloudformation.If("CreateCluster", cloudformation.Ref("Cluster"), cloudformation.Ref(parameterClusterName))
|
||||
return cluster
|
||||
}
|
||||
|
||||
|
@ -515,12 +512,12 @@ func createCloudMap(project *types.Project, template *cloudformation.Template) {
|
|||
template.Resources["CloudMap"] = &cloudmap.PrivateDnsNamespace{
|
||||
Description: fmt.Sprintf("Service Map for Docker Compose project %s", project.Name),
|
||||
Name: fmt.Sprintf("%s.local", project.Name),
|
||||
Vpc: cloudformation.Ref(ParameterVPCId),
|
||||
Vpc: cloudformation.Ref(parameterVPCId),
|
||||
}
|
||||
}
|
||||
|
||||
func convertNetwork(project *types.Project, net types.NetworkConfig, vpc string, template *cloudformation.Template) string {
|
||||
if sg, ok := net.Extensions[ExtensionSecurityGroup]; ok {
|
||||
if sg, ok := net.Extensions[extensionSecurityGroup]; ok {
|
||||
logrus.Debugf("Security Group for network %q set by user to %q", net.Name, sg)
|
||||
return sg.(string)
|
||||
}
|
||||
|
@ -583,7 +580,7 @@ func normalizeResourceName(s string) string {
|
|||
return strings.Title(regexp.MustCompile("[^a-zA-Z0-9]+").ReplaceAllString(s, ""))
|
||||
}
|
||||
|
||||
func getPolicy(taskDef *ecs.TaskDefinition) (*PolicyDocument, error) {
|
||||
func getPolicy(taskDef *ecs.TaskDefinition) *PolicyDocument {
|
||||
arns := []string{}
|
||||
for _, container := range taskDef.ContainerDefinitions {
|
||||
if container.RepositoryCredentials != nil {
|
||||
|
@ -601,12 +598,12 @@ func getPolicy(taskDef *ecs.TaskDefinition) (*PolicyDocument, error) {
|
|||
Statement: []PolicyStatement{
|
||||
{
|
||||
Effect: "Allow",
|
||||
Action: []string{ActionGetSecretValue, ActionGetParameters, ActionDecrypt},
|
||||
Action: []string{actionGetSecretValue, actionGetParameters, actionDecrypt},
|
||||
Resource: arns,
|
||||
}},
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func uniqueStrings(items []string) []string {
|
||||
|
|
|
@ -45,7 +45,7 @@ func TestSimpleConvert(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestLogging(t *testing.T) {
|
||||
template := convertYaml(t, "test", `
|
||||
template := convertYaml(t, `
|
||||
services:
|
||||
foo:
|
||||
image: hello_world
|
||||
|
@ -64,7 +64,7 @@ x-aws-logs_retention: 10
|
|||
}
|
||||
|
||||
func TestEnvFile(t *testing.T) {
|
||||
template := convertYaml(t, "test", `
|
||||
template := convertYaml(t, `
|
||||
services:
|
||||
foo:
|
||||
image: hello_world
|
||||
|
@ -84,7 +84,7 @@ services:
|
|||
}
|
||||
|
||||
func TestEnvFileAndEnv(t *testing.T) {
|
||||
template := convertYaml(t, "test", `
|
||||
template := convertYaml(t, `
|
||||
services:
|
||||
foo:
|
||||
image: hello_world
|
||||
|
@ -106,7 +106,7 @@ services:
|
|||
}
|
||||
|
||||
func TestRollingUpdateLimits(t *testing.T) {
|
||||
template := convertYaml(t, "test", `
|
||||
template := convertYaml(t, `
|
||||
services:
|
||||
foo:
|
||||
image: hello_world
|
||||
|
@ -121,7 +121,7 @@ services:
|
|||
}
|
||||
|
||||
func TestRollingUpdateExtension(t *testing.T) {
|
||||
template := convertYaml(t, "test", `
|
||||
template := convertYaml(t, `
|
||||
services:
|
||||
foo:
|
||||
image: hello_world
|
||||
|
@ -136,16 +136,17 @@ services:
|
|||
}
|
||||
|
||||
func TestRolePolicy(t *testing.T) {
|
||||
template := convertYaml(t, "test", `
|
||||
template := convertYaml(t, `
|
||||
services:
|
||||
foo:
|
||||
image: hello_world
|
||||
x-aws-pull_credentials: "secret"
|
||||
`)
|
||||
role := template.Resources["FooTaskExecutionRole"].(*iam.Role)
|
||||
assert.Check(t, role != nil)
|
||||
assert.Check(t, role.ManagedPolicyArns[0] == ECSTaskExecutionPolicy)
|
||||
assert.Check(t, role.ManagedPolicyArns[1] == ECRReadOnlyPolicy)
|
||||
x := template.Resources["FooTaskExecutionRole"]
|
||||
assert.Check(t, x != nil)
|
||||
role := *(x.(*iam.Role))
|
||||
assert.Check(t, role.ManagedPolicyArns[0] == ecsTaskExecutionPolicy)
|
||||
assert.Check(t, role.ManagedPolicyArns[1] == ecrReadOnlyPolicy)
|
||||
// We expect an extra policy has been created for x-aws-pull_credentials
|
||||
assert.Check(t, len(role.Policies) == 1)
|
||||
policy := role.Policies[0].PolicyDocument.(*PolicyDocument)
|
||||
|
@ -155,7 +156,7 @@ services:
|
|||
}
|
||||
|
||||
func TestMapNetworksToSecurityGroups(t *testing.T) {
|
||||
template := convertYaml(t, "test", `
|
||||
template := convertYaml(t, `
|
||||
services:
|
||||
test:
|
||||
image: hello_world
|
||||
|
@ -172,29 +173,31 @@ networks:
|
|||
assert.Check(t, template.Resources["TestPublicNetwork"] != nil)
|
||||
assert.Check(t, template.Resources["TestBacktierNetwork"] != nil)
|
||||
assert.Check(t, template.Resources["TestBacktierNetworkIngress"] != nil)
|
||||
ingress := template.Resources["TestPublicNetworkIngress"].(*ec2.SecurityGroupIngress)
|
||||
assert.Check(t, ingress != nil)
|
||||
i := template.Resources["TestPublicNetworkIngress"]
|
||||
assert.Check(t, i != nil)
|
||||
ingress := *i.(*ec2.SecurityGroupIngress)
|
||||
assert.Check(t, ingress.SourceSecurityGroupId == cloudformation.Ref("TestPublicNetwork"))
|
||||
|
||||
}
|
||||
|
||||
func TestLoadBalancerTypeApplication(t *testing.T) {
|
||||
template := convertYaml(t, "test123456789009876543211234567890", `
|
||||
template := convertYaml(t, `
|
||||
services:
|
||||
test:
|
||||
image: nginx
|
||||
ports:
|
||||
- 80:80
|
||||
`)
|
||||
lb := template.Resources["TestLoadBalancer"].(*elasticloadbalancingv2.LoadBalancer)
|
||||
lb := template.Resources["TestLoadBalancer"]
|
||||
assert.Check(t, lb != nil)
|
||||
assert.Check(t, len(lb.Name) <= 32)
|
||||
assert.Check(t, lb.Type == elbv2.LoadBalancerTypeEnumApplication)
|
||||
assert.Check(t, len(lb.SecurityGroups) > 0)
|
||||
loadBalancer := *lb.(*elasticloadbalancingv2.LoadBalancer)
|
||||
assert.Check(t, len(loadBalancer.Name) <= 32)
|
||||
assert.Check(t, loadBalancer.Type == elbv2.LoadBalancerTypeEnumApplication)
|
||||
assert.Check(t, len(loadBalancer.SecurityGroups) > 0)
|
||||
}
|
||||
|
||||
func TestNoLoadBalancerIfNoPortExposed(t *testing.T) {
|
||||
template := convertYaml(t, "test", `
|
||||
template := convertYaml(t, `
|
||||
services:
|
||||
test:
|
||||
image: nginx
|
||||
|
@ -209,20 +212,21 @@ services:
|
|||
}
|
||||
|
||||
func TestServiceReplicas(t *testing.T) {
|
||||
template := convertYaml(t, "test", `
|
||||
template := convertYaml(t, `
|
||||
services:
|
||||
test:
|
||||
image: nginx
|
||||
deploy:
|
||||
replicas: 10
|
||||
`)
|
||||
s := template.Resources["TestService"].(*ecs.Service)
|
||||
s := template.Resources["TestService"]
|
||||
assert.Check(t, s != nil)
|
||||
assert.Check(t, s.DesiredCount == 10)
|
||||
service := *s.(*ecs.Service)
|
||||
assert.Check(t, service.DesiredCount == 10)
|
||||
}
|
||||
|
||||
func TestTaskSizeConvert(t *testing.T) {
|
||||
template := convertYaml(t, "test", `
|
||||
template := convertYaml(t, `
|
||||
services:
|
||||
test:
|
||||
image: nginx
|
||||
|
@ -239,7 +243,7 @@ services:
|
|||
assert.Equal(t, def.Cpu, "512")
|
||||
assert.Equal(t, def.Memory, "2048")
|
||||
|
||||
template = convertYaml(t, "test", `
|
||||
template = convertYaml(t, `
|
||||
services:
|
||||
test:
|
||||
image: nginx
|
||||
|
@ -257,7 +261,7 @@ services:
|
|||
assert.Equal(t, def.Memory, "8192")
|
||||
}
|
||||
func TestTaskSizeConvertFailure(t *testing.T) {
|
||||
model := loadConfig(t, "test", `
|
||||
model := loadConfig(t, `
|
||||
services:
|
||||
test:
|
||||
image: nginx
|
||||
|
@ -273,7 +277,7 @@ services:
|
|||
}
|
||||
|
||||
func TestLoadBalancerTypeNetwork(t *testing.T) {
|
||||
template := convertYaml(t, "test", `
|
||||
template := convertYaml(t, `
|
||||
services:
|
||||
test:
|
||||
image: nginx
|
||||
|
@ -281,13 +285,14 @@ services:
|
|||
- 80:80
|
||||
- 88:88
|
||||
`)
|
||||
lb := template.Resources["TestLoadBalancer"].(*elasticloadbalancingv2.LoadBalancer)
|
||||
lb := template.Resources["TestLoadBalancer"]
|
||||
assert.Check(t, lb != nil)
|
||||
assert.Check(t, lb.Type == elbv2.LoadBalancerTypeEnumNetwork)
|
||||
loadBalancer := *lb.(*elasticloadbalancingv2.LoadBalancer)
|
||||
assert.Check(t, loadBalancer.Type == elbv2.LoadBalancerTypeEnumNetwork)
|
||||
}
|
||||
|
||||
func TestServiceMapping(t *testing.T) {
|
||||
template := convertYaml(t, "test", `
|
||||
template := convertYaml(t, `
|
||||
services:
|
||||
test:
|
||||
image: "image"
|
||||
|
@ -326,7 +331,7 @@ func get(l []ecs.TaskDefinition_KeyValuePair, name string) string {
|
|||
}
|
||||
|
||||
func TestResourcesHaveProjectTagSet(t *testing.T) {
|
||||
template := convertYaml(t, "test", `
|
||||
template := convertYaml(t, `
|
||||
services:
|
||||
test:
|
||||
image: nginx
|
||||
|
@ -353,7 +358,7 @@ func convertResultAsString(t *testing.T, project *types.Project) string {
|
|||
backend := &ecsAPIService{}
|
||||
template, err := backend.convert(project)
|
||||
assert.NilError(t, err)
|
||||
resultAsJSON, err := Marshall(template)
|
||||
resultAsJSON, err := marshall(template)
|
||||
assert.NilError(t, err)
|
||||
return fmt.Sprintf("%s\n", string(resultAsJSON))
|
||||
}
|
||||
|
@ -368,15 +373,15 @@ func load(t *testing.T, paths ...string) *types.Project {
|
|||
return project
|
||||
}
|
||||
|
||||
func convertYaml(t *testing.T, name string, yaml string) *cloudformation.Template {
|
||||
project := loadConfig(t, name, yaml)
|
||||
func convertYaml(t *testing.T, yaml string) *cloudformation.Template {
|
||||
project := loadConfig(t, yaml)
|
||||
backend := &ecsAPIService{}
|
||||
template, err := backend.convert(project)
|
||||
assert.NilError(t, err)
|
||||
return template
|
||||
}
|
||||
|
||||
func loadConfig(t *testing.T, name string, yaml string) *types.Project {
|
||||
func loadConfig(t *testing.T, yaml string) *types.Project {
|
||||
dict, err := loader.ParseYAML([]byte(yaml))
|
||||
assert.NilError(t, err)
|
||||
model, err := loader.Load(types.ConfigDetails{
|
||||
|
|
|
@ -21,7 +21,7 @@ import (
|
|||
"strconv"
|
||||
)
|
||||
|
||||
var NAMES = []string{
|
||||
var names = []string{
|
||||
"grey",
|
||||
"red",
|
||||
"green",
|
||||
|
@ -32,14 +32,8 @@ var NAMES = []string{
|
|||
"white",
|
||||
}
|
||||
|
||||
var COLORS map[string]ColorFunc
|
||||
|
||||
// ColorFunc use ANSI codes to render colored text on console
|
||||
type ColorFunc func(s string) string
|
||||
|
||||
var Monochrome = func(s string) string {
|
||||
return s
|
||||
}
|
||||
// colorFunc use ANSI codes to render colored text on console
|
||||
type colorFunc func(s string) string
|
||||
|
||||
func ansiColor(code, s string) string {
|
||||
return fmt.Sprintf("%s%s%s", ansi(code), s, ansi("0"))
|
||||
|
@ -49,38 +43,38 @@ func ansi(code string) string {
|
|||
return fmt.Sprintf("\033[%sm", code)
|
||||
}
|
||||
|
||||
func makeColorFunc(code string) ColorFunc {
|
||||
func makeColorFunc(code string) colorFunc {
|
||||
return func(s string) string {
|
||||
return ansiColor(code, s)
|
||||
}
|
||||
}
|
||||
|
||||
var Rainbow = make(chan ColorFunc)
|
||||
var loop = make(chan colorFunc)
|
||||
|
||||
func init() {
|
||||
COLORS = map[string]ColorFunc{}
|
||||
for i, name := range NAMES {
|
||||
COLORS[name] = makeColorFunc(strconv.Itoa(30 + i))
|
||||
COLORS["intense_"+name] = makeColorFunc(strconv.Itoa(30+i) + ";1")
|
||||
colors := map[string]colorFunc{}
|
||||
for i, name := range names {
|
||||
colors[name] = makeColorFunc(strconv.Itoa(30 + i))
|
||||
colors["intense_"+name] = makeColorFunc(strconv.Itoa(30+i) + ";1")
|
||||
}
|
||||
|
||||
go func() {
|
||||
i := 0
|
||||
rainbow := []ColorFunc{
|
||||
COLORS["cyan"],
|
||||
COLORS["yellow"],
|
||||
COLORS["green"],
|
||||
COLORS["magenta"],
|
||||
COLORS["blue"],
|
||||
COLORS["intense_cyan"],
|
||||
COLORS["intense_yellow"],
|
||||
COLORS["intense_green"],
|
||||
COLORS["intense_magenta"],
|
||||
COLORS["intense_blue"],
|
||||
rainbow := []colorFunc{
|
||||
colors["cyan"],
|
||||
colors["yellow"],
|
||||
colors["green"],
|
||||
colors["magenta"],
|
||||
colors["blue"],
|
||||
colors["intense_cyan"],
|
||||
colors["intense_yellow"],
|
||||
colors["intense_green"],
|
||||
colors["intense_magenta"],
|
||||
colors["intense_blue"],
|
||||
}
|
||||
|
||||
for {
|
||||
Rainbow <- rainbow[i]
|
||||
loop <- rainbow[i]
|
||||
i = (i + 1) % len(rainbow)
|
||||
}
|
||||
}()
|
||||
|
|
|
@ -21,7 +21,7 @@ import (
|
|||
"github.com/compose-spec/compose-go/types"
|
||||
)
|
||||
|
||||
type FargateCompatibilityChecker struct {
|
||||
type fargateCompatibilityChecker struct {
|
||||
compatibility.AllowList
|
||||
}
|
||||
|
||||
|
@ -68,13 +68,13 @@ var compatibleComposeAttributes = []string{
|
|||
"secrets.file",
|
||||
}
|
||||
|
||||
func (c *FargateCompatibilityChecker) CheckImage(service *types.ServiceConfig) {
|
||||
func (c *fargateCompatibilityChecker) CheckImage(service *types.ServiceConfig) {
|
||||
if service.Image == "" {
|
||||
c.Incompatible("service %s doesn't define a Docker image to run", service.Name)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *FargateCompatibilityChecker) CheckPortsPublished(p *types.ServicePortConfig) {
|
||||
func (c *fargateCompatibilityChecker) CheckPortsPublished(p *types.ServicePortConfig) {
|
||||
if p.Published == 0 {
|
||||
p.Published = p.Target
|
||||
}
|
||||
|
@ -83,7 +83,7 @@ func (c *FargateCompatibilityChecker) CheckPortsPublished(p *types.ServicePortCo
|
|||
}
|
||||
}
|
||||
|
||||
func (c *FargateCompatibilityChecker) CheckCapAdd(service *types.ServiceConfig) {
|
||||
func (c *fargateCompatibilityChecker) CheckCapAdd(service *types.ServiceConfig) {
|
||||
add := []string{}
|
||||
for _, cap := range service.CapAdd {
|
||||
switch cap {
|
||||
|
@ -96,7 +96,7 @@ func (c *FargateCompatibilityChecker) CheckCapAdd(service *types.ServiceConfig)
|
|||
service.CapAdd = add
|
||||
}
|
||||
|
||||
func (c *FargateCompatibilityChecker) CheckLoggingDriver(config *types.LoggingConfig) {
|
||||
func (c *fargateCompatibilityChecker) CheckLoggingDriver(config *types.LoggingConfig) {
|
||||
if config.Driver != "" && config.Driver != "awslogs" {
|
||||
c.Unsupported("services.logging.driver %s is not supported", config.Driver)
|
||||
}
|
||||
|
|
|
@ -103,7 +103,7 @@ func (h contextCreateAWSHelper) saveCredentials(profile string, accessKeyID stri
|
|||
p := credentials.SharedCredentialsProvider{Profile: profile}
|
||||
_, err := p.Retrieve()
|
||||
if err == nil {
|
||||
return fmt.Errorf("credentials already exists!")
|
||||
return fmt.Errorf("credentials already exists")
|
||||
}
|
||||
|
||||
if err.(awserr.Error).Code() == "SharedCredsLoad" && err.(awserr.Error).Message() == "failed to load shared credentials file" {
|
||||
|
|
|
@ -44,10 +44,7 @@ func convert(project *types.Project, service types.ServiceConfig) (*ecs.TaskDefi
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, memReservation, err := toContainerReservation(service)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, memReservation := toContainerReservation(service)
|
||||
credential := getRepoCredentials(service)
|
||||
|
||||
// override resolve.conf search directive to also search <project>.local
|
||||
|
@ -141,7 +138,11 @@ func convert(project *types.Project, service types.ServiceConfig) (*ecs.TaskDefi
|
|||
}, nil
|
||||
}
|
||||
|
||||
func createSecretsSideCar(project *types.Project, service types.ServiceConfig, logConfiguration *ecs.TaskDefinition_LogConfiguration) (ecs.TaskDefinition_Volume, ecs.TaskDefinition_MountPoint, ecs.TaskDefinition_ContainerDefinition, error) {
|
||||
func createSecretsSideCar(project *types.Project, service types.ServiceConfig, logConfiguration *ecs.TaskDefinition_LogConfiguration) (
|
||||
ecs.TaskDefinition_Volume,
|
||||
ecs.TaskDefinition_MountPoint,
|
||||
ecs.TaskDefinition_ContainerDefinition,
|
||||
error) {
|
||||
initContainerName := fmt.Sprintf("%s_Secrets_InitContainer", normalizeResourceName(service.Name))
|
||||
secretsVolume := ecs.TaskDefinition_Volume{
|
||||
Name: "secrets",
|
||||
|
@ -166,7 +167,7 @@ func createSecretsSideCar(project *types.Project, service types.ServiceConfig, l
|
|||
ValueFrom: secretConfig.Name,
|
||||
})
|
||||
var keys []string
|
||||
if ext, ok := secretConfig.Extensions[ExtensionKeys]; ok {
|
||||
if ext, ok := secretConfig.Extensions[extensionKeys]; ok {
|
||||
if key, ok := ext.(string); ok {
|
||||
keys = append(keys, key)
|
||||
} else {
|
||||
|
@ -275,7 +276,7 @@ func toSystemControls(sysctls types.Mapping) []ecs.TaskDefinition_SystemControl
|
|||
return sys
|
||||
}
|
||||
|
||||
const MiB = 1024 * 1024
|
||||
const miB = 1024 * 1024
|
||||
|
||||
func toLimits(service types.ServiceConfig) (string, string, error) {
|
||||
// All possible cpu/mem values for Fargate
|
||||
|
@ -315,9 +316,9 @@ func toLimits(service types.ServiceConfig) (string, string, error) {
|
|||
|
||||
for _, cpu := range cpus {
|
||||
mem := cpuToMem[cpu]
|
||||
if v <= cpu*MiB {
|
||||
if v <= cpu*miB {
|
||||
for _, m := range mem {
|
||||
if limits.MemoryBytes <= m*MiB {
|
||||
if limits.MemoryBytes <= m*miB {
|
||||
cpuLimit = strconv.FormatInt(cpu, 10)
|
||||
memLimit = strconv.FormatInt(int64(m), 10)
|
||||
return cpuLimit, memLimit, nil
|
||||
|
@ -328,19 +329,19 @@ func toLimits(service types.ServiceConfig) (string, string, error) {
|
|||
return "", "", fmt.Errorf("the resources requested are not supported by ECS/Fargate")
|
||||
}
|
||||
|
||||
func toContainerReservation(service types.ServiceConfig) (string, int, error) {
|
||||
func toContainerReservation(service types.ServiceConfig) (string, int) {
|
||||
cpuReservation := ".0"
|
||||
memReservation := 0
|
||||
|
||||
if service.Deploy == nil {
|
||||
return cpuReservation, memReservation, nil
|
||||
return cpuReservation, memReservation
|
||||
}
|
||||
|
||||
reservations := service.Deploy.Resources.Reservations
|
||||
if reservations == nil {
|
||||
return cpuReservation, memReservation, nil
|
||||
return cpuReservation, memReservation
|
||||
}
|
||||
return reservations.NanoCPUs, int(reservations.MemoryBytes / MiB), nil
|
||||
return reservations.NanoCPUs, int(reservations.MemoryBytes / miB)
|
||||
}
|
||||
|
||||
func toPlacementConstraints(deploy *types.DeployConfig) []ecs.TaskDefinition_TaskDefinitionPlacementConstraint {
|
||||
|
@ -467,7 +468,7 @@ func toHostEntryPtr(hosts types.HostsList) []ecs.TaskDefinition_HostEntry {
|
|||
func getRepoCredentials(service types.ServiceConfig) *ecs.TaskDefinition_RepositoryCredentials {
|
||||
// extract registry and namespace string from image name
|
||||
for key, value := range service.Extensions {
|
||||
if key == ExtensionPullCredentials {
|
||||
if key == extensionPullCredentials {
|
||||
return &ecs.TaskDefinition_RepositoryCredentials{CredentialsParameter: value.(string)}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ func (b *ecsAPIService) Down(ctx context.Context, options *cli.ProjectOptions) e
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return b.WaitStackCompletion(ctx, name, StackDelete)
|
||||
return b.WaitStackCompletion(ctx, name, stackDelete)
|
||||
}
|
||||
|
||||
func (b *ecsAPIService) projectName(options *cli.ProjectOptions) (string, error) {
|
||||
|
|
13
ecs/iam.go
13
ecs/iam.go
|
@ -17,12 +17,12 @@
|
|||
package ecs
|
||||
|
||||
const (
|
||||
ECSTaskExecutionPolicy = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"
|
||||
ECRReadOnlyPolicy = "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly"
|
||||
ecsTaskExecutionPolicy = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"
|
||||
ecrReadOnlyPolicy = "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly"
|
||||
|
||||
ActionGetSecretValue = "secretsmanager:GetSecretValue"
|
||||
ActionGetParameters = "ssm:GetParameters"
|
||||
ActionDecrypt = "kms:Decrypt"
|
||||
actionGetSecretValue = "secretsmanager:GetSecretValue"
|
||||
actionGetParameters = "ssm:GetParameters"
|
||||
actionDecrypt = "kms:Decrypt"
|
||||
)
|
||||
|
||||
var assumeRolePolicyDocument = PolicyDocument{
|
||||
|
@ -38,12 +38,14 @@ var assumeRolePolicyDocument = PolicyDocument{
|
|||
},
|
||||
}
|
||||
|
||||
// PolicyDocument describes an IAM policy document
|
||||
// could alternatively depend on https://github.com/kubernetes-sigs/cluster-api-provider-aws/blob/master/cmd/clusterawsadm/api/iam/v1alpha1/types.go
|
||||
type PolicyDocument struct {
|
||||
Version string `json:",omitempty"`
|
||||
Statement []PolicyStatement `json:",omitempty"`
|
||||
}
|
||||
|
||||
// PolicyStatement describes an IAM policy statement
|
||||
type PolicyStatement struct {
|
||||
Effect string `json:",omitempty"`
|
||||
Action []string `json:",omitempty"`
|
||||
|
@ -51,6 +53,7 @@ type PolicyStatement struct {
|
|||
Resource []string `json:",omitempty"`
|
||||
}
|
||||
|
||||
// PolicyPrincipal describes an IAM policy principal
|
||||
type PolicyPrincipal struct {
|
||||
Service string `json:",omitempty"`
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ func (b *ecsAPIService) Ps(ctx context.Context, options *cli.ProjectOptions) ([]
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cluster := parameters[ParameterClusterName]
|
||||
cluster := parameters[parameterClusterName]
|
||||
|
||||
resources, err := b.SDK.ListStackResources(ctx, projectName)
|
||||
if err != nil {
|
||||
|
@ -61,7 +61,7 @@ func (b *ecsAPIService) Ps(ctx context.Context, options *cli.ProjectOptions) ([]
|
|||
|
||||
for i, state := range status {
|
||||
ports := []string{}
|
||||
for _, lb := range state.LoadBalancers {
|
||||
for _, lb := range state.Publishers {
|
||||
ports = append(ports, fmt.Sprintf(
|
||||
"%s:%d->%d/%s",
|
||||
lb.URL,
|
||||
|
|
|
@ -40,7 +40,7 @@ func (b *ecsAPIService) Logs(ctx context.Context, options *cli.ProjectOptions, w
|
|||
}
|
||||
|
||||
consumer := logConsumer{
|
||||
colors: map[string]ColorFunc{},
|
||||
colors: map[string]colorFunc{},
|
||||
width: 0,
|
||||
writer: writer,
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ func (b *ecsAPIService) Logs(ctx context.Context, options *cli.ProjectOptions, w
|
|||
func (l *logConsumer) Log(service, container, message string) {
|
||||
cf, ok := l.colors[service]
|
||||
if !ok {
|
||||
cf = <-Rainbow
|
||||
cf = <-loop
|
||||
l.colors[service] = cf
|
||||
l.computeWidth()
|
||||
}
|
||||
|
@ -81,7 +81,7 @@ func (l *logConsumer) computeWidth() {
|
|||
}
|
||||
|
||||
type logConsumer struct {
|
||||
colors map[string]ColorFunc
|
||||
colors map[string]colorFunc
|
||||
width int
|
||||
writer io.Writer
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ import (
|
|||
"github.com/awslabs/goformation/v4/cloudformation"
|
||||
)
|
||||
|
||||
func Marshall(template *cloudformation.Template) ([]byte, error) {
|
||||
func marshall(template *cloudformation.Template) ([]byte, error) {
|
||||
raw, err := template.JSON()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
52
ecs/sdk.go
52
ecs/sdk.go
|
@ -22,11 +22,12 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/client"
|
||||
|
||||
"github.com/docker/api/compose"
|
||||
"github.com/docker/api/secrets"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/cloudformation"
|
||||
"github.com/aws/aws-sdk-go/service/cloudformation/cloudformationiface"
|
||||
"github.com/aws/aws-sdk-go/service/cloudwatchlogs"
|
||||
|
@ -46,17 +47,16 @@ import (
|
|||
)
|
||||
|
||||
type sdk struct {
|
||||
sess *session.Session
|
||||
ECS ecsiface.ECSAPI
|
||||
EC2 ec2iface.EC2API
|
||||
ELB elbv2iface.ELBV2API
|
||||
CW cloudwatchlogsiface.CloudWatchLogsAPI
|
||||
IAM iamiface.IAMAPI
|
||||
CF cloudformationiface.CloudFormationAPI
|
||||
SM secretsmanageriface.SecretsManagerAPI
|
||||
ECS ecsiface.ECSAPI
|
||||
EC2 ec2iface.EC2API
|
||||
ELB elbv2iface.ELBV2API
|
||||
CW cloudwatchlogsiface.CloudWatchLogsAPI
|
||||
IAM iamiface.IAMAPI
|
||||
CF cloudformationiface.CloudFormationAPI
|
||||
SM secretsmanageriface.SecretsManagerAPI
|
||||
}
|
||||
|
||||
func NewSDK(sess *session.Session) sdk {
|
||||
func newSDK(sess client.ConfigProvider) sdk {
|
||||
return sdk{
|
||||
ECS: ecs.New(sess),
|
||||
EC2: ec2.New(sess),
|
||||
|
@ -177,7 +177,7 @@ func (s sdk) StackExists(ctx context.Context, name string) (bool, error) {
|
|||
|
||||
func (s sdk) CreateStack(ctx context.Context, name string, template *cf.Template, parameters map[string]string) error {
|
||||
logrus.Debug("Create CloudFormation stack")
|
||||
json, err := Marshall(template)
|
||||
json, err := marshall(template)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -205,7 +205,7 @@ func (s sdk) CreateStack(ctx context.Context, name string, template *cf.Template
|
|||
|
||||
func (s sdk) CreateChangeSet(ctx context.Context, name string, template *cf.Template, parameters map[string]string) (string, error) {
|
||||
logrus.Debug("Create CloudFormation Changeset")
|
||||
json, err := Marshall(template)
|
||||
json, err := marshall(template)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -258,9 +258,9 @@ func (s sdk) UpdateStack(ctx context.Context, changeset string) error {
|
|||
}
|
||||
|
||||
const (
|
||||
StackCreate = iota
|
||||
StackUpdate
|
||||
StackDelete
|
||||
stackCreate = iota
|
||||
stackUpdate
|
||||
stackDelete
|
||||
)
|
||||
|
||||
func (s sdk) WaitStackComplete(ctx context.Context, name string, operation int) error {
|
||||
|
@ -268,9 +268,9 @@ func (s sdk) WaitStackComplete(ctx context.Context, name string, operation int)
|
|||
StackName: aws.String(name),
|
||||
}
|
||||
switch operation {
|
||||
case StackCreate:
|
||||
case stackCreate:
|
||||
return s.CF.WaitUntilStackCreateCompleteWithContext(ctx, input)
|
||||
case StackDelete:
|
||||
case stackDelete:
|
||||
return s.CF.WaitUntilStackDeleteCompleteWithContext(ctx, input)
|
||||
default:
|
||||
return fmt.Errorf("internal error: unexpected stack operation %d", operation)
|
||||
|
@ -322,14 +322,14 @@ func (s sdk) ListStackParameters(ctx context.Context, name string) (map[string]s
|
|||
return parameters, nil
|
||||
}
|
||||
|
||||
type StackResource struct {
|
||||
type stackResource struct {
|
||||
LogicalID string
|
||||
Type string
|
||||
ARN string
|
||||
Status string
|
||||
}
|
||||
|
||||
func (s sdk) ListStackResources(ctx context.Context, name string) ([]StackResource, error) {
|
||||
func (s sdk) ListStackResources(ctx context.Context, name string) ([]stackResource, error) {
|
||||
// FIXME handle pagination
|
||||
res, err := s.CF.ListStackResourcesWithContext(ctx, &cloudformation.ListStackResourcesInput{
|
||||
StackName: aws.String(name),
|
||||
|
@ -338,9 +338,9 @@ func (s sdk) ListStackResources(ctx context.Context, name string) ([]StackResour
|
|||
return nil, err
|
||||
}
|
||||
|
||||
resources := []StackResource{}
|
||||
resources := []stackResource{}
|
||||
for _, r := range res.StackResourceSummaries {
|
||||
resources = append(resources, StackResource{
|
||||
resources = append(resources, stackResource{
|
||||
LogicalID: aws.StringValue(r.LogicalResourceId),
|
||||
Type: aws.StringValue(r.ResourceType),
|
||||
ARN: aws.StringValue(r.PhysicalResourceId),
|
||||
|
@ -495,11 +495,11 @@ func (s sdk) DescribeServices(ctx context.Context, cluster string, arns []string
|
|||
return nil, err
|
||||
}
|
||||
status = append(status, compose.ServiceStatus{
|
||||
ID: aws.StringValue(service.ServiceName),
|
||||
Name: name,
|
||||
Replicas: int(aws.Int64Value(service.RunningCount)),
|
||||
Desired: int(aws.Int64Value(service.DesiredCount)),
|
||||
LoadBalancers: loadBalancers,
|
||||
ID: aws.StringValue(service.ServiceName),
|
||||
Name: name,
|
||||
Replicas: int(aws.Int64Value(service.RunningCount)),
|
||||
Desired: int(aws.Int64Value(service.DesiredCount)),
|
||||
Publishers: loadBalancers,
|
||||
})
|
||||
}
|
||||
return status, nil
|
||||
|
|
|
@ -24,11 +24,13 @@ import (
|
|||
"path/filepath"
|
||||
)
|
||||
|
||||
// Secret define sensitive data to be bound as file
|
||||
type Secret struct {
|
||||
Name string
|
||||
Keys []string
|
||||
}
|
||||
|
||||
// CreateSecretFiles retrieve sensitive data from env and store as plain text a a file in path
|
||||
func CreateSecretFiles(secret Secret, path string) error {
|
||||
value, ok := os.LookupEnv(secret.Name)
|
||||
if !ok {
|
||||
|
|
|
@ -28,21 +28,21 @@ const secretsFolder = "/run/secrets"
|
|||
|
||||
func main() {
|
||||
if len(os.Args) != 2 {
|
||||
fmt.Fprintf(os.Stderr, "usage: secrets <json encoded []Secret>")
|
||||
fmt.Fprint(os.Stderr, "usage: secrets <json encoded []Secret>")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
var input []secrets.Secret
|
||||
err := json.Unmarshal([]byte(os.Args[1]), &input)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, err.Error())
|
||||
fmt.Fprint(os.Stderr, err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
for _, secret := range input {
|
||||
err := secrets.CreateSecretFiles(secret, secretsFolder)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, err.Error())
|
||||
fmt.Fprint(os.Stderr, err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
|
20
ecs/up.go
20
ecs/up.go
|
@ -67,20 +67,20 @@ func (b *ecsAPIService) Up(ctx context.Context, options *cli.ProjectOptions) err
|
|||
}
|
||||
|
||||
parameters := map[string]string{
|
||||
ParameterClusterName: cluster,
|
||||
ParameterVPCId: vpc,
|
||||
ParameterSubnet1Id: subNets[0],
|
||||
ParameterSubnet2Id: subNets[1],
|
||||
ParameterLoadBalancerARN: lb,
|
||||
parameterClusterName: cluster,
|
||||
parameterVPCId: vpc,
|
||||
parameterSubnet1Id: subNets[0],
|
||||
parameterSubnet2Id: subNets[1],
|
||||
parameterLoadBalancerARN: lb,
|
||||
}
|
||||
|
||||
update, err := b.SDK.StackExists(ctx, project.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
operation := StackCreate
|
||||
operation := stackCreate
|
||||
if update {
|
||||
operation = StackUpdate
|
||||
operation = stackUpdate
|
||||
changeset, err := b.SDK.CreateChangeSet(ctx, project.Name, template, parameters)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -110,7 +110,7 @@ func (b *ecsAPIService) Up(ctx context.Context, options *cli.ProjectOptions) err
|
|||
|
||||
func (b ecsAPIService) GetVPC(ctx context.Context, project *types.Project) (string, error) {
|
||||
//check compose file for custom VPC selected
|
||||
if vpc, ok := project.Extensions[ExtensionVPC]; ok {
|
||||
if vpc, ok := project.Extensions[extensionVPC]; ok {
|
||||
vpcID := vpc.(string)
|
||||
ok, err := b.SDK.VpcExists(ctx, vpcID)
|
||||
if err != nil {
|
||||
|
@ -130,7 +130,7 @@ func (b ecsAPIService) GetVPC(ctx context.Context, project *types.Project) (stri
|
|||
|
||||
func (b ecsAPIService) GetLoadBalancer(ctx context.Context, project *types.Project) (string, error) {
|
||||
//check compose file for custom VPC selected
|
||||
if ext, ok := project.Extensions[ExtensionLB]; ok {
|
||||
if ext, ok := project.Extensions[extensionLB]; ok {
|
||||
lb := ext.(string)
|
||||
ok, err := b.SDK.LoadBalancerExists(ctx, lb)
|
||||
if err != nil {
|
||||
|
@ -146,7 +146,7 @@ func (b ecsAPIService) GetLoadBalancer(ctx context.Context, project *types.Proje
|
|||
|
||||
func (b ecsAPIService) GetCluster(ctx context.Context, project *types.Project) (string, error) {
|
||||
//check compose file for custom VPC selected
|
||||
if ext, ok := project.Extensions[ExtensionCluster]; ok {
|
||||
if ext, ok := project.Extensions[extensionCluster]; ok {
|
||||
cluster := ext.(string)
|
||||
ok, err := b.SDK.ClusterExists(ctx, cluster)
|
||||
if err != nil {
|
||||
|
|
10
ecs/wait.go
10
ecs/wait.go
|
@ -28,7 +28,7 @@ import (
|
|||
"github.com/aws/aws-sdk-go/aws"
|
||||
)
|
||||
|
||||
func (b *ecsAPIService) WaitStackCompletion(ctx context.Context, name string, operation int) error {
|
||||
func (b *ecsAPIService) WaitStackCompletion(ctx context.Context, name string, operation int) error { //nolint:gocyclo
|
||||
knownEvents := map[string]struct{}{}
|
||||
// progress writer
|
||||
w := progress.ContextWriter(ctx)
|
||||
|
@ -76,23 +76,23 @@ func (b *ecsAPIService) WaitStackCompletion(ctx context.Context, name string, op
|
|||
|
||||
switch status {
|
||||
case "CREATE_COMPLETE":
|
||||
if operation == StackCreate {
|
||||
if operation == stackCreate {
|
||||
progressStatus = progress.Done
|
||||
|
||||
}
|
||||
case "UPDATE_COMPLETE":
|
||||
if operation == StackUpdate {
|
||||
if operation == stackUpdate {
|
||||
progressStatus = progress.Done
|
||||
}
|
||||
case "DELETE_COMPLETE":
|
||||
if operation == StackDelete {
|
||||
if operation == stackDelete {
|
||||
progressStatus = progress.Done
|
||||
}
|
||||
default:
|
||||
if strings.HasSuffix(status, "_FAILED") {
|
||||
progressStatus = progress.Error
|
||||
if stackErr == nil {
|
||||
operation = StackDelete
|
||||
operation = stackDelete
|
||||
stackErr = fmt.Errorf(reason)
|
||||
}
|
||||
}
|
||||
|
|
22
ecs/x.go
22
ecs/x.go
|
@ -17,15 +17,15 @@
|
|||
package ecs
|
||||
|
||||
const (
|
||||
ExtensionSecurityGroup = "x-aws-securitygroup"
|
||||
ExtensionVPC = "x-aws-vpc"
|
||||
ExtensionPullCredentials = "x-aws-pull_credentials"
|
||||
ExtensionLB = "x-aws-loadbalancer"
|
||||
ExtensionCluster = "x-aws-cluster"
|
||||
ExtensionKeys = "x-aws-keys"
|
||||
ExtensionMinPercent = "x-aws-min_percent"
|
||||
ExtensionMaxPercent = "x-aws-max_percent"
|
||||
ExtensionRetention = "x-aws-logs_retention"
|
||||
ExtensionRole = "x-aws-role"
|
||||
ExtensionManagedPolicies = "x-aws-policies"
|
||||
extensionSecurityGroup = "x-aws-securitygroup"
|
||||
extensionVPC = "x-aws-vpc"
|
||||
extensionPullCredentials = "x-aws-pull_credentials"
|
||||
extensionLB = "x-aws-loadbalancer"
|
||||
extensionCluster = "x-aws-cluster"
|
||||
extensionKeys = "x-aws-keys"
|
||||
extensionMinPercent = "x-aws-min_percent"
|
||||
extensionMaxPercent = "x-aws-max_percent"
|
||||
extensionRetention = "x-aws-logs_retention"
|
||||
extensionRole = "x-aws-role"
|
||||
extensionManagedPolicies = "x-aws-policies"
|
||||
)
|
||||
|
|
|
@ -29,6 +29,7 @@ type Service interface {
|
|||
DeleteSecret(ctx context.Context, id string, recover bool) error
|
||||
}
|
||||
|
||||
// Secret hold sensitive data
|
||||
type Secret struct {
|
||||
ID string `json:"ID"`
|
||||
Name string `json:"Name"`
|
||||
|
@ -38,6 +39,7 @@ type Secret struct {
|
|||
password string
|
||||
}
|
||||
|
||||
// NewSecret builds a secret
|
||||
func NewSecret(name, username, password, description string) Secret {
|
||||
return Secret{
|
||||
Name: name,
|
||||
|
@ -47,6 +49,7 @@ func NewSecret(name, username, password, description string) Secret {
|
|||
}
|
||||
}
|
||||
|
||||
// ToJSON marshall a Secret into JSON string
|
||||
func (s Secret) ToJSON() (string, error) {
|
||||
b, err := json.MarshalIndent(&s, "", "\t")
|
||||
if err != nil {
|
||||
|
@ -55,6 +58,7 @@ func (s Secret) ToJSON() (string, error) {
|
|||
return string(b), nil
|
||||
}
|
||||
|
||||
// GetCredString marshall a Secret's sensitive data into JSON string
|
||||
func (s Secret) GetCredString() (string, error) {
|
||||
creds := map[string]string{
|
||||
"username": s.username,
|
||||
|
|
Loading…
Reference in New Issue