Merge lp:~dave-cheney/goamz/004-send-409-conflict into lp:~gophers/goamz/trunk

Proposed by Dave Cheney
Status: Merged
Merged at revision: 25
Proposed branch: lp:~dave-cheney/goamz/004-send-409-conflict
Merge into: lp:~gophers/goamz/trunk
Diff against target: 183 lines (+63/-10)
4 files modified
s3/s3.go (+2/-2)
s3/s3i_test.go (+12/-0)
s3/s3t_test.go (+17/-2)
s3/s3test/server.go (+32/-6)
To merge this branch: bzr merge lp:~dave-cheney/goamz/004-send-409-conflict
Reviewer Review Type Date Requested Status
The Go Language Gophers Pending
Review via email: mp+138903@code.launchpad.net

Description of the change

s3: add support for 409 responses

Required to fix LP 1042107

https://codereview.appspot.com/6901061/

To post a comment you must log in.
Revision history for this message
William Reade (fwereade) wrote :
Revision history for this message
John A Meinel (jameinel) wrote :

The change LGTM, but there are some small questions.
1) If you're changing the service to return 409, shouldn't there be a
corresponding client-side change that says "oh 409, that means it
already exists and I should just treat it as a duplicate".

2) Should we have something more like:
  s.emulate = "us-east-1"

Rather than a simple boolean s.emulateUSEast1? I'm thinking that
eventually we may find that USEast2 acts differently from USWest, vs
Asia, etc.

I realize that us-east-1 is the most tested at this point, but it does
seem like you want more than 1 bit of info for the parametrization of
the test server.

https://codereview.appspot.com/6901061/

Revision history for this message
John A Meinel (jameinel) wrote :

I see that I missed your patch to juju-core to handle the 409 case.
Though I do still wonder if it should be handled inside goamz rather
than being handled in juju-core.

https://codereview.appspot.com/6901061/

Revision history for this message
Roger Peppe (rogpeppe) wrote :

On 2012/12/10 08:38:24, jameinel wrote:
> 2) Should we have something more like:
> s.emulate = "us-east-1"

i'd be happier with this too. that means we can add any
number of region-specific tweaks in the future. who
knows what differences there are?

https://codereview.appspot.com/6901061/

27. By Dave Cheney

responding to review feedback

Revision history for this message
John A Meinel (jameinel) wrote :

On 2012/12/10 23:40:16, dfc wrote:
> On 2012/12/10 23:39:03, dfc wrote:
> > Please take a look.

> Thanks for your comments. I have added a *Config style structure which
can be
> extended when we need more control over the s3test.Server.

LGTM. If you want, we could have a "useast1_config" and a "uswest1" or
whatever. So we don't have to figure out what the various configs
actually mean. But overall it seems fine to me.

https://codereview.appspot.com/6901061/

Revision history for this message
John A Meinel (jameinel) wrote :

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 2012-12-11 9:15, Dave Cheney wrote:
> We could do that with a set of *Configs, ie
>
> var USEast1 *Config var USWest1 = &Config { Send409Conflict: true,
> }
>
> and so on ...

That was my thought, yes.

John
=:->

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.12 (Cygwin)
Comment: Using GnuPG with undefined - http://www.enigmail.net/

iEYEARECAAYFAlDGxzkACgkQJdeBCYSNAAME8ACfU6V4r4Yb1pOfotGdi7yyRK/b
DCYAnRYRLboFTvnU2ftHUY3igXQI3gBs
=fCP5
-----END PGP SIGNATURE-----

Revision history for this message
Roger Peppe (rogpeppe) wrote :

LGTM
On Dec 11, 2012 5:43 AM, "John A Meinel" <email address hidden> wrote:

> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> On 2012-12-11 9:15, Dave Cheney wrote:
> > We could do that with a set of *Configs, ie
> >
> > var USEast1 *Config var USWest1 = &Config { Send409Conflict: true,
> > }
> >
> > and so on ...
>
> That was my thought, yes.
>
> John
> =:->
>
> -----BEGIN PGP SIGNATURE-----
> Version: GnuPG v1.4.12 (Cygwin)
> Comment: Using GnuPG with undefined - http://www.enigmail.net/
>
> iEYEARECAAYFAlDGxzkACgkQJdeBCYSNAAME8ACfU6V4r4Yb1pOfotGdi7yyRK/b
> DCYAnRYRLboFTvnU2ftHUY3igXQI3gBs
> =fCP5
> -----END PGP SIGNATURE-----
>
> --
>
> https://code.launchpad.net/~dave-cheney/goamz/004-send-409-conflict/+merge/138903
> Your team The Go Language Gophers is requested to review the proposed
> merge of lp:~dave-cheney/goamz/004-send-409-conflict into lp:goamz.
>

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 's3/s3.go'
2--- s3/s3.go 2012-07-19 13:51:13 +0000
3+++ s3/s3.go 2012-12-10 23:40:24 +0000
4@@ -64,7 +64,7 @@
5 <LocationConstraint>%s</LocationConstraint>
6 </CreateBucketConfiguration>`
7
8-// locationConstraint returns an io.Reader specifying a LocationConstraint if
9+// locationConstraint returns an io.Reader specifying a LocationConstraint if
10 // required for the region.
11 //
12 // See http://goo.gl/bh9Kq for more details.
13@@ -269,7 +269,7 @@
14 // "photos/2006/January/",
15 // },
16 // }
17-//
18+//
19 // See http://goo.gl/YjQTc for more details.
20 func (b *Bucket) List(prefix, delim, marker string, max int) (result *ListResp, err error) {
21 params := map[string][]string{
22
23=== modified file 's3/s3i_test.go'
24--- s3/s3i_test.go 2012-07-12 01:56:51 +0000
25+++ s3/s3i_test.go 2012-12-10 23:40:24 +0000
26@@ -299,6 +299,18 @@
27 },
28 }
29
30+func (s *ClientTests) TestDoublePutBucket(c *C) {
31+ b := s.Bucket(testBucket)
32+ err := b.PutBucket(s3.PublicRead)
33+ c.Assert(err, IsNil)
34+
35+ err = b.PutBucket(s3.PublicRead)
36+ if err != nil {
37+ c.Assert(err, FitsTypeOf, new(s3.Error))
38+ c.Assert(err.(*s3.Error).Code, Equals, "BucketAlreadyOwnedByYou")
39+ }
40+}
41+
42 func (s *ClientTests) TestBucketList(c *C) {
43 b := s.Bucket(testBucket)
44 err := b.PutBucket(s3.Private)
45
46=== modified file 's3/s3t_test.go'
47--- s3/s3t_test.go 2012-07-06 03:23:10 +0000
48+++ s3/s3t_test.go 2012-12-10 23:40:24 +0000
49@@ -11,10 +11,11 @@
50 auth aws.Auth
51 region aws.Region
52 srv *s3test.Server
53+ config *s3test.Config
54 }
55
56 func (s *LocalServer) SetUp(c *C) {
57- srv, err := s3test.NewServer()
58+ srv, err := s3test.NewServer(s.config)
59 c.Assert(err, IsNil)
60 c.Assert(srv, NotNil)
61
62@@ -36,7 +37,17 @@
63 clientTests ClientTests
64 }
65
66-var _ = Suite(&LocalServerSuite{})
67+var (
68+ // run tests twice, once in us-east-1 mode, once not.
69+ _ = Suite(&LocalServerSuite{})
70+ _ = Suite(&LocalServerSuite{
71+ srv: LocalServer{
72+ config: &s3test.Config{
73+ Send409Conflict: true,
74+ },
75+ },
76+ })
77+)
78
79 func (s *LocalServerSuite) SetUpSuite(c *C) {
80 s.srv.SetUp(c)
81@@ -57,3 +68,7 @@
82 func (s *LocalServerSuite) TestBucketList(c *C) {
83 s.clientTests.TestBucketList(c)
84 }
85+
86+func (s *LocalServerSuite) TestDoublePutBucket(c *C) {
87+ s.clientTests.TestDoublePutBucket(c)
88+}
89
90=== modified file 's3/s3test/server.go'
91--- s3/s3test/server.go 2012-07-05 05:47:52 +0000
92+++ s3/s3test/server.go 2012-12-10 23:40:24 +0000
93@@ -40,6 +40,25 @@
94 reqId string
95 }
96
97+// Config controls the internal behaviour of the Server. A nil config is the default
98+// and behaves as if all configurations assume their default behaviour. Once passed
99+// to NewServer, the configuration must not be modified.
100+type Config struct {
101+ // Send409Conflict controls how the Server will respond to calls to PUT on a
102+ // previously existing bucket. The default is false, and corresponds to the
103+ // us-east-1 s3 enpoint. Setting this value to true emulates the behaviour of
104+ // all other regions.
105+ // http://docs.amazonwebservices.com/AmazonS3/latest/API/ErrorResponses.html
106+ Send409Conflict bool
107+}
108+
109+func (c *Config) send409Conflict() bool {
110+ if c != nil {
111+ return c.Send409Conflict
112+ }
113+ return false
114+}
115+
116 // Server is a fake S3 server for testing purposes.
117 // All of the data for the server is kept in memory.
118 type Server struct {
119@@ -48,6 +67,7 @@
120 listener net.Listener
121 mu sync.Mutex
122 buckets map[string]*bucket
123+ config *Config
124 }
125
126 type bucket struct {
127@@ -75,7 +95,7 @@
128 delete(a *action) interface{}
129 }
130
131-func NewServer() (*Server, error) {
132+func NewServer(config *Config) (*Server, error) {
133 l, err := net.Listen("tcp", "localhost:0")
134 if err != nil {
135 return nil, fmt.Errorf("cannot listen on localhost: %v", err)
136@@ -84,6 +104,7 @@
137 listener: l,
138 url: "http://" + l.Addr().String(),
139 buckets: make(map[string]*bucket),
140+ config: config,
141 }
142 go http.Serve(l, http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
143 srv.serveHTTP(w, req)
144@@ -386,6 +407,7 @@
145 // PUT on a bucket creates the bucket.
146 // http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketPUT.html
147 func (r bucketResource) put(a *action) interface{} {
148+ var created bool
149 if r.bucket == nil {
150 if !validBucketName(r.name) {
151 fatalf(400, "InvalidBucketName", "The specified bucket is not valid")
152@@ -400,6 +422,10 @@
153 objects: make(map[string]*object),
154 }
155 a.srv.buckets[r.name] = r.bucket
156+ created = true
157+ }
158+ if !created && a.srv.config.send409Conflict() {
159+ fatalf(409, "BucketAlreadyOwnedByYou", "Your previous request to create the named bucket succeeded and you already own it.")
160 }
161 r.bucket.acl = s3.ACL(a.req.Header.Get("x-amz-acl"))
162 return nil
163@@ -413,15 +439,15 @@
164 // validBucketName returns whether name is a valid bucket name.
165 // Here are the rules, from:
166 // http://docs.amazonwebservices.com/AmazonS3/2006-03-01/dev/BucketRestrictions.html
167-//
168-// Can contain lowercase letters, numbers, periods (.), underscores (_),
169+//
170+// Can contain lowercase letters, numbers, periods (.), underscores (_),
171 // and dashes (-). You can use uppercase letters for buckets only in the
172 // US Standard region.
173-//
174+//
175 // Must start with a number or letter
176-//
177+//
178 // Must be between 3 and 255 characters long
179-//
180+//
181 // There's one extra rule (Must not be formatted as an IP address (e.g., 192.168.5.4)
182 // but the real S3 server does not seem to check that rule, so we will not
183 // check it either.

Subscribers

People subscribed via source and target branches