1package main
2
3import (
4	"bytes"
5	"fmt"
6	"io"
7	"io/ioutil"
8	"time"
9
10	"github.com/aws/aws-sdk-go/aws"
11	"github.com/aws/aws-sdk-go/service/s3"
12)
13
14// It's not clear from the docs what S3 does when versioning has been enabled,
15// then suspended, then you request a version ID that exists.
16//
17// Turns out it continues to work just fine.
18//
19// This script also revealed that a bucket that has never had versioning will
20// return empty strings for Status and MFADelete.
21type S300001GetVersionAfterVersioningSuspended struct{}
22
23func (t *S300001GetVersionAfterVersioningSuspended) Run(ctx *Context) error {
24	client := ctx.S3Client()
25	config := ctx.Config()
26
27	bucket := aws.String(config.BucketStandard())
28
29	if err := ctx.EnsureVersioningEnabled(client, config.BucketStandard()); err != nil {
30		return err
31	}
32
33	// FIXME: defer delete object
34
35	key := fmt.Sprintf("%d/%s", time.Now().UnixNano(), ctx.RandString(32))
36
37	var versions = map[string][]byte{}
38
39	for i := 0; i < 3; i++ {
40		body := ctx.RandBytes(32)
41		rs, err := client.PutObject(&s3.PutObjectInput{
42			Key:    aws.String(key),
43			Body:   bytes.NewReader(body),
44			Bucket: bucket,
45		})
46		if err != nil {
47			return err
48		}
49
50		ver := aws.StringValue(rs.VersionId)
51		if ver == "" {
52			return fmt.Errorf("missing version ID")
53		}
54		versions[ver] = body
55	}
56
57	if _, err := client.PutBucketVersioning(&s3.PutBucketVersioningInput{
58		Bucket: bucket,
59		VersioningConfiguration: &s3.VersioningConfiguration{
60			Status: aws.String("Suspended"),
61		},
62	}); err != nil {
63		return err
64	}
65
66	{
67		vers, err := client.GetBucketVersioning(&s3.GetBucketVersioningInput{Bucket: bucket})
68		if err != nil {
69			return err
70		}
71		status := aws.StringValue(vers.Status)
72		if status != "Suspended" {
73			return fmt.Errorf("unexpected status %q", status)
74		}
75	}
76
77	readCloseBody := func(rdr io.ReadCloser) ([]byte, error) {
78		defer rdr.Close()
79		return ioutil.ReadAll(rdr)
80	}
81
82	for ver, body := range versions {
83		rs, err := client.GetObject(&s3.GetObjectInput{
84			Key:       aws.String(key),
85			Bucket:    bucket,
86			VersionId: aws.String(ver),
87		})
88		if err != nil {
89			return err
90		}
91		rbody, err := readCloseBody(rs.Body)
92		if err != nil {
93			return err
94		}
95
96		if !bytes.Equal(body, rbody) {
97			return fmt.Errorf("version not equal")
98		}
99	}
100
101	return nil
102}
103