@@ -11,6 +11,7 @@ import (
1111 "github.com/aws/aws-sdk-go/aws/session"
1212 "github.com/aws/aws-sdk-go/service/ec2"
1313 "github.com/aws/aws-sdk-go/service/ecs"
14+ "github.com/codegangsta/cli"
1415 "io/ioutil"
1516 "net/http"
1617 "os"
@@ -65,6 +66,30 @@ func formatAwsError(err error) {
6566 }
6667}
6768
69+ // Verify that the ECS cluster exists.
70+ func verifyClusterExists (ecs_obj * ecs.ECS , cluster string ) {
71+ params := & ecs.DescribeClustersInput {
72+ Clusters : []* string {
73+ aws .String (cluster ),
74+ },
75+ }
76+ clusters , err := ecs_obj .DescribeClusters (params )
77+
78+ if err != nil {
79+ fmt .Println ("Cannot verify if ECS cluster exists:" )
80+ formatAwsError (err )
81+ os .Exit (1 )
82+ }
83+ if len (clusters .Clusters ) == 0 {
84+ fmt .Printf ("Error: ECS Cluster '%s' does not exist, cannot proceed.\n " , cluster )
85+ os .Exit (1 )
86+ }
87+ if len (clusters .Clusters ) != 1 {
88+ fmt .Printf ("Error: Unexpected number of ECS Clusters returned when searching for '%s'. Received: %+v\n " , cluster , clusters .Clusters )
89+ os .Exit (1 )
90+ }
91+ }
92+
6893// Verify that the ECS service exists.
6994func verifyServiceExists (ecs_obj * ecs.ECS , cluster string , service string ) {
7095 params := & ecs.DescribeServicesInput {
@@ -82,7 +107,7 @@ func verifyServiceExists(ecs_obj *ecs.ECS, cluster string, service string) {
82107 }
83108}
84109
85- func getContainerInstanceArnsForService (ecs_obj * ecs.ECS , cluster string , service string , local_container_instance_arn string ) []string {
110+ func getContainerInstanceArnsForService (ecs_obj * ecs.ECS , cluster string , service string , local_container_instance_arn string , debug bool ) []string {
86111 // Fetch a task list based on the service name.
87112 list_tasks_params := & ecs.ListTasksInput {
88113 Cluster : & cluster ,
@@ -137,7 +162,7 @@ func getContainerInstanceArnsForService(ecs_obj *ecs.ECS, cluster string, servic
137162 return result
138163}
139164
140- func getEc2InstanceIdsFromContainerInstances (ecs_obj * ecs.ECS , cluster string , container_instances []string ) []string {
165+ func getEc2InstanceIdsFromContainerInstances (ecs_obj * ecs.ECS , cluster string , container_instances []string , debug bool ) []string {
141166 params := & ecs.DescribeContainerInstancesInput {
142167 Cluster : aws .String (cluster ),
143168 ContainerInstances : aws .StringSlice (container_instances ),
@@ -173,7 +198,7 @@ func getEc2InstanceIdsFromContainerInstances(ecs_obj *ecs.ECS, cluster string, c
173198 return result
174199}
175200
176- func getEc2PrivateIpsFromInstanceIds (ec2_obj * ec2.EC2 , instance_ids []string ) []string {
201+ func getEc2PrivateIpsFromInstanceIds (ec2_obj * ec2.EC2 , instance_ids []string , debug bool ) []string {
177202 params := & ec2.DescribeInstancesInput {
178203 InstanceIds : aws .StringSlice (instance_ids ),
179204 }
@@ -214,22 +239,7 @@ func getEc2PrivateIpsFromInstanceIds(ec2_obj *ec2.EC2, instance_ids []string) []
214239 return result
215240}
216241
217- var debug bool
218-
219- func main () {
220- // Check that the ECS service name is passed in as an argument.
221- if len (os .Args ) != 2 && len (os .Args ) != 3 {
222- fmt .Println ("Usage:" , os .Args [0 ], "ecs_service_name [debug]" )
223- os .Exit (1 )
224- }
225- ecs_service := os .Args [1 ]
226- if len (os .Args ) == 3 && os .Args [2 ] == "debug" {
227- fmt .Println ("Debug Mode Enabled" )
228- debug = true
229- } else {
230- debug = false
231- }
232-
242+ func doMain (current_cluster bool , cluster_name string , ecs_service string , debug bool ) {
233243 // Get the metadata from the ECS agent on the local Docker host.
234244 local_ecs_agent_metadata := getEcsAgentMetadata ()
235245
@@ -242,17 +252,26 @@ func main() {
242252 os .Exit (1 )
243253 }
244254
245- // Discover the ECS cluster this EC2 instance belongs to, via local ECS agent.
246- ecs_cluster := local_ecs_agent_metadata .Cluster
247-
248255 // Reusable config session object for AWS services with current region attached.
256+ // TODOLATER: support other regions via a flag.
249257 aws_config_session := session .New (& aws.Config {Region : aws .String (region )})
250258
251259 // Create an ECS service object.
252260 ecs_obj := ecs .New (aws_config_session )
253261 // Create an EC2 service object.
254262 ec2_obj := ec2 .New (aws_config_session )
255263
264+ var ecs_cluster string
265+ if current_cluster == true {
266+ // Discover the ECS cluster this EC2 instance belongs to, via local ECS agent.
267+ ecs_cluster = local_ecs_agent_metadata .Cluster
268+ } else {
269+ // Use the user provided WAN cluster, for connecting to services in a different ECS Cluster.
270+ // First we verify the cluster exists before proceeding.
271+ verifyClusterExists (ecs_obj , cluster_name )
272+ ecs_cluster = cluster_name
273+ }
274+
256275 // Check that the service exists.
257276 verifyServiceExists (ecs_obj , ecs_cluster , ecs_service )
258277
@@ -261,22 +280,67 @@ func main() {
261280
262281 // Get all tasks for the given service, in this ECS cluster. We exclude the current container instance in the result,
263282 // as we only need to know about all other instances.
264- container_instances := getContainerInstanceArnsForService (ecs_obj , ecs_cluster , ecs_service , local_ecs_agent_metadata .ContainerInstanceArn )
283+ container_instances := getContainerInstanceArnsForService (ecs_obj , ecs_cluster , ecs_service , local_ecs_agent_metadata .ContainerInstanceArn , debug )
265284 if debug == true {
266285 fmt .Println ("container_instances:" , strings .Join (container_instances , "," ))
267286 }
268287
269288 // Get EC2 instance IDs for all container instances returned.
270- instance_ids := getEc2InstanceIdsFromContainerInstances (ecs_obj , ecs_cluster , container_instances )
289+ instance_ids := getEc2InstanceIdsFromContainerInstances (ecs_obj , ecs_cluster , container_instances , debug )
271290 if debug == true {
272291 fmt .Println ("instance_ids:" , strings .Join (instance_ids , "," ))
273292 }
274293
275294 // Get the private IP of the EC2 (container) instance running the ECS agent.
276- instance_private_ips := getEc2PrivateIpsFromInstanceIds (ec2_obj , instance_ids )
295+ instance_private_ips := getEc2PrivateIpsFromInstanceIds (ec2_obj , instance_ids , debug )
277296 if debug == true {
278297 fmt .Println ("instance_private_ips:" , strings .Join (instance_private_ips , "," ))
279298 }
280299
281300 fmt .Println (strings .Join (instance_private_ips , "," ))
282301}
302+
303+ func parseFlags (c * cli.Context ) (bool , string , string , bool ) {
304+ current_cluster := false
305+ cluster := ""
306+ if c .String ("c" ) == "" {
307+ current_cluster = true
308+ } else {
309+ cluster = c .String ("cluster" )
310+ }
311+ if c .String ("s" ) == "" {
312+ fmt .Printf ("Error: Service (-s) must not be empty. Cannot proceed.\n \n " )
313+ cli .ShowAppHelp (c )
314+ os .Exit (1 )
315+ }
316+ return current_cluster , cluster , c .String ("s" ), c .Bool ("d" )
317+ }
318+
319+ func main () {
320+ app := cli .NewApp ()
321+ app .Name = "ecs-discoverer"
322+ app .Version = "0.3.0"
323+ app .Usage = "Discovery tool for Private IPs of ECS EC2 Container Instances for a given Service/Cluster"
324+ app .Action = func (c * cli.Context ) {
325+ current_cluster , cluster , service , debug := parseFlags (c )
326+ doMain (current_cluster , cluster , service , debug )
327+ }
328+ app .Flags = []cli.Flag {
329+ cli.StringFlag {
330+ Name : "c" ,
331+ Value : "" ,
332+ Usage : "ECS Cluster Name (Optional - defaults to the ECS Cluster of this instance only)" ,
333+ },
334+ cli.BoolFlag {
335+ Name : "d" ,
336+ Usage : "Debug Mode" ,
337+ },
338+ cli.StringFlag {
339+ Name : "s" ,
340+ Value : "" ,
341+ Usage : "ECS Service Name (Required)" ,
342+ },
343+ }
344+
345+ app .Run (os .Args )
346+ }
0 commit comments