github.com/danp/terraform@v0.9.5-0.20170426144147-39d740081351/builtin/providers/aws/data_source_aws_instance.go (about)

     1  package aws
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  
     7  	"github.com/aws/aws-sdk-go/aws"
     8  	"github.com/aws/aws-sdk-go/service/ec2"
     9  	"github.com/hashicorp/terraform/helper/schema"
    10  )
    11  
    12  func dataSourceAwsInstance() *schema.Resource {
    13  	return &schema.Resource{
    14  		Read: dataSourceAwsInstanceRead,
    15  
    16  		Schema: map[string]*schema.Schema{
    17  			"filter":        dataSourceFiltersSchema(),
    18  			"tags":          dataSourceTagsSchema(),
    19  			"instance_tags": tagsSchemaComputed(),
    20  			"instance_id": {
    21  				Type:     schema.TypeString,
    22  				Optional: true,
    23  				ForceNew: true,
    24  			},
    25  			"ami": {
    26  				Type:     schema.TypeString,
    27  				Computed: true,
    28  			},
    29  			"instance_type": {
    30  				Type:     schema.TypeString,
    31  				Computed: true,
    32  			},
    33  			"instance_state": {
    34  				Type:     schema.TypeString,
    35  				Computed: true,
    36  			},
    37  			"availability_zone": {
    38  				Type:     schema.TypeString,
    39  				Computed: true,
    40  			},
    41  			"tenancy": {
    42  				Type:     schema.TypeString,
    43  				Computed: true,
    44  			},
    45  			"key_name": {
    46  				Type:     schema.TypeString,
    47  				Computed: true,
    48  			},
    49  			"public_dns": {
    50  				Type:     schema.TypeString,
    51  				Computed: true,
    52  			},
    53  			"public_ip": {
    54  				Type:     schema.TypeString,
    55  				Computed: true,
    56  			},
    57  			"private_dns": {
    58  				Type:     schema.TypeString,
    59  				Computed: true,
    60  			},
    61  			"private_ip": {
    62  				Type:     schema.TypeString,
    63  				Computed: true,
    64  			},
    65  			"iam_instance_profile": {
    66  				Type:     schema.TypeString,
    67  				Computed: true,
    68  			},
    69  			"subnet_id": {
    70  				Type:     schema.TypeString,
    71  				Computed: true,
    72  			},
    73  			"network_interface_id": {
    74  				Type:     schema.TypeString,
    75  				Computed: true,
    76  			},
    77  			"associate_public_ip_address": {
    78  				Type:     schema.TypeBool,
    79  				Computed: true,
    80  			},
    81  			"ebs_optimized": {
    82  				Type:     schema.TypeBool,
    83  				Computed: true,
    84  			},
    85  			"source_dest_check": {
    86  				Type:     schema.TypeBool,
    87  				Computed: true,
    88  			},
    89  			"monitoring": {
    90  				Type:     schema.TypeBool,
    91  				Computed: true,
    92  			},
    93  			"user_data": {
    94  				Type:     schema.TypeString,
    95  				Computed: true,
    96  			},
    97  			"security_groups": {
    98  				Type:     schema.TypeSet,
    99  				Computed: true,
   100  				Elem: &schema.Schema{
   101  					Type: schema.TypeString,
   102  				},
   103  			},
   104  			"vpc_security_group_ids": {
   105  				Type:     schema.TypeSet,
   106  				Computed: true,
   107  				Elem: &schema.Schema{
   108  					Type: schema.TypeString,
   109  				},
   110  			},
   111  			"ephemeral_block_device": {
   112  				Type:     schema.TypeSet,
   113  				Computed: true,
   114  				Elem: &schema.Resource{
   115  					Schema: map[string]*schema.Schema{
   116  						"device_name": {
   117  							Type:     schema.TypeString,
   118  							Required: true,
   119  						},
   120  
   121  						"virtual_name": {
   122  							Type:     schema.TypeString,
   123  							Optional: true,
   124  						},
   125  
   126  						"no_device": {
   127  							Type:     schema.TypeBool,
   128  							Optional: true,
   129  						},
   130  					},
   131  				},
   132  			},
   133  			"ebs_block_device": {
   134  				Type:     schema.TypeSet,
   135  				Computed: true,
   136  				Elem: &schema.Resource{
   137  					Schema: map[string]*schema.Schema{
   138  						"delete_on_termination": {
   139  							Type:     schema.TypeBool,
   140  							Computed: true,
   141  						},
   142  
   143  						"device_name": {
   144  							Type:     schema.TypeString,
   145  							Computed: true,
   146  						},
   147  
   148  						"encrypted": {
   149  							Type:     schema.TypeBool,
   150  							Computed: true,
   151  						},
   152  
   153  						"iops": {
   154  							Type:     schema.TypeInt,
   155  							Computed: true,
   156  						},
   157  
   158  						"snapshot_id": {
   159  							Type:     schema.TypeString,
   160  							Computed: true,
   161  						},
   162  
   163  						"volume_size": {
   164  							Type:     schema.TypeInt,
   165  							Computed: true,
   166  						},
   167  
   168  						"volume_type": {
   169  							Type:     schema.TypeString,
   170  							Computed: true,
   171  						},
   172  					},
   173  				},
   174  			},
   175  			"root_block_device": {
   176  				Type:     schema.TypeSet,
   177  				Computed: true,
   178  				Elem: &schema.Resource{
   179  					Schema: map[string]*schema.Schema{
   180  						"delete_on_termination": {
   181  							Type:     schema.TypeBool,
   182  							Computed: true,
   183  						},
   184  
   185  						"iops": {
   186  							Type:     schema.TypeInt,
   187  							Computed: true,
   188  						},
   189  
   190  						"volume_size": {
   191  							Type:     schema.TypeInt,
   192  							Computed: true,
   193  						},
   194  
   195  						"volume_type": {
   196  							Type:     schema.TypeString,
   197  							Computed: true,
   198  						},
   199  					},
   200  				},
   201  			},
   202  		},
   203  	}
   204  }
   205  
   206  // dataSourceAwsInstanceRead performs the instanceID lookup
   207  func dataSourceAwsInstanceRead(d *schema.ResourceData, meta interface{}) error {
   208  	conn := meta.(*AWSClient).ec2conn
   209  
   210  	filters, filtersOk := d.GetOk("filter")
   211  	instanceID, instanceIDOk := d.GetOk("instance_id")
   212  	tags, tagsOk := d.GetOk("instance_tags")
   213  
   214  	if filtersOk == false && instanceIDOk == false && tagsOk == false {
   215  		return fmt.Errorf("One of filters, instance_tags, or instance_id must be assigned")
   216  	}
   217  
   218  	// Build up search parameters
   219  	params := &ec2.DescribeInstancesInput{}
   220  	if filtersOk {
   221  		params.Filters = buildAwsDataSourceFilters(filters.(*schema.Set))
   222  	}
   223  	if instanceIDOk {
   224  		params.InstanceIds = []*string{aws.String(instanceID.(string))}
   225  	}
   226  	if tagsOk {
   227  		params.Filters = append(params.Filters, buildEC2TagFilterList(
   228  			tagsFromMap(tags.(map[string]interface{})),
   229  		)...)
   230  	}
   231  
   232  	// Perform the lookup
   233  	resp, err := conn.DescribeInstances(params)
   234  	if err != nil {
   235  		return err
   236  	}
   237  
   238  	// If no instances were returned, return
   239  	if len(resp.Reservations) == 0 {
   240  		return fmt.Errorf("Your query returned no results. Please change your search criteria and try again.")
   241  	}
   242  
   243  	var filteredInstances []*ec2.Instance
   244  
   245  	// loop through reservations, and remove terminated instances, populate instance slice
   246  	for _, res := range resp.Reservations {
   247  		for _, instance := range res.Instances {
   248  			if instance.State != nil && *instance.State.Name != "terminated" {
   249  				filteredInstances = append(filteredInstances, instance)
   250  			}
   251  		}
   252  	}
   253  
   254  	var instance *ec2.Instance
   255  	if len(filteredInstances) < 1 {
   256  		return fmt.Errorf("Your query returned no results. Please change your search criteria and try again.")
   257  	}
   258  
   259  	// (TODO: Support a list of instances to be returned)
   260  	// Possibly with a different data source that returns a list of individual instance data sources
   261  	if len(filteredInstances) > 1 {
   262  		return fmt.Errorf("Your query returned more than one result. Please try a more " +
   263  			"specific search criteria.")
   264  	} else {
   265  		instance = filteredInstances[0]
   266  	}
   267  
   268  	log.Printf("[DEBUG] aws_instance - Single Instance ID found: %s", *instance.InstanceId)
   269  	return instanceDescriptionAttributes(d, instance, conn)
   270  }
   271  
   272  // Populate instance attribute fields with the returned instance
   273  func instanceDescriptionAttributes(d *schema.ResourceData, instance *ec2.Instance, conn *ec2.EC2) error {
   274  	d.SetId(*instance.InstanceId)
   275  	// Set the easy attributes
   276  	d.Set("instance_state", instance.State.Name)
   277  	if instance.Placement != nil {
   278  		d.Set("availability_zone", instance.Placement.AvailabilityZone)
   279  	}
   280  	if instance.Placement.Tenancy != nil {
   281  		d.Set("tenancy", instance.Placement.Tenancy)
   282  	}
   283  	d.Set("ami", instance.ImageId)
   284  	d.Set("instance_type", instance.InstanceType)
   285  	d.Set("key_name", instance.KeyName)
   286  	d.Set("public_dns", instance.PublicDnsName)
   287  	d.Set("public_ip", instance.PublicIpAddress)
   288  	d.Set("private_dns", instance.PrivateDnsName)
   289  	d.Set("private_ip", instance.PrivateIpAddress)
   290  	d.Set("iam_instance_profile", iamInstanceProfileArnToName(instance.IamInstanceProfile))
   291  
   292  	// iterate through network interfaces, and set subnet, network_interface, public_addr
   293  	if len(instance.NetworkInterfaces) > 0 {
   294  		for _, ni := range instance.NetworkInterfaces {
   295  			if *ni.Attachment.DeviceIndex == 0 {
   296  				d.Set("subnet_id", ni.SubnetId)
   297  				d.Set("network_interface_id", ni.NetworkInterfaceId)
   298  				d.Set("associate_public_ip_address", ni.Association != nil)
   299  			}
   300  		}
   301  	} else {
   302  		d.Set("subnet_id", instance.SubnetId)
   303  		d.Set("network_interface_id", "")
   304  	}
   305  
   306  	d.Set("ebs_optimized", instance.EbsOptimized)
   307  	if instance.SubnetId != nil && *instance.SubnetId != "" {
   308  		d.Set("source_dest_check", instance.SourceDestCheck)
   309  	}
   310  
   311  	if instance.Monitoring != nil && instance.Monitoring.State != nil {
   312  		monitoringState := *instance.Monitoring.State
   313  		d.Set("monitoring", monitoringState == "enabled" || monitoringState == "pending")
   314  	}
   315  
   316  	d.Set("tags", dataSourceTags(instance.Tags))
   317  
   318  	// Security Groups
   319  	if err := readSecurityGroups(d, instance); err != nil {
   320  		return err
   321  	}
   322  
   323  	// Block devices
   324  	if err := readBlockDevices(d, instance, conn); err != nil {
   325  		return err
   326  	}
   327  	if _, ok := d.GetOk("ephemeral_block_device"); !ok {
   328  		d.Set("ephemeral_block_device", []interface{}{})
   329  	}
   330  
   331  	// Lookup and Set Instance Attributes
   332  	{
   333  		attr, err := conn.DescribeInstanceAttribute(&ec2.DescribeInstanceAttributeInput{
   334  			Attribute:  aws.String("disableApiTermination"),
   335  			InstanceId: aws.String(d.Id()),
   336  		})
   337  		if err != nil {
   338  			return err
   339  		}
   340  		d.Set("disable_api_termination", attr.DisableApiTermination.Value)
   341  	}
   342  	{
   343  		attr, err := conn.DescribeInstanceAttribute(&ec2.DescribeInstanceAttributeInput{
   344  			Attribute:  aws.String(ec2.InstanceAttributeNameUserData),
   345  			InstanceId: aws.String(d.Id()),
   346  		})
   347  		if err != nil {
   348  			return err
   349  		}
   350  		if attr.UserData.Value != nil {
   351  			d.Set("user_data", userDataHashSum(*attr.UserData.Value))
   352  		}
   353  	}
   354  
   355  	return nil
   356  }