Пример #1
0
// Private function without the confirmation terminal prompts
func rebootInstances(instList *Instances, dryRun bool) (err error) {
	for _, instance := range *instList {
		azs, _ := regions.GetAZs()

		svc := ec2.New(session.New(&aws.Config{Region: aws.String(azs.GetRegion(instance.AvailabilityZone))}))

		params := &ec2.RebootInstancesInput{
			InstanceIds: []*string{
				aws.String(instance.InstanceID),
			},
			DryRun: aws.Bool(dryRun),
		}

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

		terminal.Information("Rebooted Instance [" + instance.InstanceID + "] named [" + instance.Name + "] in [" + instance.AvailabilityZone + "]!")
	}

	return nil
}
Пример #2
0
// 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

}
Пример #3
0
// 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
}
Пример #4
0
// 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

}
Пример #5
0
// 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
}
Пример #6
0
// 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
}