func (e *SecurityGroup) Find(c *fi.Context) (*SecurityGroup, error) { cloud := c.Cloud.(*awsup.AWSCloud) var vpcID *string if e.VPC != nil { vpcID = e.VPC.ID } if vpcID == nil || e.Name == nil { return nil, nil } filters := cloud.BuildFilters(e.Name) filters = append(filters, awsup.NewEC2Filter("vpc-id", *vpcID)) filters = append(filters, awsup.NewEC2Filter("group-name", *e.Name)) request := &ec2.DescribeSecurityGroupsInput{ Filters: filters, } response, err := cloud.EC2.DescribeSecurityGroups(request) if err != nil { return nil, fmt.Errorf("error listing SecurityGroups: %v", err) } if response == nil || len(response.SecurityGroups) == 0 { return nil, nil } if len(response.SecurityGroups) != 1 { return nil, fmt.Errorf("found multiple SecurityGroups matching tags") } sg := response.SecurityGroups[0] actual := &SecurityGroup{ ID: sg.GroupId, Name: sg.GroupName, Description: sg.Description, VPC: &VPC{ID: sg.VpcId}, } glog.V(2).Infof("found matching SecurityGroup %q", *actual.ID) e.ID = actual.ID return actual, nil }
func buildEC2Filters(cloud fi.Cloud) []*ec2.Filter { awsCloud := cloud.(*awsup.AWSCloud) tags := awsCloud.Tags() var filters []*ec2.Filter for k, v := range tags { filter := awsup.NewEC2Filter("tag:"+k, v) filters = append(filters, filter) } return filters }
func (e *InternetGateway) Find(c *fi.Context) (*InternetGateway, error) { cloud := c.Cloud.(*awsup.AWSCloud) request := &ec2.DescribeInternetGatewaysInput{} shared := fi.BoolValue(e.Shared) if shared { if fi.StringValue(e.VPC.ID) == "" { return nil, fmt.Errorf("VPC ID is required when InternetGateway is shared") } request.Filters = []*ec2.Filter{awsup.NewEC2Filter("attachment.vpc-id", *e.VPC.ID)} } else { if e.ID != nil { request.InternetGatewayIds = []*string{e.ID} } else { request.Filters = cloud.BuildFilters(e.Name) } } response, err := cloud.EC2.DescribeInternetGateways(request) if err != nil { return nil, fmt.Errorf("error listing InternetGateways: %v", err) } if response == nil || len(response.InternetGateways) == 0 { return nil, nil } if len(response.InternetGateways) != 1 { return nil, fmt.Errorf("found multiple InternetGateways matching tags") } igw := response.InternetGateways[0] actual := &InternetGateway{ ID: igw.InternetGatewayId, Name: findNameTag(igw.Tags), } glog.V(2).Infof("found matching InternetGateway %q", *actual.ID) for _, attachment := range igw.Attachments { actual.VPC = &VPC{ID: attachment.VpcId} } // Prevent spurious comparison failures actual.Shared = e.Shared if e.ID == nil { e.ID = actual.ID } return actual, nil }
func (e *SecurityGroupRule) Find(c *fi.Context) (*SecurityGroupRule, error) { cloud := c.Cloud.(*awsup.AWSCloud) if e.SecurityGroup == nil || e.SecurityGroup.ID == nil { return nil, nil } request := &ec2.DescribeSecurityGroupsInput{ Filters: []*ec2.Filter{ awsup.NewEC2Filter("group-id", *e.SecurityGroup.ID), }, } response, err := cloud.EC2.DescribeSecurityGroups(request) if err != nil { return nil, fmt.Errorf("error listing SecurityGroup: %v", err) } if response == nil || len(response.SecurityGroups) == 0 { return nil, nil } if len(response.SecurityGroups) != 1 { glog.Fatalf("found multiple security groups for id=%s", *e.SecurityGroup.ID) } sg := response.SecurityGroups[0] //glog.V(2).Info("found existing security group") var foundRule *ec2.IpPermission matchProtocol := "-1" // Wildcard if e.Protocol != nil { matchProtocol = *e.Protocol } ipPermissions := sg.IpPermissions if fi.BoolValue(e.Egress) { ipPermissions = sg.IpPermissionsEgress } for _, rule := range ipPermissions { if aws.Int64Value(rule.FromPort) != aws.Int64Value(e.FromPort) { continue } if aws.Int64Value(rule.ToPort) != aws.Int64Value(e.ToPort) { continue } if aws.StringValue(rule.IpProtocol) != matchProtocol { continue } if e.CIDR != nil { // TODO: Only if len 1? match := false for _, ipRange := range rule.IpRanges { if aws.StringValue(ipRange.CidrIp) == *e.CIDR { match = true break } } if !match { continue } } if e.SourceGroup != nil { // TODO: Only if len 1? match := false for _, spec := range rule.UserIdGroupPairs { if aws.StringValue(spec.GroupId) == *e.SourceGroup.ID { match = true break } } if !match { continue } } foundRule = rule break } if foundRule != nil { actual := &SecurityGroupRule{ Name: e.Name, SecurityGroup: &SecurityGroup{ID: e.SecurityGroup.ID}, FromPort: foundRule.FromPort, ToPort: foundRule.ToPort, Protocol: foundRule.IpProtocol, Egress: e.Egress, } if aws.StringValue(actual.Protocol) == "-1" { actual.Protocol = nil } if e.CIDR != nil { actual.CIDR = e.CIDR } if e.SourceGroup != nil { actual.SourceGroup = &SecurityGroup{ID: e.SourceGroup.ID} } return actual, nil } return nil, nil }
func (e *Instance) Find(c *fi.Context) (*Instance, error) { cloud := c.Cloud.(*awsup.AWSCloud) filters := cloud.BuildFilters(e.Name) filters = append(filters, awsup.NewEC2Filter("instance-state-name", "pending", "running", "stopping", "stopped")) request := &ec2.DescribeInstancesInput{ Filters: filters, } response, err := cloud.EC2.DescribeInstances(request) if err != nil { return nil, fmt.Errorf("error listing instances: %v", err) } instances := []*ec2.Instance{} if response != nil { for _, reservation := range response.Reservations { for _, instance := range reservation.Instances { instances = append(instances, instance) } } } if len(instances) == 0 { return nil, nil } if len(instances) != 1 { return nil, fmt.Errorf("found multiple Instances with name: %s", *e.Name) } glog.V(2).Info("found existing instance") i := instances[0] if i.InstanceId == nil { return nil, fmt.Errorf("found instance, but InstanceId was nil") } actual := &Instance{ ID: i.InstanceId, PrivateIPAddress: i.PrivateIpAddress, InstanceType: i.InstanceType, ImageID: i.ImageId, Name: findNameTag(i.Tags), } // Fetch instance UserData { request := &ec2.DescribeInstanceAttributeInput{} request.InstanceId = i.InstanceId request.Attribute = aws.String("userData") response, err := cloud.EC2.DescribeInstanceAttribute(request) if err != nil { return nil, fmt.Errorf("error querying EC2 for user metadata for instance %q: %v", *i.InstanceId) } if response.UserData != nil { b, err := base64.StdEncoding.DecodeString(aws.StringValue(response.UserData.Value)) if err != nil { return nil, fmt.Errorf("error decoding EC2 UserData: %v", err) } actual.UserData = fi.NewBytesResource(b) } } if i.SubnetId != nil { actual.Subnet = &Subnet{ID: i.SubnetId} } if i.KeyName != nil { actual.SSHKey = &SSHKey{Name: i.KeyName} } for _, sg := range i.SecurityGroups { actual.SecurityGroups = append(actual.SecurityGroups, &SecurityGroup{ID: sg.GroupId}) } associatePublicIpAddress := false for _, ni := range i.NetworkInterfaces { if aws.StringValue(ni.Association.PublicIp) != "" { associatePublicIpAddress = true } } actual.AssociatePublicIP = &associatePublicIpAddress if i.IamInstanceProfile != nil { actual.IAMInstanceProfile = &IAMInstanceProfile{Name: nameFromIAMARN(i.IamInstanceProfile.Arn)} } actual.Tags = mapEC2TagsToMap(i.Tags) e.ID = actual.ID // Avoid spurious changes on ImageId if e.ImageID != nil && actual.ImageID != nil && *actual.ImageID != *e.ImageID { image, err := cloud.ResolveImage(*e.ImageID) if err != nil { glog.Warningf("unable to resolve image: %q: %v", *e.ImageID, err) } else if image == nil { glog.Warningf("unable to resolve image: %q: not found", *e.ImageID) } else if aws.StringValue(image.ImageId) == *actual.ImageID { glog.V(4).Infof("Returning matching ImageId as expected name: %q -> %q", *actual.ImageID, *e.ImageID) actual.ImageID = e.ImageID } } return actual, nil }
func (e *ElasticIP) find(cloud *awsup.AWSCloud) (*ElasticIP, error) { publicIP := e.PublicIP allocationID := e.ID tagOnResourceID, err := e.findTagOnResourceID(cloud) if err != nil { return nil, err } // Find via tag on foreign resource if allocationID == nil && publicIP == nil && e.TagUsingKey != nil && tagOnResourceID != nil { var filters []*ec2.Filter filters = append(filters, awsup.NewEC2Filter("key", *e.TagUsingKey)) filters = append(filters, awsup.NewEC2Filter("resource-id", *tagOnResourceID)) request := &ec2.DescribeTagsInput{ Filters: filters, } response, err := cloud.EC2.DescribeTags(request) if err != nil { return nil, fmt.Errorf("error listing tags: %v", err) } if response == nil || len(response.Tags) == 0 { return nil, nil } if len(response.Tags) != 1 { return nil, fmt.Errorf("found multiple tags for: %v", e) } t := response.Tags[0] publicIP = t.Value glog.V(2).Infof("Found public IP via tag: %v", *publicIP) } if publicIP != nil || allocationID != nil { request := &ec2.DescribeAddressesInput{} if allocationID != nil { request.AllocationIds = []*string{allocationID} } else if publicIP != nil { request.Filters = []*ec2.Filter{awsup.NewEC2Filter("public-ip", *publicIP)} } response, err := cloud.EC2.DescribeAddresses(request) if err != nil { return nil, fmt.Errorf("error listing ElasticIPs: %v", err) } if response == nil || len(response.Addresses) == 0 { return nil, nil } if len(response.Addresses) != 1 { return nil, fmt.Errorf("found multiple ElasticIPs for: %v", e) } a := response.Addresses[0] actual := &ElasticIP{ ID: a.AllocationId, PublicIP: a.PublicIp, } // These two are weird properties; we copy them so they don't come up as changes actual.TagUsingKey = e.TagUsingKey actual.TagOnResource = e.TagOnResource e.ID = actual.ID return actual, nil } return nil, nil }