// CreateVolume creates a new EBS Volume func CreateVolume(class, name, az string, dryRun bool) error { // --dry-run flag if dryRun { terminal.Information("--dry-run flag is set, not making any actual changes!") } // Class Config volCfg, err := config.LoadVolumeClass(class) if err != nil { return err } terminal.Information("Found Volume Class Configuration for [" + class + "]!") // Verify the az input azs, errs := regions.GetAZs() if errs != nil { return errors.New("Error Verifying Availability Zone input") } if !azs.ValidAZ(az) { return cli.NewExitError("Availability Zone ["+az+"] is Invalid!", 1) } terminal.Information("Found Availability Zone [" + az + "]!") region := azs.GetRegion(az) // Get the latest snapshot latestSnapshot, err := GetLatestSnapshotByTag(region, "Class", volCfg.Snapshot) if err != nil { return err } terminal.Information("Found Snapshot [" + latestSnapshot.SnapshotID + "] with class [" + latestSnapshot.Class + "] created [" + latestSnapshot.CreatedHuman + "]!") svc := ec2.New(session.New(&aws.Config{Region: aws.String(region)})) params := &ec2.CreateVolumeInput{ AvailabilityZone: aws.String(az), DryRun: aws.Bool(dryRun), Size: aws.Int64(int64(volCfg.VolumeSize)), SnapshotId: aws.String(latestSnapshot.SnapshotID), VolumeType: aws.String(volCfg.VolumeType), //Encrypted: aws.Bool(true), //Iops: aws.Int64(1), //KmsKeyId: aws.String("String"), } createVolumeResp, err := svc.CreateVolume(params) if err != nil { if awsErr, ok := err.(awserr.Error); ok { return errors.New(awsErr.Message()) } return err } terminal.Information("Created Volume [" + *createVolumeResp.VolumeId + "] named [" + name + "] in [" + region + "]!") // Add Tags err = SetEc2NameAndClassTags(createVolumeResp.VolumeId, name, class, region) if err != nil { if awsErr, ok := err.(awserr.Error); ok { return errors.New(awsErr.Message()) } return err } return nil }
// Private function without the confirmation terminal prompts func updateAutoScaleGroups(asgList *AutoScaleGroups, version string, double, dryRun bool) (err error) { for _, asg := range *asgList { // Get the ASG class config cfg, err := config.LoadAutoscalingGroupClass(asg.Class) if err != nil { return err } terminal.Information("Found Autoscaling group class configuration for [" + asg.Class + "]") // Get the Launch Configuration class config launchConfigurationCfg, err := config.LoadLaunchConfigurationClass(cfg.LaunchConfigurationClass) if err != nil { return err } terminal.Information("Found Launch Configuration class configuration for [" + cfg.LaunchConfigurationClass + "]") // Get the AZs azs, errs := regions.GetAZs() if errs != nil { return errors.New("Error gathering region list") } for region, regionAZs := range azs.GetRegionMap(cfg.AvailabilityZones) { // TODO check if exists yet ? // Verify that the latest Launch Configuration is available in this region lcName := GetLaunchConfigurationName(region, cfg.LaunchConfigurationClass, launchConfigurationCfg.Version) if lcName == "" { return fmt.Errorf("Launch Configuration [%s] version [%d] is not available in [%s]!", cfg.LaunchConfigurationClass, launchConfigurationCfg.Version, region) } terminal.Information(fmt.Sprintf("Found latest Launch Configuration [%s] version [%d] in [%s]", cfg.LaunchConfigurationClass, launchConfigurationCfg.Version, asg.Region)) svc := autoscaling.New(session.New(&aws.Config{Region: aws.String(region)})) params := &autoscaling.UpdateAutoScalingGroupInput{ AutoScalingGroupName: aws.String(asg.Name), AvailabilityZones: []*string{ aws.String("XmlStringMaxLen255"), // Required // More values... }, DefaultCooldown: aws.Int64(int64(cfg.DefaultCooldown)), DesiredCapacity: aws.Int64(int64(cfg.DesiredCapacity)), HealthCheckGracePeriod: aws.Int64(int64(cfg.HealthCheckGracePeriod)), HealthCheckType: aws.String(cfg.HealthCheckType), LaunchConfigurationName: aws.String(lcName), MaxSize: aws.Int64(int64(asg.MaxSize)), MinSize: aws.Int64(int64(asg.MinSize)), //NewInstancesProtectedFromScaleIn: aws.Bool(true), // TODO? //PlacementGroup: aws.String("XmlStringMaxLen255"), // TODO } subList := new(Subnets) var vpcZones []string if cfg.SubnetClass != "" { err := GetRegionSubnets(region, subList, "") if err != nil { return err } } // Set the AZs for _, az := range regionAZs { if !azs.ValidAZ(az) { return cli.NewExitError("Availability Zone ["+az+"] is Invalid!", 1) } terminal.Information("Found Availability Zone [" + az + "]!") params.AvailabilityZones = append(params.AvailabilityZones, aws.String(az)) for _, sub := range *subList { if sub.Class == cfg.SubnetClass && sub.AvailabilityZone == az { vpcZones = append(vpcZones, sub.SubnetID) } } } // Set the VPCZoneIdentifier (SubnetIds seperated by comma) params.VPCZoneIdentifier = aws.String(strings.Join(vpcZones, ", ")) // Set the Termination Policies for _, terminationPolicy := range cfg.LoadBalancerNames { params.TerminationPolicies = append(params.TerminationPolicies, aws.String(terminationPolicy)) // ?? } // Update it! if !dryRun { _, err := svc.UpdateAutoScalingGroup(params) if err != nil { if awsErr, ok := err.(awserr.Error); ok { return errors.New(awsErr.Message()) } return err } terminal.Information("Updated AutoScaling Group [" + asg.Name + "] in [" + region + "]!") } else { fmt.Println(params) } } } return nil }
// CreateAutoScaleGroups creates a new AutoScale Group of the given class func CreateAutoScaleGroups(class string, dryRun bool) (err error) { // --dry-run flag if dryRun { terminal.Information("--dry-run flag is set, not making any actual changes!") } // Verify the asg config class input cfg, err := config.LoadAutoscalingGroupClass(class) if err != nil { return err } terminal.Information("Found Autoscaling group class configuration for [" + class + "]") // Verify the launchconfig class input launchConfigurationCfg, err := config.LoadLaunchConfigurationClass(cfg.LaunchConfigurationClass) if err != nil { return err } terminal.Information("Found Launch Configuration class configuration for [" + cfg.LaunchConfigurationClass + "]") // Get the AZs azs, errs := regions.GetAZs() if errs != nil { return errors.New("Error gathering region list") } for region, regionAZs := range azs.GetRegionMap(cfg.AvailabilityZones) { // Verify that the latest Launch Configuration is available in this region lcName := GetLaunchConfigurationName(region, cfg.LaunchConfigurationClass, launchConfigurationCfg.Version) if lcName == "" { return fmt.Errorf("Launch Configuration [%s] version [%d] is not available in [%s]!", cfg.LaunchConfigurationClass, launchConfigurationCfg.Version, region) } terminal.Information(fmt.Sprintf("Found latest Launch Configuration [%s] version [%d] in [%s]", cfg.LaunchConfigurationClass, launchConfigurationCfg.Version, region)) svc := autoscaling.New(session.New(&aws.Config{Region: aws.String(region)})) params := &autoscaling.CreateAutoScalingGroupInput{ AutoScalingGroupName: aws.String(class), MaxSize: aws.Int64(int64(cfg.MaxSize)), MinSize: aws.Int64(int64(cfg.MinSize)), DefaultCooldown: aws.Int64(int64(cfg.DefaultCooldown)), DesiredCapacity: aws.Int64(int64(cfg.DesiredCapacity)), HealthCheckGracePeriod: aws.Int64(int64(cfg.HealthCheckGracePeriod)), HealthCheckType: aws.String(cfg.HealthCheckType), LaunchConfigurationName: aws.String(lcName), // InstanceId: aws.String("XmlStringMaxLen19"), // TODO ? // NewInstancesProtectedFromScaleIn: aws.Bool(true), // TODO ? // PlacementGroup: aws.String("XmlStringMaxLen255"), // TODO ? Tags: []*autoscaling.Tag{ { // Name Key: aws.String("Name"), PropagateAtLaunch: aws.Bool(true), ResourceId: aws.String(class), ResourceType: aws.String("auto-scaling-group"), Value: aws.String(lcName), }, { // Class Key: aws.String("Class"), PropagateAtLaunch: aws.Bool(true), ResourceId: aws.String(class), ResourceType: aws.String("auto-scaling-group"), Value: aws.String(class), }, }, } subList := new(Subnets) var vpcZones []string if cfg.SubnetClass != "" { err := GetRegionSubnets(region, subList, "") if err != nil { return err } } // Set the AZs for _, az := range regionAZs { if !azs.ValidAZ(az) { return cli.NewExitError("Availability Zone ["+az+"] is Invalid!", 1) } terminal.Information("Found Availability Zone [" + az + "]!") params.AvailabilityZones = append(params.AvailabilityZones, aws.String(az)) for _, sub := range *subList { if sub.Class == cfg.SubnetClass && sub.AvailabilityZone == az { vpcZones = append(vpcZones, sub.SubnetID) } } } // Set the VPCZoneIdentifier (SubnetIds seperated by comma) params.VPCZoneIdentifier = aws.String(strings.Join(vpcZones, ", ")) // Set the Load Balancers for _, elb := range cfg.LoadBalancerNames { params.LoadBalancerNames = append(params.LoadBalancerNames, aws.String(elb)) } // Set the Termination Policies for _, terminationPolicy := range cfg.LoadBalancerNames { params.TerminationPolicies = append(params.TerminationPolicies, aws.String(terminationPolicy)) // ?? } // Create it! if !dryRun { _, err := svc.CreateAutoScalingGroup(params) if err != nil { if awsErr, ok := err.(awserr.Error); ok { return errors.New(awsErr.Message()) } return err } terminal.Information("Created AutoScaling Group [" + aws.StringValue(params.AutoScalingGroupName) + "] in [" + region + "]!") terminal.Information("Done!") } else { fmt.Println(params) } } return nil }
// CreateSubnet creates a new VPC Subnet func CreateSubnet(class, name, vpc, ip, az string, dryRun bool) error { // --dry-run flag if dryRun { terminal.Information("--dry-run flag is set, not making any actual changes!") } // Class Config cfg, err := config.LoadSubnetClass(class) if err != nil { return err } terminal.Information("Found Subnet Class Configuration for [" + class + "]!") // Verify the az input azs, errs := regions.GetAZs() if errs != nil { return errors.New("Error Verifying Availability Zone input") } if !azs.ValidAZ(az) { return cli.NewExitError("Availability Zone ["+az+"] is Invalid!", 1) } terminal.Information("Found Availability Zone [" + az + "]!") region := azs.GetRegion(az) // Verify the vpc input targetVpc, err := GetVpcByTag(region, "Class", vpc) if err != nil { return err } terminal.Information("Found [" + targetVpc.Name + "] VPC [" + targetVpc.VpcID + "]!") // Create the Subnet svc := ec2.New(session.New(&aws.Config{Region: aws.String(region)})) params := &ec2.CreateSubnetInput{ CidrBlock: aws.String(ip + cfg.CIDR), VpcId: aws.String(targetVpc.VpcID), DryRun: aws.Bool(dryRun), AvailabilityZone: aws.String(az), } createSubnetResp, err := svc.CreateSubnet(params) if err != nil { return err } terminal.Information("Created Subnet [" + *createSubnetResp.Subnet.SubnetId + "] named [" + name + "] in [" + *createSubnetResp.Subnet.AvailabilityZone + "]!") // Add Tags err = SetEc2NameAndClassTags(createSubnetResp.Subnet.SubnetId, name, class, region) if err != nil { return err } terminal.Information("Done!") return nil }
// Main Function ////////////////.......... func main() { // Check for Creds found := aws.CheckCreds() if !found { return } // Check for the awsm db if !config.CheckDB() { create := terminal.BoxPromptBool("No awsm database found!", "Do you want to create one now?") if !create { terminal.Information("Ok then, maybe next time.. ") return } err := config.CreateAwsmDatabase() if err != nil { terminal.ErrorLine(err.Error()) return } } var dryRun bool var force bool var double bool // optional flag when updating an auto-scale group app := cli.NewApp() app.Name = "awsm" app.Usage = "AWSM Interface" app.Version = "1.0" app.Author = "Ahmad A" app.Email = "*****@*****.**" app.EnableBashCompletion = true app.Flags = []cli.Flag{ cli.BoolFlag{ Name: "dry-run", Destination: &dryRun, Usage: "dry-run (Don't make any real changes)", }, } app.Commands = []cli.Command{ { Name: "api", Usage: "Start the awsm api server", Action: func(c *cli.Context) error { api.StartAPI() return nil }, }, /* { Name: "dashboard", Usage: "Launch the awsm Dashboard GUI", Flags: []cli.Flag{ cli.BoolFlag{ Name: "dev-mode", Destination: &dryRun, Usage: "dev-mode (Don't reopen dashboard on each restart)", }, }, Action: func(c *cli.Context) error { aws.RunDashboard(c.Bool("dev-mode")) return nil }, }, */ { Name: "attachVolume", Usage: "Attach an AWS EBS Volume to an EC2 Instance", Arguments: []cli.Argument{ cli.Argument{ Name: "volume", Description: "The volume to attach", Optional: false, }, cli.Argument{ Name: "instance", Description: "The instance to attach the volume to", Optional: false, }, }, Action: func(c *cli.Context) error { err := aws.AttachVolume(c.NamedArg("volume"), c.NamedArg("instance"), dryRun) if err != nil { terminal.ErrorLine(err.Error()) } return nil }, }, { Name: "installKeyPair", Usage: "Installs a Key Pair locally", Arguments: []cli.Argument{ cli.Argument{ Name: "class", Description: "The class of the key pair", Optional: false, }, }, Action: func(c *cli.Context) error { err := aws.InstallKeyPair(c.NamedArg("class"), dryRun) if err != nil { terminal.ErrorLine(err.Error()) } return nil }, }, { Name: "copyImage", Usage: "Copy an AWS Machine Image to another region", Arguments: []cli.Argument{ cli.Argument{ Name: "search", Description: "The image to copy", Optional: false, }, cli.Argument{ Name: "region", Description: "The region to copy the image to", Optional: false, }, }, Action: func(c *cli.Context) error { err := aws.CopyImage(c.NamedArg("search"), c.NamedArg("region"), dryRun) if err != nil { terminal.ErrorLine(err.Error()) } return nil }, }, { Name: "copySnapshot", Usage: "Copy an AWS EBS Snapshot to another region", Arguments: []cli.Argument{ cli.Argument{ Name: "search", Description: "The snapshot to copy", Optional: false, }, cli.Argument{ Name: "region", Description: "The region to copy the snapshot to", Optional: false, }, }, Action: func(c *cli.Context) error { err := aws.CopySnapshot(c.NamedArg("search"), c.NamedArg("region"), dryRun) if err != nil { terminal.ErrorLine(err.Error()) } return nil }, }, { Name: "createAddress", Usage: "Create an AWS Elastic IP Address", Arguments: []cli.Argument{ cli.Argument{ Name: "region", Description: "The region to create the elastic ip in", Optional: false, }, cli.Argument{ Name: "domain", Description: "The domain to create the elastic ip in (classic or vpc)", Optional: false, }, }, Action: func(c *cli.Context) error { err := aws.CreateAddress(c.NamedArg("region"), c.NamedArg("domain"), dryRun) if err != nil { terminal.ErrorLine(err.Error()) } return nil }, }, { Name: "createAutoScaleGroups", Usage: "Create an AWS AutoScaling Groups", Arguments: []cli.Argument{ cli.Argument{ Name: "class", Description: "The class of the autoscaling groups to create", Optional: false, }, }, Action: func(c *cli.Context) error { err := aws.CreateAutoScaleGroups(c.NamedArg("class"), dryRun) if err != nil { terminal.ErrorLine(err.Error()) } return nil }, }, { Name: "createIAMUser", Usage: "Create an IAM User", Arguments: []cli.Argument{ cli.Argument{ Name: "username", Description: "The username for this IAM user", Optional: false, }, cli.Argument{ Name: "path", Description: "The optional path for the user", Optional: true, }, }, Action: func(c *cli.Context) error { err := aws.CreateIAMUser(c.NamedArg("username"), c.NamedArg("path")) if err != nil { terminal.ErrorLine(err.Error()) } return nil }, }, { Name: "createImage", Usage: "Create an AWS Machine Image from a running instance", Arguments: []cli.Argument{ cli.Argument{ Name: "search", Description: "The AMI to create an image of", Optional: false, }, cli.Argument{ Name: "class", Description: "The class of the new image", Optional: false, }, cli.Argument{ Name: "name", Description: "The name of the new image", Optional: false, }, }, Action: func(c *cli.Context) error { err := aws.CreateImage(c.NamedArg("search"), c.NamedArg("class"), c.NamedArg("name"), dryRun) if err != nil { terminal.ErrorLine(err.Error()) } return nil }, }, { Name: "createLaunchConfigurations", Usage: "Create an AWS AutoScaling Launch Configurations", Arguments: []cli.Argument{ cli.Argument{ Name: "class", Description: "The class of the launch configuration groups to create", Optional: false, }, }, Action: func(c *cli.Context) error { err := aws.CreateLaunchConfigurations(c.NamedArg("class"), dryRun) if err != nil { terminal.ErrorLine(err.Error()) } return nil }, }, { Name: "createKeyPair", Usage: "Create an AWS Key Pair in the specified region", Arguments: []cli.Argument{ cli.Argument{ Name: "class", Description: "The class of the key pair", Optional: false, }, cli.Argument{ Name: "region", Description: "The region to create the keypair in", Optional: false, }, }, Action: func(c *cli.Context) error { err := aws.CreateKeyPair(c.NamedArg("class"), c.NamedArg("region"), dryRun) if err != nil { terminal.ErrorLine(err.Error()) } return nil }, }, { Name: "createSimpleDBDomain", Usage: "Create an AWS SimpleDB Domain", Arguments: []cli.Argument{ cli.Argument{ Name: "domain", Description: "The domain of the db", Optional: false, }, cli.Argument{ Name: "region", Description: "The region of the db", Optional: false, }, }, Action: func(c *cli.Context) error { err := aws.CreateSimpleDBDomain(c.NamedArg("domain"), c.NamedArg("region")) if err != nil { terminal.ErrorLine(err.Error()) } return nil }, }, { Name: "createSnapshot", Usage: "Create an AWS EBS snapshot of a volume", Arguments: []cli.Argument{ cli.Argument{ Name: "search", Description: "The volume to create a snapshot from", Optional: false, }, cli.Argument{ Name: "class", Description: "The class of the new snapshot", Optional: false, }, cli.Argument{ Name: "name", Description: "The name of the new snapshot", Optional: false, }, }, Action: func(c *cli.Context) error { err := aws.CreateSnapshot(c.NamedArg("search"), c.NamedArg("class"), c.NamedArg("name"), dryRun) if err != nil { terminal.ErrorLine(err.Error()) } return nil }, }, { Name: "createVolume", Usage: "Create an AWS EBS volume", Arguments: []cli.Argument{ cli.Argument{ Name: "class", Description: "The class of the new volume", Optional: false, }, cli.Argument{ Name: "name", Description: "The name of the new volume", Optional: false, }, cli.Argument{ Name: "az", Description: "The Availability Zone to create the volume in", Optional: false, }, }, Action: func(c *cli.Context) error { err := aws.CreateVolume(c.NamedArg("class"), c.NamedArg("name"), c.NamedArg("az"), dryRun) if err != nil { terminal.ErrorLine(err.Error()) } return nil }, }, { Name: "createVpc", Usage: "Create an AWS VPC", Arguments: []cli.Argument{ cli.Argument{ Name: "class", Description: "The class of VPC to create", Optional: false, }, cli.Argument{ Name: "name", Description: "The name of the VPC", Optional: false, }, cli.Argument{ Name: "ip", Description: "The IP address of this VPC (not including CIDR)", Optional: false, }, cli.Argument{ Name: "region", Description: "The region to create the VPC in", Optional: false, }, }, Action: func(c *cli.Context) error { err := aws.CreateVpc(c.NamedArg("class"), c.NamedArg("name"), c.NamedArg("ip"), c.NamedArg("region"), dryRun) if err != nil { terminal.ErrorLine(err.Error()) } return nil }, }, { Name: "createSubnet", Usage: "Create an AWS VPC Subnet", Arguments: []cli.Argument{ cli.Argument{ Name: "class", Description: "The class of Subnet to create", Optional: false, }, cli.Argument{ Name: "name", Description: "The name of the Subnet", Optional: false, }, cli.Argument{ Name: "vpc", Description: "The VPC to create the Subnet in", Optional: false, }, cli.Argument{ Name: "ip", Description: "The IP address of this Subnet (not including CIDR)", Optional: false, }, cli.Argument{ Name: "az", Description: "The Availability Zone to create the Subnet in", Optional: true, }, }, Action: func(c *cli.Context) error { err := aws.CreateSubnet(c.NamedArg("class"), c.NamedArg("name"), c.NamedArg("vpc"), c.NamedArg("ip"), c.NamedArg("az"), dryRun) if err != nil { terminal.ErrorLine(err.Error()) } return nil }, }, { Name: "deleteAddresses", Usage: "Delete AWS Elastic IP Addresses", Arguments: []cli.Argument{ cli.Argument{ Name: "search", Description: "The search term for the elastic ip to delete", Optional: false, }, cli.Argument{ Name: "region", Description: "The region to delete the elastic ip from", Optional: true, }, }, Action: func(c *cli.Context) error { err := aws.DeleteAddresses(c.NamedArg("search"), c.NamedArg("region"), dryRun) if err != nil { terminal.ErrorLine(err.Error()) } return nil }, }, { Name: "deleteAutoScaleGroups", Usage: "Delete AWS AutoScaling Groups", Arguments: []cli.Argument{ cli.Argument{ Name: "search", Description: "The search term for the autoscaling group to delete", Optional: false, }, cli.Argument{ Name: "region", Description: "The region to delete the autoscaling group from", Optional: true, }, }, Flags: []cli.Flag{ cli.BoolFlag{ Name: "force", Destination: &force, Usage: "force (Force deletes all instances and lifecycle actions)", }, }, Action: func(c *cli.Context) error { err := aws.DeleteAutoScaleGroups(c.NamedArg("search"), c.NamedArg("region"), force, dryRun) if err != nil { terminal.ErrorLine(err.Error()) } return nil }, }, { Name: "deleteIAMUsers", Usage: "Delete AWS IAM Users", Arguments: []cli.Argument{ cli.Argument{ Name: "search", Description: "The search term for iam username", Optional: false, }, }, Action: func(c *cli.Context) error { err := aws.DeleteIAMUsers(c.NamedArg("search")) if err != nil { terminal.ErrorLine(err.Error()) } return nil }, }, { Name: "deleteImages", Usage: "Delete AWS Machine Images", Arguments: []cli.Argument{ cli.Argument{ Name: "search", Description: "The search term for images to delete", Optional: false, }, cli.Argument{ Name: "region", Description: "The region of the images (optional)", Optional: true, }, }, Action: func(c *cli.Context) error { err := aws.DeleteImages(c.NamedArg("search"), c.NamedArg("region"), dryRun) if err != nil { terminal.ErrorLine(err.Error()) } return nil }, }, { Name: "deleteKeyPairs", Usage: "Delete AWS KeyPairs", Arguments: []cli.Argument{ cli.Argument{ Name: "name", Description: "The name of the AWS KeyPair to delete", Optional: false, }, }, Action: func(c *cli.Context) error { errs := aws.DeleteKeyPairs(c.NamedArg("name"), dryRun) if errs != nil { return cli.NewExitError("Errors Deleting KeyPair!", 1) } return nil }, }, { Name: "deleteLaunchConfigurations", Usage: "Delete AWS AutoScaling Launch Configurations", Arguments: []cli.Argument{ cli.Argument{ Name: "search", Description: "The search term for the launch configuration to delete", Optional: false, }, cli.Argument{ Name: "region", Description: "The region to delete the launch configuration from", Optional: true, }, }, Action: func(c *cli.Context) error { err := aws.DeleteLaunchConfigurations(c.NamedArg("search"), c.NamedArg("region"), dryRun) if err != nil { terminal.ErrorLine(err.Error()) } return nil }, }, { Name: "deleteSecurityGroups", Usage: "Delete AWS Security Groups", Arguments: []cli.Argument{ cli.Argument{ Name: "search", Description: "The search term for the security group to delete", Optional: false, }, cli.Argument{ Name: "region", Description: "The region to delete the security group from", Optional: true, }, }, Action: func(c *cli.Context) error { err := aws.DeleteSecurityGroups(c.NamedArg("search"), c.NamedArg("region"), dryRun) if err != nil { terminal.ErrorLine(err.Error()) } return nil }, }, { Name: "deleteSnapshots", Usage: "Delete AWS EBS Snapshots", Arguments: []cli.Argument{ cli.Argument{ Name: "search", Description: "The search term for snapshots to delete", Optional: false, }, cli.Argument{ Name: "region", Description: "The region of the snapshots (optional)", Optional: true, }, }, Action: func(c *cli.Context) error { err := aws.DeleteSnapshots(c.NamedArg("search"), c.NamedArg("region"), dryRun) if err != nil { terminal.ErrorLine(err.Error()) } return nil }, }, { Name: "deleteSimpleDBDomains", Usage: "Delete AWS SimpleDB Domains", Arguments: []cli.Argument{ cli.Argument{ Name: "search", Description: "The search term for simpleDB domain to delete", Optional: false, }, cli.Argument{ Name: "region", Description: "The region of the DBs (optional)", Optional: true, }, }, Action: func(c *cli.Context) error { err := aws.DeleteSimpleDBDomains(c.NamedArg("search"), c.NamedArg("region")) if err != nil { terminal.ErrorLine(err.Error()) } return nil }, }, { Name: "deleteVolumes", Usage: "Delete AWS EBS Volumes", Arguments: []cli.Argument{ cli.Argument{ Name: "volume", Description: "The volume to delete", Optional: false, }, cli.Argument{ Name: "region", Description: "The region of the volumes (optional)", Optional: true, }, }, Action: func(c *cli.Context) error { err := aws.DeleteVolumes(c.NamedArg("volume"), c.NamedArg("region"), dryRun) if err != nil { terminal.ErrorLine(err.Error()) } return nil }, }, { Name: "deleteSubnets", Usage: "Delete AWS VPC Subnets", Arguments: []cli.Argument{ cli.Argument{ Name: "search", Description: "The search term for Subnets to delete", Optional: false, }, cli.Argument{ Name: "region", Description: "The region of the subnets (optional)", Optional: true, }, }, Action: func(c *cli.Context) error { err := aws.DeleteSubnets(c.NamedArg("search"), c.NamedArg("region"), dryRun) if err != nil { terminal.ErrorLine(err.Error()) } return nil }, }, { Name: "deleteVpcs", Usage: "Delete AWS VPCs", Arguments: []cli.Argument{ cli.Argument{ Name: "search", Description: "The search term for VPCs to delete", Optional: false, }, cli.Argument{ Name: "region", Description: "The region of the VPCs (optional)", Optional: true, }, }, Action: func(c *cli.Context) error { err := aws.DeleteVpcs(c.NamedArg("search"), c.NamedArg("region"), dryRun) if err != nil { terminal.ErrorLine(err.Error()) } return nil }, }, { Name: "detachVolume", Usage: "Detach an AWS EBS Volume", Arguments: []cli.Argument{ cli.Argument{ Name: "volume", Description: "The volume to detach", Optional: false, }, cli.Argument{ Name: "instance", Description: "The instance to detach the volume from", Optional: false, }, }, Flags: []cli.Flag{ cli.BoolFlag{ Name: "force", Destination: &force, Usage: "force detach", }, }, Action: func(c *cli.Context) error { err := aws.DetachVolume(c.NamedArg("volume"), c.NamedArg("instance"), force, dryRun) if err != nil { terminal.ErrorLine(err.Error()) } return nil }, }, { Name: "stopInstances", Usage: "Stop AWS instances", Arguments: []cli.Argument{ cli.Argument{ Name: "search", Description: "The search term for instance to stop", Optional: false, }, cli.Argument{ Name: "region", Description: "The region of the instance (optional)", Optional: true, }, }, Flags: []cli.Flag{ cli.BoolFlag{ Name: "force", Destination: &force, Usage: "force (Force deletes all instances and lifecycle actions)", }, }, Action: func(c *cli.Context) error { err := aws.StopInstances(c.NamedArg("search"), c.NamedArg("region"), force, dryRun) if err != nil { terminal.ErrorLine(err.Error()) } return nil }, }, { Name: "startInstances", Usage: "Start AWS instances", Arguments: []cli.Argument{ cli.Argument{ Name: "search", Description: "The search term for Instance to start", Optional: false, }, cli.Argument{ Name: "region", Description: "The region of the instance (optional)", Optional: true, }, }, Action: func(c *cli.Context) error { err := aws.StartInstances(c.NamedArg("search"), c.NamedArg("region"), dryRun) if err != nil { terminal.ErrorLine(err.Error()) } return nil }, }, { Name: "rebootInstances", Usage: "Reboot AWS instances", Arguments: []cli.Argument{ cli.Argument{ Name: "search", Description: "The search term for instance to reboot", Optional: false, }, cli.Argument{ Name: "region", Description: "The region of the instance (optional)", Optional: true, }, }, Action: func(c *cli.Context) error { err := aws.RebootInstances(c.NamedArg("search"), c.NamedArg("region"), dryRun) if err != nil { terminal.ErrorLine(err.Error()) } return nil }, }, { Name: "terminateInstances", Usage: "Terminate AWS instances", Arguments: []cli.Argument{ cli.Argument{ Name: "name", Description: "The search term for instance to terminate", Optional: false, }, cli.Argument{ Name: "region", Description: "The region of the instance (optional)", Optional: true, }, }, Action: func(c *cli.Context) error { err := aws.TerminateInstances(c.NamedArg("name"), c.NamedArg("region"), dryRun) if err != nil { terminal.ErrorLine(err.Error()) } return nil }, }, { Name: "launchInstance", Usage: "Launch an EC2 instance", Arguments: []cli.Argument{ cli.Argument{ Name: "class", Description: "The class of the instance (dev, stage, etc)", Optional: false, }, cli.Argument{ Name: "sequence", Description: "The sequence of the instance (1...100)", Optional: false, }, cli.Argument{ Name: "az", Description: "The availability zone to launch the instance in (us-west-2a, us-east-1a, etc)", Optional: false, }, }, Action: func(c *cli.Context) error { err := aws.LaunchInstance(c.NamedArg("class"), c.NamedArg("sequence"), c.NamedArg("az"), dryRun) if err != nil { terminal.ErrorLine(err.Error()) } return nil }, }, { Name: "listAddresses", Usage: "Lists AWS Elastic IP Addresses", Arguments: []cli.Argument{ cli.Argument{ Name: "search", Description: "The keyword to search for", Optional: true, }, }, Action: func(c *cli.Context) error { addresses, errs := aws.GetAddresses(c.NamedArg("search"), false) if errs != nil { return cli.NewExitError("Error Listing Addresses!", 1) } addresses.PrintTable() return nil }, }, { Name: "listAlarms", Usage: "Lists CloudWatch Alarms", Action: func(c *cli.Context) error { alarms, errs := aws.GetAlarms() if errs != nil { return cli.NewExitError("Error Listing Alarms!", 1) } alarms.PrintTable() return nil }, }, { Name: "listAutoScaleGroups", Usage: "Lists AutoScale Groups", Arguments: []cli.Argument{ cli.Argument{ Name: "search", Description: "The keyword to search for", Optional: true, }, }, Action: func(c *cli.Context) error { groups, errs := aws.GetAutoScaleGroups(c.NamedArg("search")) if errs != nil { return cli.NewExitError("Error Listing Auto Scale Groups!", 1) } groups.PrintTable() return nil }, }, { Name: "listIAMUsers", Usage: "Lists IAM Users", Arguments: []cli.Argument{ cli.Argument{ Name: "search", Description: "The keyword to search for", Optional: true, }, }, Action: func(c *cli.Context) error { iam, errs := aws.GetIAMUsers(c.NamedArg("search")) if errs != nil { return cli.NewExitError("Error Listing IAM Users!", 1) } iam.PrintTable() return nil }, }, { Name: "listImages", Usage: "Lists AWS Machine Images owned by us", Arguments: []cli.Argument{ cli.Argument{ Name: "search", Description: "The keyword to search for", Optional: true, }, }, Action: func(c *cli.Context) error { images, errs := aws.GetImages(c.NamedArg("search"), false) if errs != nil { return cli.NewExitError("Error Listing Images!", 1) } images.PrintTable() return nil }, }, { Name: "listInstances", Usage: "Lists AWS EC2 Instances", Arguments: []cli.Argument{ cli.Argument{ Name: "search", Description: "The keyword to search for", Optional: true, }, }, Action: func(c *cli.Context) error { instances, errs := aws.GetInstances(c.NamedArg("search"), false) if errs != nil { return cli.NewExitError("Error Listing Instances!", 1) } instances.PrintTable() return nil }, }, { Name: "listKeyPairs", Usage: "Lists AWS Key Pairs", Arguments: []cli.Argument{ cli.Argument{ Name: "search", Description: "The keyword to search for", Optional: true, }, }, Action: func(c *cli.Context) error { keyPairs, errs := aws.GetKeyPairs(c.NamedArg("search")) if errs != nil { return cli.NewExitError("Error Listing Key Pairs!", 1) } keyPairs.PrintTable() return nil }, }, { Name: "listLaunchConfigurations", Usage: "Lists Launch Configurations", Arguments: []cli.Argument{ cli.Argument{ Name: "search", Description: "The keyword to search for", Optional: true, }, }, Action: func(c *cli.Context) error { launchConfigs, errs := aws.GetLaunchConfigurations(c.NamedArg("search")) if errs != nil { return cli.NewExitError("Error Listing Launch Configurations!", 1) } launchConfigs.PrintTable() return nil }, }, { Name: "listLoadBalancers", Usage: "Lists Elastic Load Balancers", Action: func(c *cli.Context) error { loadBalancers, errs := aws.GetLoadBalancers() if errs != nil { return cli.NewExitError("Error Listing Load Balancers!", 1) } loadBalancers.PrintTable() return nil }, }, { Name: "listScalingPolicies", Usage: "Lists Scaling Policies", Action: func(c *cli.Context) error { policies, errs := aws.GetScalingPolicies() if errs != nil { return cli.NewExitError("Error Listing Auto Scaling Policies!", 1) } policies.PrintTable() return nil }, }, { Name: "listSecurityGroups", Usage: "Lists Security Groups", Arguments: []cli.Argument{ cli.Argument{ Name: "search", Description: "The keyword to search for", Optional: true, }, }, Action: func(c *cli.Context) error { groups, errs := aws.GetSecurityGroups(c.NamedArg("search")) if errs != nil { return cli.NewExitError("Error Listing Security Groups!", 1) } groups.PrintTable() return nil }, }, { Name: "listSnapshots", Usage: "Lists AWS EBS Snapshots", Arguments: []cli.Argument{ cli.Argument{ Name: "search", Description: "The keyword to search for", Optional: true, }, }, Action: func(c *cli.Context) error { snapshots, errs := aws.GetSnapshots(c.NamedArg("search"), false) if errs != nil { return cli.NewExitError("Error Listing Snapshots!", 1) } snapshots.PrintTable() return nil }, }, { Name: "listSubnets", Usage: "Lists AWS Subnets", Arguments: []cli.Argument{ cli.Argument{ Name: "search", Description: "The keyword to search for", Optional: true, }, }, Action: func(c *cli.Context) error { subnets, errs := aws.GetSubnets(c.NamedArg("search")) if errs != nil { return cli.NewExitError("Error Listing Subnets!", 1) } subnets.PrintTable() return nil }, }, { Name: "listSimpleDBDomains", Usage: "Lists AWS SimpleDB Domains", Arguments: []cli.Argument{ cli.Argument{ Name: "search", Description: "The keyword to search for", Optional: true, }, }, Action: func(c *cli.Context) error { domains, errs := aws.GetSimpleDBDomains(c.NamedArg("search")) if errs != nil { return cli.NewExitError("Error Listing Simple DB Domains!", 1) } domains.PrintTable() return nil }, }, { Name: "listVolumes", Usage: "Lists AWS EBS Volumes", Arguments: []cli.Argument{ cli.Argument{ Name: "search", Description: "The keyword to search for", Optional: true, }, }, Action: func(c *cli.Context) error { volumes, errs := aws.GetVolumes(c.NamedArg("search"), false) if errs != nil { return cli.NewExitError("Error Listing Volumes!", 1) } volumes.PrintTable() return nil }, }, { Name: "listVpcs", Usage: "Lists AWS Vpcs", Arguments: []cli.Argument{ cli.Argument{ Name: "search", Description: "The keyword to search for", Optional: true, }, }, Action: func(c *cli.Context) error { vpcs, errs := aws.GetVpcs(c.NamedArg("search")) if errs != nil { return cli.NewExitError("Error Listing VPCs!", 1) } vpcs.PrintTable() return nil }, }, { Name: "resumeProcesses", Usage: "Resume scaling processes on autoscaling groups", Arguments: []cli.Argument{ cli.Argument{ Name: "search", Description: "The search term for the autoscaling group to resume", Optional: false, }, cli.Argument{ Name: "region", Description: "The region to resume the processes in", Optional: true, }, }, Action: func(c *cli.Context) error { err := aws.ResumeProcesses(c.NamedArg("search"), c.NamedArg("region"), dryRun) if err != nil { terminal.ErrorLine(err.Error()) } return nil }, }, { Name: "runCommand", Usage: "Run a command on a set of instances", Action: func(c *cli.Context) error { // TODO return nil }, }, { Name: "suspendProcesses", Usage: "Suspend scaling processes on autoscaling groups", Arguments: []cli.Argument{ cli.Argument{ Name: "search", Description: "The search term for the autoscaling group to suspend", Optional: false, }, cli.Argument{ Name: "region", Description: "The region to suspend the processes in", Optional: true, }, }, Action: func(c *cli.Context) error { err := aws.SuspendProcesses(c.NamedArg("search"), c.NamedArg("region"), dryRun) if err != nil { terminal.ErrorLine(err.Error()) } return nil }, }, { Name: "updateAutoScaleGroups", Usage: "Update AutoScaling Groups", Arguments: []cli.Argument{ cli.Argument{ Name: "search", Description: "The search term autoscaling group to update", Optional: false, }, cli.Argument{ Name: "version", Description: "The version of the launch configuration group to use (defaults to the most recent)", Optional: true, }, }, Flags: []cli.Flag{ cli.BoolFlag{ Name: "double", Destination: &double, Usage: "double (Doubles the desired-capacity and max-capacity)", }, }, Action: func(c *cli.Context) error { err := aws.UpdateAutoScaleGroups(c.NamedArg("search"), c.NamedArg("version"), double, dryRun) if err != nil { terminal.ErrorLine(err.Error()) } return nil }, }, { Name: "updateSecurityGroups", Usage: "Update Security Groups", Arguments: []cli.Argument{ cli.Argument{ Name: "search", Description: "The search term autoscaling group to update", Optional: false, }, cli.Argument{ Name: "region", Description: "The region to update the security groups in (optional)", Optional: true, }, }, Flags: []cli.Flag{ cli.BoolFlag{ Name: "double", Destination: &double, Usage: "double (Doubles the desired-capacity and max-capacity)", }, }, Action: func(c *cli.Context) error { err := aws.UpdateSecurityGroups(c.NamedArg("search"), c.NamedArg("region"), dryRun) if err != nil { terminal.ErrorLine(err.Error()) } return nil }, }, } app.Run(os.Args) }
// LaunchInstance Launches a new EC2 Instance func LaunchInstance(class, sequence, az string, dryRun bool) error { // --dry-run flag if dryRun { terminal.Information("--dry-run flag is set, not making any actual changes!") } // Instance Class Config instanceCfg, err := config.LoadInstanceClass(class) if err != nil { return err } terminal.Information("Found Instance class configuration for [" + class + "]!") // AZ azs, _ := regions.GetAZs() if !azs.ValidAZ(az) { return cli.NewExitError("Availability Zone ["+az+"] is Invalid!", 1) } terminal.Information("Found Availability Zone [" + az + "]!") region := azs.GetRegion(az) // AMI ami, err := GetLatestImageByTag(region, "Class", instanceCfg.AMI) if err != nil { return err } terminal.Information("Found AMI [" + ami.ImageID + "] with class [" + ami.Class + "] created [" + ami.CreatedHuman + "]!") // EBS ebsVolumes := make([]*ec2.BlockDeviceMapping, len(instanceCfg.EBSVolumes)) for i, ebsClass := range instanceCfg.EBSVolumes { volCfg, err := config.LoadVolumeClass(ebsClass) if err != nil { return err } terminal.Information("Found Volume Class Configuration for [" + ebsClass + "]!") latestSnapshot, err := GetLatestSnapshotByTag(region, "Class", volCfg.Snapshot) if err != nil { return err } terminal.Information("Found Snapshot [" + latestSnapshot.SnapshotID + "] with class [" + latestSnapshot.Class + "] created [" + latestSnapshot.CreatedHuman + "]!") ebsVolumes[i] = &ec2.BlockDeviceMapping{ DeviceName: aws.String(volCfg.DeviceName), Ebs: &ec2.EbsBlockDevice{ DeleteOnTermination: aws.Bool(volCfg.DeleteOnTermination), //Encrypted: aws.Bool(volCfg.Encrypted), SnapshotId: aws.String(latestSnapshot.SnapshotID), VolumeSize: aws.Int64(int64(volCfg.VolumeSize)), VolumeType: aws.String(volCfg.VolumeType), }, //NoDevice: aws.String("String"), //VirtualName: aws.String("String"), } if volCfg.VolumeType == "io1" { ebsVolumes[i].Ebs.Iops = aws.Int64(int64(volCfg.Iops)) } } // EBS Optimized if instanceCfg.EbsOptimized { terminal.Information("Launching as EBS Optimized") } // IAM Profile var iam IAMUser if len(instanceCfg.IAMUser) > 0 { iam, err := GetIAMUser(instanceCfg.IAMUser) if err != nil { return err } terminal.Information("Found IAM User [" + iam.UserName + "]!") } // KeyPair keyPair, err := GetKeyPairByName(region, instanceCfg.KeyName) if err != nil { return err } terminal.Information("Found KeyPair [" + keyPair.KeyName + "] in [" + keyPair.Region + "]!") // Network Interfaces // Placement ?? // VPC / Subnet var vpc Vpc var subnet Subnet var subnetID string secGroupIds := make([]*string, len(instanceCfg.SecurityGroups)) if instanceCfg.Vpc != "" && instanceCfg.Subnet != "" { // VPC vpc, err = GetVpcByTag(region, "Class", instanceCfg.Vpc) if err != nil { return err } terminal.Information("Found VPC [" + vpc.VpcID + "] in Region [" + region + "]!") // Subnet subnet, err = vpc.GetVpcSubnetByTag("Class", instanceCfg.Subnet) if err != nil { return err } subnetID = subnet.SubnetID terminal.Information("Found Subnet [" + subnet.SubnetID + "] in VPC [" + subnet.VpcID + "]!") // VPC Security Groups secGroups, err := vpc.GetVpcSecurityGroupByTagMulti("Class", instanceCfg.SecurityGroups) if err != nil { return err } for i, secGroup := range secGroups { terminal.Information("Found VPC Security Group [" + secGroup.GroupID + "] with name [" + secGroup.Name + "]!") secGroupIds[i] = aws.String(secGroup.GroupID) } } else { terminal.Information("No VPC and/or Subnet specified for instance Class [" + class + "]!") // EC2-Classic security groups secGroups, err := GetSecurityGroupByTagMulti(region, "Class", instanceCfg.SecurityGroups) if err != nil { return err } for i, secGroup := range secGroups { terminal.Information("Found Security Group [" + secGroup.GroupID + "] with name [" + secGroup.Name + "]!") secGroupIds[i] = aws.String(secGroup.GroupID) } } // User Data // ================================================================ // ================================================================ // ================================================================ svc := ec2.New(session.New(&aws.Config{Region: aws.String(region)})) params := &ec2.RunInstancesInput{ ImageId: aws.String(ami.ImageID), MaxCount: aws.Int64(1), MinCount: aws.Int64(1), BlockDeviceMappings: ebsVolumes, DryRun: aws.Bool(dryRun), EbsOptimized: aws.Bool(instanceCfg.EbsOptimized), IamInstanceProfile: &ec2.IamInstanceProfileSpecification{ Arn: aws.String(iam.Arn), Name: aws.String(iam.UserName), }, InstanceInitiatedShutdownBehavior: aws.String(instanceCfg.ShutdownBehavior), InstanceType: aws.String(instanceCfg.InstanceType), KeyName: aws.String(keyPair.KeyName), Monitoring: &ec2.RunInstancesMonitoringEnabled{ Enabled: aws.Bool(instanceCfg.Monitoring), }, NetworkInterfaces: []*ec2.InstanceNetworkInterfaceSpecification{ // only needed when we launch with a public ip. TODO { /* AssociatePublicIpAddress: aws.Bool(instanceCfg.PublicIpAddress), DeleteOnTermination: aws.Bool(true), //Description: aws.String("String"), DeviceIndex: aws.Int64(0), Groups: []*string{ aws.String("String"), // Required }, PrivateIpAddress: aws.String("String"), PrivateIpAddresses: []*ec2.PrivateIpAddressSpecification{ { // Required PrivateIpAddress: aws.String("String"), // Required Primary: aws.Bool(true), }, }, SecondaryPrivateIpAddressCount: aws.Int64(1), SubnetId: aws.String("String"), */ }, }, /* Placement: &ec2.Placement{ // havent played around with placements yet, TODO? Affinity: aws.String("String"), AvailabilityZone: aws.String("String"), GroupName: aws.String("String"), HostId: aws.String("String"), Tenancy: aws.String("Tenancy"), }, */ // PrivateIpAddress: aws.String("String"), SecurityGroupIds: secGroupIds, SubnetId: aws.String(subnetID), UserData: aws.String(base64.StdEncoding.EncodeToString([]byte(instanceCfg.UserData))), //KernelId: aws.String("String"), //RamdiskId: aws.String("String"), } launchInstanceResp, err := svc.RunInstances(params) if err != nil { if awsErr, ok := err.(awserr.Error); ok { return errors.New(awsErr.Message()) } return err } // Add Tags instanceTagsParams := &ec2.CreateTagsInput{ Resources: []*string{ launchInstanceResp.Instances[0].InstanceId, }, Tags: []*ec2.Tag{ { Key: aws.String("Name"), Value: aws.String(class + sequence), }, { Key: aws.String("Sequence"), Value: aws.String(sequence), }, { Key: aws.String("Class"), Value: aws.String(class), }, }, DryRun: aws.Bool(dryRun), } _, err = svc.CreateTags(instanceTagsParams) if err != nil { if awsErr, ok := err.(awserr.Error); ok { return errors.New(awsErr.Message()) } return err } terminal.Information("Finished Launching Instance!") inst := make(Instances, 1) inst[1].Marshal(launchInstanceResp.Instances[0], region, &Subnets{subnet}, &Vpcs{vpc}, &Images{ami}) inst.PrintTable() // ================================================================ // ================================================================ // ================================================================ return nil }