Skip to content

Commit

Permalink
add init --task-definition flag.
Browse files Browse the repository at this point in the history
Enables to generate task definition and config file only, without
service.
  • Loading branch information
fujiwara committed Jul 26, 2023
1 parent 543927b commit 404f490
Showing 1 changed file with 98 additions and 57 deletions.
155 changes: 98 additions & 57 deletions init.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ var CreateFileMode = os.FileMode(0644)
type InitOption struct {
Region string `help:"AWS region" env:"AWS_REGION" default:""`
Cluster string `help:"ECS cluster name" default:"default"`
Service string `help:"ECS service name" required:""`
Service string `help:"ECS service name" required:"" xor:"FROM"`
TaskDefinition string `help:"ECS task definition name:revision" required:"" xor:"FROM"`
TaskDefinitionPath string `help:"path to output task definition file" default:"ecs-task-def.json"`
ServiceDefinitionPath string `help:"path to output service definition file" default:"ecs-service-def.json"`
ConfigFilePath string
Expand Down Expand Up @@ -51,6 +52,15 @@ var (

func (d *App) Init(ctx context.Context, opt InitOption) error {
conf := d.config
var tdOnly bool
if opt.Service != "" {
tdOnly = false
} else if opt.TaskDefinition != "" {
tdOnly = true
} else {
return fmt.Errorf("--service or --task-definition is required")
}

d.LogJSON(opt)
if opt.Jsonnet {
if ext := filepath.Ext(conf.ServiceDefinitionPath); ext == jsonExt {
Expand All @@ -66,22 +76,85 @@ func (d *App) Init(ctx context.Context, opt InitOption) error {
if err := conf.Restrict(ctx); err != nil {
return err
}
var err error
var sv *Service
var tdArn string
if tdOnly {
tdArn = opt.TaskDefinition
} else {
sv, tdArn, err = d.initServiceDefinition(ctx, opt)
if err != nil {
return err
}
}
td, err := d.initTaskDefinition(ctx, opt, tdArn)
if err != nil {
return err
}
if err := d.initConfigurationFile(ctx, opt, sv, td); err != nil {
return err
}
return nil
}

func (d *App) initConfigurationFile(ctx context.Context, opt InitOption, sv *Service, td *TaskDefinitionInput) error {
conf := d.config
if sv == nil {
// tdOnly
conf.Service = ""
conf.ServiceDefinitionPath = ""
} else if sv.isCodeDeploy() {
info, err := d.findDeploymentInfo(ctx)
if err != nil {
Log("[WARNING] failed to find CodeDeploy deployment info: %s", err)
Log("[WARNING] you need to set config.codedeploy section manually")
} else {
conf.CodeDeploy = &ConfigCodeDeploy{
ApplicationName: *info.ApplicationName,
DeploymentGroupName: *info.DeploymentGroupName,
}
}
}
{
var b []byte
var err error
if opt.Jsonnet {
b, err = json.MarshalIndent(conf, "", " ")
if err != nil {
return fmt.Errorf("unable to marshal config to JSON: %w", err)
}
out, err := formatter.Format(opt.ConfigFilePath, string(b), formatter.DefaultOptions())
if err != nil {
return fmt.Errorf("unable to format config as Jsonnet: %w", err)
}
b = []byte(out)
} else {
b, err = yaml.Marshal(conf)
if err != nil {
return fmt.Errorf("unable to marshal config to YAML: %w", err)
}
}
d.Log("save config to %s", opt.ConfigFilePath)
if err := d.saveFile(opt.ConfigFilePath, b, CreateFileMode, opt.ForceOverwrite); err != nil {
return err
}
}
return nil
}

func (d *App) initServiceDefinition(ctx context.Context, opt InitOption) (*Service, string, error) {
conf := d.config
out, err := d.ecs.DescribeServices(ctx, d.DescribeServicesInput())
if err != nil {
return fmt.Errorf("failed to describe service: %w", err)
return nil, "", fmt.Errorf("failed to describe service: %w", err)
}
if len(out.Services) == 0 {
return ErrNotFound("service is not found")
return nil, "", ErrNotFound("service is not found")
}

sv, err := d.newServiceFromTypes(ctx, out.Services[0])
if err != nil {
return fmt.Errorf("failed to describe service: %w", err)
}
td, err := d.DescribeTaskDefinition(ctx, *sv.TaskDefinition)
if err != nil {
return err
return nil, "", fmt.Errorf("failed to describe service: %w", err)
}

if long, _ := isLongArnFormat(*sv.ServiceArn); long {
Expand All @@ -90,84 +163,52 @@ func (d *App) Init(ctx context.Context, opt InitOption) error {
ResourceArn: sv.ServiceArn,
})
if err != nil {
return fmt.Errorf("failed to list tags for service: %w", err)
return nil, "", fmt.Errorf("failed to list tags for service: %w", err)
}
sv.Tags = lt.Tags
}

// service-def
tdArn := *sv.TaskDefinition
treatmentServiceDefinition(sv)
if b, err := MarshalJSONForAPI(sv); err != nil {
return fmt.Errorf("unable to marshal service definition to JSON: %w", err)
return nil, "", fmt.Errorf("unable to marshal service definition to JSON: %w", err)
} else {
if opt.Jsonnet {
out, err := formatter.Format(conf.ServiceDefinitionPath, string(b), formatter.DefaultOptions())
if err != nil {
return fmt.Errorf("unable to format service definition as Jsonnet: %w", err)
return nil, "", fmt.Errorf("unable to format service definition as Jsonnet: %w", err)
}
b = []byte(out)
}
d.Log("save service definition to %s", conf.ServiceDefinitionPath)
if err := d.saveFile(conf.ServiceDefinitionPath, b, CreateFileMode, opt.ForceOverwrite); err != nil {
return err
return nil, "", err
}
}
return sv, tdArn, nil
}

// task-def
func (d *App) initTaskDefinition(ctx context.Context, opt InitOption, tdArn string) (*TaskDefinitionInput, error) {
conf := d.config
td, err := d.DescribeTaskDefinition(ctx, tdArn)
if err != nil {
return nil, err
}
if b, err := MarshalJSONForAPI(td); err != nil {
return fmt.Errorf("unable to marshal task definition to JSON: %w", err)
return nil, fmt.Errorf("unable to marshal task definition to JSON: %w", err)
} else {
if opt.Jsonnet {
out, err := formatter.Format(conf.TaskDefinitionPath, string(b), formatter.DefaultOptions())
if err != nil {
return fmt.Errorf("unable to format task definition as Jsonnet: %w", err)
return nil, fmt.Errorf("unable to format task definition as Jsonnet: %w", err)
}
b = []byte(out)
}
d.Log("save task definition to %s", conf.TaskDefinitionPath)
if err := d.saveFile(conf.TaskDefinitionPath, b, CreateFileMode, opt.ForceOverwrite); err != nil {
return err
}
}

// config
if sv.isCodeDeploy() {
info, err := d.findDeploymentInfo(ctx)
if err != nil {
Log("[WARNING] failed to find CodeDeploy deployment info: %s", err)
Log("[WARNING] you need to set config.codedeploy section manually")
} else {
conf.CodeDeploy = &ConfigCodeDeploy{
ApplicationName: *info.ApplicationName,
DeploymentGroupName: *info.DeploymentGroupName,
}
return nil, err
}
}
{
var b []byte
var err error
if opt.Jsonnet {
b, err = json.MarshalIndent(conf, "", " ")
if err != nil {
return fmt.Errorf("unable to marshal config to JSON: %w", err)
}
out, err := formatter.Format(opt.ConfigFilePath, string(b), formatter.DefaultOptions())
if err != nil {
return fmt.Errorf("unable to format config as Jsonnet: %w", err)
}
b = []byte(out)
} else {
b, err = yaml.Marshal(conf)
if err != nil {
return fmt.Errorf("unable to marshal config to YAML: %w", err)
}
}
d.Log("save config to %s", opt.ConfigFilePath)
if err := d.saveFile(opt.ConfigFilePath, b, CreateFileMode, opt.ForceOverwrite); err != nil {
return err
}
}
return nil
return td, nil
}

func treatmentServiceDefinition(sv *Service) {
Expand Down

0 comments on commit 404f490

Please sign in to comment.