1package imds
2
3import (
4	"context"
5	"encoding/json"
6	"fmt"
7	"io"
8	"strings"
9	"time"
10
11	"github.com/aws/smithy-go"
12	smithyio "github.com/aws/smithy-go/io"
13	"github.com/aws/smithy-go/middleware"
14	smithyhttp "github.com/aws/smithy-go/transport/http"
15)
16
17const getIAMInfoPath = getMetadataPath + "/iam/info"
18
19// GetIAMInfo retrieves an identity document describing an
20// instance. Error is returned if the request fails or is unable to parse
21// the response.
22func (c *Client) GetIAMInfo(
23	ctx context.Context, params *GetIAMInfoInput, optFns ...func(*Options),
24) (
25	*GetIAMInfoOutput, error,
26) {
27	if params == nil {
28		params = &GetIAMInfoInput{}
29	}
30
31	result, metadata, err := c.invokeOperation(ctx, "GetIAMInfo", params, optFns,
32		addGetIAMInfoMiddleware,
33	)
34	if err != nil {
35		return nil, err
36	}
37
38	out := result.(*GetIAMInfoOutput)
39	out.ResultMetadata = metadata
40	return out, nil
41}
42
43// GetIAMInfoInput provides the input parameters for GetIAMInfo operation.
44type GetIAMInfoInput struct{}
45
46// GetIAMInfoOutput provides the output parameters for GetIAMInfo operation.
47type GetIAMInfoOutput struct {
48	IAMInfo
49
50	ResultMetadata middleware.Metadata
51}
52
53func addGetIAMInfoMiddleware(stack *middleware.Stack, options Options) error {
54	return addAPIRequestMiddleware(stack,
55		options,
56		buildGetIAMInfoPath,
57		buildGetIAMInfoOutput,
58	)
59}
60
61func buildGetIAMInfoPath(params interface{}) (string, error) {
62	return getIAMInfoPath, nil
63}
64
65func buildGetIAMInfoOutput(resp *smithyhttp.Response) (v interface{}, err error) {
66	defer func() {
67		closeErr := resp.Body.Close()
68		if err == nil {
69			err = closeErr
70		} else if closeErr != nil {
71			err = fmt.Errorf("response body close error: %v, original error: %w", closeErr, err)
72		}
73	}()
74
75	var buff [1024]byte
76	ringBuffer := smithyio.NewRingBuffer(buff[:])
77	body := io.TeeReader(resp.Body, ringBuffer)
78
79	imdsResult := &GetIAMInfoOutput{}
80	if err = json.NewDecoder(body).Decode(&imdsResult.IAMInfo); err != nil {
81		return nil, &smithy.DeserializationError{
82			Err:      fmt.Errorf("failed to decode instance identity document, %w", err),
83			Snapshot: ringBuffer.Bytes(),
84		}
85	}
86	// Any code other success is an error
87	if !strings.EqualFold(imdsResult.Code, "success") {
88		return nil, fmt.Errorf("failed to get EC2 IMDS IAM info, %s",
89			imdsResult.Code)
90	}
91
92	return imdsResult, nil
93}
94
95// IAMInfo provides the shape for unmarshaling an IAM info from the metadata
96// API.
97type IAMInfo struct {
98	Code               string
99	LastUpdated        time.Time
100	InstanceProfileArn string
101	InstanceProfileID  string
102}
103