// Copyright 2015-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"). You may // not use this file except in compliance with the License. A copy of the // License is located at // // http://aws.amazon.com/apache2.0/ // // or in the "license" file accompanying this file. This file is distributed // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either // express or implied. See the License for the specific language governing // permissions and limitations under the License. // Package utils provides some utility functions. This is the kitchen sink. package utils import ( "fmt" "os" "strconv" "strings" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/service/ecs" ) const ( // ECSCLIResourcePrefix is prepended to the names of resources created through the ecs-cli ECSCLIResourcePrefix = "amazon-ecs-cli-setup-" containerNameParamKey = "containerName" containerPortParamKey = "containerPort" loadBalancerNameParamKey = "loadBalancerName" targetGroupArnParamKey = "targetGroupArn" ) // InSlice checks if the given string exists in the given slice: func InSlice(str string, list []string) bool { for _, s := range list { if s == str { return true } } return false } // GetHomeDir returns the file path of the user's home directory. func GetHomeDir() (string, error) { // Can not use user.Current https://github.com/golang/go/issues/6376 homeDir := os.Getenv("HOME") // *nix if homeDir == "" { // Windows homeDir = os.Getenv("USERPROFILE") } if homeDir == "" { return "", fmt.Errorf("user home directory not found") } return homeDir, nil } // EntityAlreadyExists returns true if an error indicates that the AWS resource already exists func EntityAlreadyExists(err error) bool { if awsErr, ok := err.(awserr.Error); ok { return awsErr.Code() == "EntityAlreadyExists" } return false } // ParseTags parses AWS Resource tags from the flag value // users specify tags in this format: key1=value1,key2=value2,key3=value3 func ParseTags(flagValue string, tags []*ecs.Tag) ([]*ecs.Tag, error) { keyValPairs := strings.Split(flagValue, ",") for _, kv := range keyValPairs { pair := strings.SplitN(kv, "=", 2) if len(pair) != 2 { return nil, fmt.Errorf("Tag input not formatted correctly: %s", kv) } tags = append(tags, &ecs.Tag{ Key: aws.String(pair[0]), Value: aws.String(pair[1]), }) } return tags, nil } // GetTagsMap parses AWS Resource tags from the flag value // users specify tags in this format: key1=value1,key2=value2,key3=value3 // Returns tags in the format used by the standalone resource tagging API func GetTagsMap(flagValue string) (map[string]*string, error) { tags := make(map[string]*string) keyValPairs := strings.Split(flagValue, ",") for _, pair := range keyValPairs { split := strings.SplitN(pair, "=", 2) if len(split) != 2 { return nil, fmt.Errorf("Tag input not formatted correctly: %s", pair) } tags[split[0]] = aws.String(split[1]) } return tags, nil } // GetPartition returns the partition for a given region // This is meant to be used when constructing ARNs func GetPartition(region string) string { if strings.HasPrefix(region, "cn") { return "aws-cn" } else if strings.HasPrefix(region, "us-gov") { return "aws-us-gov" } else { return "aws" } } // ParseLoadBalancers parses a StringSlice array into an array of load balancers struct // Input: ["targetGroupArn="...",containerName="...",containerPort=80","targetGroupArn="...",containerName="...",containerPort=40"] func ParseLoadBalancers(flagValues []string) ([]*ecs.LoadBalancer, error) { var list []*ecs.LoadBalancer for _, flagValue := range flagValues { m := make(map[string]string) validFlags := []string{containerNameParamKey, containerPortParamKey, loadBalancerNameParamKey, targetGroupArnParamKey} currentFlags := map[string]bool{ "containerName": false, "containerPort": false, } var elbv1, elbv2 bool keyValPairs := strings.Split(flagValue, ",") for _, kv := range keyValPairs { pair := strings.SplitN(kv, "=", -1) if len(pair) != 2 { return nil, fmt.Errorf("There is an (key=value) initialization error, please check to see if you are using = accordingly on %s", pair[0]) } key, val := pair[0], pair[1] if ok := contains(validFlags, key); !ok { return nil, fmt.Errorf("[--%s] is an invalid flag", key) } m[key] = val if key == "targetGroupArn" { elbv2 = true } else if key == "loadBalancerName" { elbv1 = true } if currentFlags[key] { return nil, fmt.Errorf("%s already exists", key) } currentFlags[key] = true } if elbv1 && elbv2 { return nil, fmt.Errorf("[--%s] and [--%s] flags cannot both be specified", "target-group-arn", "load-balancer-name") } for key, value := range currentFlags { if value == false { return nil, fmt.Errorf("--%s must be specified", key) } } containerPort, err := strconv.ParseInt(m["containerPort"], 10, 64) if err != nil { return nil, fmt.Errorf("Fail to parse container port %s for container %s", m["containerPort"], m["containerName"]) } if elbv2 { list = append(list, &ecs.LoadBalancer{ TargetGroupArn: aws.String(m["targetGroupArn"]), ContainerName: aws.String(m["containerName"]), ContainerPort: aws.Int64((containerPort)), }) } else if elbv1 { list = append(list, &ecs.LoadBalancer{ LoadBalancerName: aws.String(m["loadBalancerName"]), ContainerName: aws.String(m["containerName"]), ContainerPort: aws.Int64((containerPort)), }) } else { return nil, fmt.Errorf("Target Group Arn or Load Balancer Name cannot be blank") } } return list, nil } func contains(s []string, e string) bool { for _, a := range s { if a == e { return true } } return false }