Exemple #1
0
// CreateAddress creates a new Elastic IP Address in the given region and domain
func CreateAddress(region, domain string, dryRun bool) error {

	// --dry-run flag
	if dryRun {
		terminal.Information("--dry-run flag is set, not making any actual changes!")
	}

	// Validate the region
	if !regions.ValidRegion(region) {
		return errors.New("Region [" + region + "] is Invalid!")
	}

	// Validate the domain
	if !(domain == "vpc" || domain != "classic") {
		return errors.New("Domain should be either [vpc] or [classic].")
	}

	svc := ec2.New(session.New(&aws.Config{Region: aws.String(region)}))

	// Create the address
	params := &ec2.AllocateAddressInput{
		Domain: aws.String(domain),
		DryRun: aws.Bool(dryRun),
	}
	_, err := svc.AllocateAddress(params)

	if err != nil {
		if awsErr, ok := err.(awserr.Error); ok {
			return errors.New(awsErr.Message())
		}
		return err
	}

	return nil
}
Exemple #2
0
// CreateKeyPair creates a KeyPair of a specified class in the specified region
func CreateKeyPair(class, region string, dryRun bool) error {

	if dryRun {
		terminal.Information("--dry-run flag is set, not making any actual changes!")
	}

	// KeyPair Class Config
	keypairCfg, err := config.LoadKeyPairClass(class)
	if err != nil {
		return err
	}

	terminal.Information("Found KeyPair class configuration for [" + class + "]!")

	// Validate the region
	if !regions.ValidRegion(region) {
		return errors.New("Region [" + region + "] is Invalid!")
	}

	// Import the KeyPair to the requested region
	err = importKeyPair(region, class, []byte(keypairCfg.PublicKey), dryRun)
	if err != nil {
		return err
	}

	return nil
}
Exemple #3
0
// CreateVpc creates a new VPC
func CreateVpc(class, name, ip, region 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.LoadVpcClass(class)
	if err != nil {
		return err
	}

	terminal.Information("Found VPC Class Configuration for [" + class + "]!")

	// Validate the region
	if !regions.ValidRegion(region) {
		return errors.New("Region [" + region + "] is Invalid!")
	}

	// TODO limit to one VPC of a class per region, so that we can target VPCs by class instead of name.

	svc := ec2.New(session.New(&aws.Config{Region: aws.String(region)}))

	// Create the VPC
	vpcParams := &ec2.CreateVpcInput{
		CidrBlock:       aws.String(ip + cfg.CIDR),
		DryRun:          aws.Bool(dryRun),
		InstanceTenancy: aws.String(cfg.Tenancy),
	}
	createVpcResp, err := svc.CreateVpc(vpcParams)

	if err != nil {
		return err
	}

	terminal.Information("Created VPC [" + *createVpcResp.Vpc.VpcId + "] named [" + name + "] in [" + region + "]!")

	// Add Tags
	err = SetEc2NameAndClassTags(createVpcResp.Vpc.VpcId, name, class, region)

	if err != nil {
		return err
	}

	return nil

}
Exemple #4
0
// CopySnapshot copies a Snapshot to another region
func CopySnapshot(search, region string, dryRun bool) error {

	// --dry-run flag
	if dryRun {
		terminal.Information("--dry-run flag is set, not making any actual changes!")
	}

	// Validate the destination region
	if !regions.ValidRegion(region) {
		return errors.New("Region [" + region + "] is Invalid!")
	}

	// Get the source snapshot
	snapshots, _ := GetSnapshots(search, true)
	snapCount := len(*snapshots)
	if snapCount == 0 {
		return errors.New("No available snapshots found for your search terms.")
	}
	if snapCount > 1 {
		snapshots.PrintTable()
		return errors.New("Please limit your search to return only one snapshot.")
	}

	snapshot := (*snapshots)[0]

	copySnapResp, err := copySnapshot(snapshot, region, dryRun)
	if err != nil {
		return err
	}

	terminal.Information("Created Snapshot [" + *copySnapResp.SnapshotId + "] named [" + snapshot.Name + "] to [" + region + "]!")

	// Add Tags
	err = SetEc2NameAndClassTags(copySnapResp.SnapshotId, snapshot.Name, snapshot.Class, region)

	if err != nil {
		if awsErr, ok := err.(awserr.Error); ok {
			return errors.New(awsErr.Message())
		}
		return err
	}

	return nil
}
Exemple #5
0
// CreateSecurityGroup creates a new Security Group based on the provided class, region, and VPC ID
func CreateSecurityGroup(class, region, vpcID string, dryRun bool) error {

	// --dry-run flag
	if dryRun {
		terminal.Information("--dry-run flag is set, not making any actual changes!")
	}

	// Validate the region
	if !regions.ValidRegion(region) {
		return errors.New("Region [" + region + "] is Invalid!")
	}

	// Verify the security group class input
	cfg, err := config.LoadSecurityGroupClass(class)
	if err != nil {
		return err
	}

	terminal.Information("Found Security Group class configuration for [" + class + "]")

	svc := ec2.New(session.New(&aws.Config{Region: aws.String(region)}))

	// Create the security group
	params := &ec2.CreateSecurityGroupInput{
		Description: aws.String(cfg.Description),
		GroupName:   aws.String(class),
		DryRun:      aws.Bool(dryRun),
		VpcId:       aws.String(vpcID),
	}

	_, err = svc.CreateSecurityGroup(params)

	if err != nil {
		if awsErr, ok := err.(awserr.Error); ok {
			return errors.New(awsErr.Message())
		}
		return err
	}

	return nil
}
Exemple #6
0
// CreateSimpleDBDomain creates a new SimpleDB Domain
func CreateSimpleDBDomain(domain, region string) error {

	// Validate the region
	if !regions.ValidRegion(region) {
		return errors.New("Region [" + region + "] is Invalid!")
	}

	svc := simpledb.New(session.New(&aws.Config{Region: aws.String(region)}))

	params := &simpledb.CreateDomainInput{
		DomainName: aws.String(domain),
	}

	terminal.Information("Creating SimpleDB Domain [" + domain + "] in [" + region + "]...")

	_, err := svc.CreateDomain(params)
	if err == nil {
		terminal.Information("Done!")
	}

	return err
}
Exemple #7
0
// CopyImage copies an existing AMI to another region
func CopyImage(search, region string, dryRun bool) error {

	// --dry-run flag
	if dryRun {
		terminal.Information("--dry-run flag is set, not making any actual changes!")
	}

	// Validate the destination region
	if !regions.ValidRegion(region) {
		return errors.New("Region [" + region + "] is Invalid!")
	}

	// Get the source image
	images, _ := GetImages(search, true)
	imgCount := len(*images)
	if imgCount == 0 {
		return errors.New("No available images found for your search terms.")
	}
	if imgCount > 1 {
		images.PrintTable()
		return errors.New("Please limit your search to return only one image.")
	}
	image := (*images)[0]

	// Copy image to the destination region
	copyImageResp, err := copyImage(image, region, dryRun)

	if err != nil {
		return err
	}

	terminal.Information("Created Image [" + *copyImageResp.ImageId + "] named [" + image.Name + "] to [" + region + "]!")

	// Add Tags
	return SetEc2NameAndClassTags(copyImageResp.ImageId, image.Name, image.Class, region)
}
Exemple #8
0
// CreateAlarm creates a new CloudWatch Alarm given the provided class, region, and dimensions of that Alarm
func CreateAlarm(class, region string, dimensions map[string]string, dryRun bool) error {

	// --dry-run flag
	if dryRun {
		terminal.Information("--dry-run flag is set, not making any actual changes!")
	}

	// Validate the region
	if !regions.ValidRegion(region) {
		return errors.New("Region [" + region + "] is Invalid!")
	}

	// Verify the alarm class input
	cfg, err := config.LoadAlarmClass(class)
	if err != nil {
		return err
	}
	terminal.Information("Found CloudWatch Alarm class configuration for [" + class + "]")

	svc := cloudwatch.New(session.New(&aws.Config{Region: aws.String(region)}))

	// Create the alarm
	params := &cloudwatch.PutMetricAlarmInput{
		AlarmName:          aws.String(class),
		ComparisonOperator: aws.String(cfg.ComparisonOperator),
		EvaluationPeriods:  aws.Int64(int64(cfg.EvaluationPeriods)),
		MetricName:         aws.String(cfg.MetricName),
		Namespace:          aws.String(cfg.Namespace),
		Period:             aws.Int64(int64(cfg.Period)),
		Statistic:          aws.String(cfg.Statistic),
		Threshold:          aws.Float64(cfg.Threshold),
		ActionsEnabled:     aws.Bool(cfg.ActionsEnabled),
		AlarmDescription:   aws.String(cfg.AlarmDescription),
		Unit:               aws.String(cfg.Unit),
	}

	// Set the Alarm Actions
	for _, action := range cfg.AlarmActions {
		params.AlarmActions = append(params.AlarmActions, aws.String(action))
	}

	// Set the Alarm Dimensions
	for name, value := range dimensions {
		params.Dimensions = append(params.Dimensions, &cloudwatch.Dimension{
			Name:  aws.String(name),
			Value: aws.String(value),
		})
	}

	// Set the Alarm InsufficientDataActions
	for _, action := range cfg.InsufficientDataActions {
		params.InsufficientDataActions = append(params.InsufficientDataActions, aws.String(action))
	}

	// Set the Alarm OKActions
	for _, action := range cfg.OKActions {
		params.OKActions = append(params.OKActions, aws.String(action))
	}

	if !dryRun {
		_, err = svc.PutMetricAlarm(params)

		if err != nil {
			if awsErr, ok := err.(awserr.Error); ok {
				return errors.New(awsErr.Message())
			}
			return err
		}
	}

	return nil
}
Exemple #9
0
// CreateLaunchConfigurations creates a new Launch Configuration of a given class
func CreateLaunchConfigurations(class string, dryRun bool) (err error) {

	// Verify the launch config class input
	cfg, err := config.LoadLaunchConfigurationClass(class)
	if err != nil {
		return err
	}

	terminal.Information("Found Launch Configuration class configuration for [" + class + "]")

	// Instance Class Config
	instanceCfg, err := config.LoadInstanceClass(cfg.InstanceClass)
	if err != nil {
		return err
	}

	terminal.Information("Found Instance class configuration for [" + cfg.InstanceClass + "]")

	// Increment the version
	terminal.Information(fmt.Sprintf("Previous version of launch configuration is [%d]", cfg.Version))
	cfg.Increment(class)
	terminal.Information(fmt.Sprintf("New version of launch configuration is [%d]", cfg.Version))

	params := &autoscaling.CreateLaunchConfigurationInput{
		LaunchConfigurationName:  aws.String(fmt.Sprintf("%s-v%d", class, cfg.Version)),
		AssociatePublicIpAddress: aws.Bool(instanceCfg.PublicIPAddress),
		InstanceMonitoring: &autoscaling.InstanceMonitoring{
			Enabled: aws.Bool(instanceCfg.Monitoring),
		},
		InstanceType: aws.String(instanceCfg.InstanceType),
		UserData:     aws.String(instanceCfg.UserData),
		//KernelId:         aws.String("XmlStringMaxLen255"),
		//PlacementTenancy: aws.String("XmlStringMaxLen64"),
		//RamdiskId:        aws.String("XmlStringMaxLen255"),
		//SpotPrice: aws.String("SpotPrice"),
		//ClassicLinkVPCId:         aws.String("XmlStringMaxLen255"),
		//ClassicLinkVPCSecurityGroups: []*string{
		//aws.String("XmlStringMaxLen255"),
		//},
	}

	// IAM Profile
	if len(instanceCfg.IAMUser) > 0 {
		iam, err := GetIAMUser(instanceCfg.IAMUser)
		if err != nil {
			return err
		}

		terminal.Information("Found IAM User [" + iam.UserName + "]")
		params.IamInstanceProfile = aws.String(iam.Arn)

	}

	for _, region := range cfg.Regions {

		if !regions.ValidRegion(region) {
			return errors.New("Region [" + region + "] is not valid!")
		}

		// EBS
		ebsVolumes := make([]*autoscaling.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] = &autoscaling.BlockDeviceMapping{
				DeviceName: aws.String(volCfg.DeviceName),
				Ebs: &autoscaling.Ebs{
					DeleteOnTermination: aws.Bool(volCfg.DeleteOnTermination),
					SnapshotId:          aws.String(latestSnapshot.SnapshotID),
					VolumeSize:          aws.Int64(int64(volCfg.VolumeSize)),
					VolumeType:          aws.String(volCfg.VolumeType),
					//Encrypted:           aws.Bool(volCfg.Encrypted),
				},
				//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")
			params.EbsOptimized = aws.Bool(instanceCfg.EbsOptimized)
		}

		params.BlockDeviceMappings = ebsVolumes

		// 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 + "]")
		params.ImageId = aws.String(ami.ImageID)

		// KeyPair
		keyPair, err := GetKeyPairByName(region, instanceCfg.KeyName)
		if err != nil {
			return err
		}

		terminal.Information("Found KeyPair [" + keyPair.KeyName + "] in [" + keyPair.Region + "]")
		params.KeyName = aws.String(keyPair.KeyName)

		// VPC / Subnet
		var vpc Vpc
		var subnet Subnet
		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
			}

			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)
			}

		}

		params.SecurityGroups = secGroupIds

		svc := autoscaling.New(session.New(&aws.Config{Region: aws.String(region)}))

		_, err = svc.CreateLaunchConfiguration(params)

		if err != nil {
			if awsErr, ok := err.(awserr.Error); ok {
				return errors.New(awsErr.Message())
			}
			return err
		}

	}

	// Rotate out older launch configurations
	if cfg.Retain > 1 {
		err := RotateLaunchConfigurations(class, cfg, dryRun)
		if err != nil {
			terminal.ShowErrorMessage(fmt.Sprintf("Error rotating [%s] launch configurations!", class), err.Error())
			return err
		}
	}

	return nil
}