]>
Commit | Line | Data |
---|---|---|
bae9f6d2 JC |
1 | package ec2metadata |
2 | ||
3 | import ( | |
4 | "encoding/json" | |
5 | "fmt" | |
6 | "net/http" | |
bae9f6d2 JC |
7 | "strings" |
8 | "time" | |
9 | ||
10 | "github.com/aws/aws-sdk-go/aws/awserr" | |
11 | "github.com/aws/aws-sdk-go/aws/request" | |
15c0b25d | 12 | "github.com/aws/aws-sdk-go/internal/sdkuri" |
bae9f6d2 JC |
13 | ) |
14 | ||
15 | // GetMetadata uses the path provided to request information from the EC2 | |
16 | // instance metdata service. The content will be returned as a string, or | |
17 | // error if the request failed. | |
18 | func (c *EC2Metadata) GetMetadata(p string) (string, error) { | |
19 | op := &request.Operation{ | |
20 | Name: "GetMetadata", | |
21 | HTTPMethod: "GET", | |
15c0b25d | 22 | HTTPPath: sdkuri.PathJoin("/meta-data", p), |
bae9f6d2 JC |
23 | } |
24 | ||
25 | output := &metadataOutput{} | |
26 | req := c.NewRequest(op, nil, output) | |
107c1cdb | 27 | err := req.Send() |
bae9f6d2 | 28 | |
107c1cdb | 29 | return output.Content, err |
bae9f6d2 JC |
30 | } |
31 | ||
32 | // GetUserData returns the userdata that was configured for the service. If | |
33 | // there is no user-data setup for the EC2 instance a "NotFoundError" error | |
34 | // code will be returned. | |
35 | func (c *EC2Metadata) GetUserData() (string, error) { | |
36 | op := &request.Operation{ | |
37 | Name: "GetUserData", | |
38 | HTTPMethod: "GET", | |
15c0b25d | 39 | HTTPPath: "/user-data", |
bae9f6d2 JC |
40 | } |
41 | ||
42 | output := &metadataOutput{} | |
43 | req := c.NewRequest(op, nil, output) | |
44 | req.Handlers.UnmarshalError.PushBack(func(r *request.Request) { | |
45 | if r.HTTPResponse.StatusCode == http.StatusNotFound { | |
46 | r.Error = awserr.New("NotFoundError", "user-data not found", r.Error) | |
47 | } | |
48 | }) | |
107c1cdb | 49 | err := req.Send() |
bae9f6d2 | 50 | |
107c1cdb | 51 | return output.Content, err |
bae9f6d2 JC |
52 | } |
53 | ||
54 | // GetDynamicData uses the path provided to request information from the EC2 | |
55 | // instance metadata service for dynamic data. The content will be returned | |
56 | // as a string, or error if the request failed. | |
57 | func (c *EC2Metadata) GetDynamicData(p string) (string, error) { | |
58 | op := &request.Operation{ | |
59 | Name: "GetDynamicData", | |
60 | HTTPMethod: "GET", | |
15c0b25d | 61 | HTTPPath: sdkuri.PathJoin("/dynamic", p), |
bae9f6d2 JC |
62 | } |
63 | ||
64 | output := &metadataOutput{} | |
65 | req := c.NewRequest(op, nil, output) | |
107c1cdb | 66 | err := req.Send() |
bae9f6d2 | 67 | |
107c1cdb | 68 | return output.Content, err |
bae9f6d2 JC |
69 | } |
70 | ||
71 | // GetInstanceIdentityDocument retrieves an identity document describing an | |
72 | // instance. Error is returned if the request fails or is unable to parse | |
73 | // the response. | |
74 | func (c *EC2Metadata) GetInstanceIdentityDocument() (EC2InstanceIdentityDocument, error) { | |
75 | resp, err := c.GetDynamicData("instance-identity/document") | |
76 | if err != nil { | |
77 | return EC2InstanceIdentityDocument{}, | |
78 | awserr.New("EC2MetadataRequestError", | |
79 | "failed to get EC2 instance identity document", err) | |
80 | } | |
81 | ||
82 | doc := EC2InstanceIdentityDocument{} | |
83 | if err := json.NewDecoder(strings.NewReader(resp)).Decode(&doc); err != nil { | |
84 | return EC2InstanceIdentityDocument{}, | |
85 | awserr.New("SerializationError", | |
86 | "failed to decode EC2 instance identity document", err) | |
87 | } | |
88 | ||
89 | return doc, nil | |
90 | } | |
91 | ||
92 | // IAMInfo retrieves IAM info from the metadata API | |
93 | func (c *EC2Metadata) IAMInfo() (EC2IAMInfo, error) { | |
94 | resp, err := c.GetMetadata("iam/info") | |
95 | if err != nil { | |
96 | return EC2IAMInfo{}, | |
97 | awserr.New("EC2MetadataRequestError", | |
98 | "failed to get EC2 IAM info", err) | |
99 | } | |
100 | ||
101 | info := EC2IAMInfo{} | |
102 | if err := json.NewDecoder(strings.NewReader(resp)).Decode(&info); err != nil { | |
103 | return EC2IAMInfo{}, | |
104 | awserr.New("SerializationError", | |
105 | "failed to decode EC2 IAM info", err) | |
106 | } | |
107 | ||
108 | if info.Code != "Success" { | |
109 | errMsg := fmt.Sprintf("failed to get EC2 IAM Info (%s)", info.Code) | |
110 | return EC2IAMInfo{}, | |
111 | awserr.New("EC2MetadataError", errMsg, nil) | |
112 | } | |
113 | ||
114 | return info, nil | |
115 | } | |
116 | ||
117 | // Region returns the region the instance is running in. | |
118 | func (c *EC2Metadata) Region() (string, error) { | |
119 | resp, err := c.GetMetadata("placement/availability-zone") | |
120 | if err != nil { | |
121 | return "", err | |
122 | } | |
123 | ||
107c1cdb ND |
124 | if len(resp) == 0 { |
125 | return "", awserr.New("EC2MetadataError", "invalid Region response", nil) | |
126 | } | |
127 | ||
bae9f6d2 JC |
128 | // returns region without the suffix. Eg: us-west-2a becomes us-west-2 |
129 | return resp[:len(resp)-1], nil | |
130 | } | |
131 | ||
132 | // Available returns if the application has access to the EC2 Metadata service. | |
133 | // Can be used to determine if application is running within an EC2 Instance and | |
134 | // the metadata service is available. | |
135 | func (c *EC2Metadata) Available() bool { | |
136 | if _, err := c.GetMetadata("instance-id"); err != nil { | |
137 | return false | |
138 | } | |
139 | ||
140 | return true | |
141 | } | |
142 | ||
143 | // An EC2IAMInfo provides the shape for unmarshaling | |
144 | // an IAM info from the metadata API | |
145 | type EC2IAMInfo struct { | |
146 | Code string | |
147 | LastUpdated time.Time | |
148 | InstanceProfileArn string | |
149 | InstanceProfileID string | |
150 | } | |
151 | ||
152 | // An EC2InstanceIdentityDocument provides the shape for unmarshaling | |
153 | // an instance identity document | |
154 | type EC2InstanceIdentityDocument struct { | |
155 | DevpayProductCodes []string `json:"devpayProductCodes"` | |
156 | AvailabilityZone string `json:"availabilityZone"` | |
157 | PrivateIP string `json:"privateIp"` | |
158 | Version string `json:"version"` | |
159 | Region string `json:"region"` | |
160 | InstanceID string `json:"instanceId"` | |
161 | BillingProducts []string `json:"billingProducts"` | |
162 | InstanceType string `json:"instanceType"` | |
163 | AccountID string `json:"accountId"` | |
164 | PendingTime time.Time `json:"pendingTime"` | |
165 | ImageID string `json:"imageId"` | |
166 | KernelID string `json:"kernelId"` | |
167 | RamdiskID string `json:"ramdiskId"` | |
168 | Architecture string `json:"architecture"` | |
169 | } |