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