Merge lp:~jtv/juju-core/session-certificate into lp:~go-bot/juju-core/trunk

Proposed by Jeroen T. Vermeulen
Status: Merged
Approved by: Jeroen T. Vermeulen
Approved revision: no longer in the source branch.
Merged at revision: 1315
Proposed branch: lp:~jtv/juju-core/session-certificate
Merge into: lp:~go-bot/juju-core/trunk
Prerequisite: lp:~jtv/juju-core/create-gwacl-sessions
Diff against target: 113 lines (+67/-15)
2 files modified
environs/azure/environ.go (+45/-8)
environs/azure/environ_test.go (+22/-7)
To merge this branch: bzr merge lp:~jtv/juju-core/session-certificate
Reviewer Review Type Date Requested Status
Jeroen T. Vermeulen (community) Approve
Review via email: mp+170611@code.launchpad.net

Commit message

Create temporary cert file for each ManagementAPI.

For now, each high-level function in the Azure provider will create its own storage contexts and management-API objects as needed. In the case of the management API, that comes with a temporary file containing an Azure certificate. (There is another way to pass the certificate to go-curl, but we want to avoid the complications and especially the unknowns at this point).

Once done with your request(s) to the management, you release it. This cleans up the certificate file, but in the future it may also serve as a hook for connection pooling. We'll treat optimization as a separate problem — it seems easy but this sort of thing often brings out creative tendencies that aren't worth the time just at the moment. As long as we don't need any actual cleanup code for the storage-API side, we chose not to create a cleanup method there. This is all internal detail after all; it doesn't affect any exported APIs.

Description of the change

To post a comment you must log in.
Revision history for this message
Martin Packman (gz) wrote :

Seems rietveld is still confused about the branch target here, looks
like it's comparing against an older trunk?

 From the diff in launchpad though, LGTM. Double check the merge makes
sense before landing. :)

https://codereview.appspot.com/10443043/

Revision history for this message
Jeroen T. Vermeulen (jtv) wrote :

mgz voted LGTM on the Rietveld merge proposal, but we created that after the LP one was already up and it seems a little confused.

Revision history for this message
Jeroen T. Vermeulen (jtv) wrote :

Continuing with a new Rietveld MP to replace the old one.

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

LGTM with some minor suggestions below.

https://codereview.appspot.com/10447043/diff/1/environs/azure/environ.go
File environs/azure/environ.go (right):

https://codereview.appspot.com/10447043/diff/1/environs/azure/environ.go#newcode153
environs/azure/environ.go:153: certFile, err :=
newTempCertFile([]byte(certData))
i hope we manage to avoid the need for these temporary files sooner
rather than later.

https://codereview.appspot.com/10447043/diff/1/environs/azure/environ.go#newcode158
environs/azure/environ.go:158: // make sure we clean up that certificate
file.
rather than recovering, i think a better approach might be something
like this:
func (env *azureEnviron) getManagementAPI() (_ *azureManagementContext,
retErr) {
      ...
       certFile, err := newTempCertFile([]byte(certData))
       if err != nil {
           return nil, err
       }
       defer func() {
           if retErr != nil {
               certFile.Delete()
           }
       }()

which amounts to much the same thing except you don't
need to call certFile.Delete if NewManagementAPI fails.

To be honest though, we're not gaining that much
by deleting the file even when we panic. That
will only happen if NewManagementAPI itself panics,
not if any other goroutine panics.

I'd probably just delete the defer and leave the
Delete in the NewManagementAPI error case.
Anyone with access to read the cert file
probably has access to get the environment
config anyway, so it's not a huge security issue.

https://codereview.appspot.com/10447043/diff/1/environs/azure/environ.go#newcode178
environs/azure/environ.go:178: // releaseManagementAPI frees up a
context object for interfacing with Azure's
// releaseManagementAPI frees up an Azure management context.
?

https://codereview.appspot.com/10447043/diff/1/environs/azure/environ_test.go
File environs/azure/environ_test.go (right):

https://codereview.appspot.com/10447043/diff/1/environs/azure/environ_test.go#newcode104
environs/azure/environ_test.go:104: }
i wouldn't mind seeing a test that checks that the temporary cert file
is deleted when NewManagementAPI fails.

https://codereview.appspot.com/10447043/

Revision history for this message
Jeroen T. Vermeulen (jtv) wrote :

LGTM votes from mgz and rogpeppe. Thanks!

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

On 20 June 2013 17:58, <email address hidden> wrote:
> Thanks Roger!
>
>
> On 2013/06/20 16:40:57, rog wrote:
>
>> i hope we manage to avoid the need for these temporary files sooner
>
> rather than
>>
>> later.
>
>
> Absolutely. There are several ways it might happen: by replacing
> libcurl with Go's built-in http library if it starts supporting this
> site, or by going through libcurl's in-memory mechanism for passing the
> certificates, or by storing the certificate somewhere slightly more
> durable perhaps. That's in descending order of desirability.
>
>
>
>> I'd probably just delete the defer and leave the
>> Delete in the NewManagementAPI error case.
>
>
> Done.
>
>
>
>> environs/azure/environ.go:178: // releaseManagementAPI frees up a
>
> context object
>>
>> for interfacing with Azure's
>> // releaseManagementAPI frees up an Azure management context.
>> ?
>
>
> I just made it say that it frees up the context object returned by
> getManagementAPI. Once. :)
>
>
>
>> i wouldn't mind seeing a test that checks that the temporary cert file
>
> is
>>
>> deleted when NewManagementAPI fails.
>
>
> There doesn't currently seem to be a failure path!

maybe just delete the error return from NewManagementAPI then
and code goes away :-)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'environs/azure/environ.go'
2--- environs/azure/environ.go 2013-06-20 13:43:05 +0000
3+++ environs/azure/environ.go 2013-06-20 17:02:46 +0000
4@@ -129,21 +129,58 @@
5 panic("unimplemented")
6 }
7
8-// TODO: Temporarily deactivating this code. Passing certificate in-memory
9-// may require gwacl change.
10-/*
11+// azureManagementContext wraps two things: a gwacl.ManagementAPI (effectively
12+// a session on the Azure management API) and a tempCertFile, which keeps track
13+// of the temporary certificate file that needs to be deleted once we're done
14+// with this particular session.
15+// Since it embeds *gwacl.ManagementAPI, you can use it much as if it were a
16+// pointer to a ManagementAPI object. Just don't forget to release it after
17+// use.
18+type azureManagementContext struct {
19+ *gwacl.ManagementAPI
20+ certFile *tempCertFile
21+}
22+
23 // getManagementAPI obtains a context object for interfacing with Azure's
24 // management API.
25 // For now, each invocation just returns a separate object. This is probably
26 // wasteful (each context gets its own SSL connection) and may need optimizing
27 // later.
28-func (env *azureEnviron) getManagementAPI() (*gwacl.ManagementAPI, error) {
29+func (env *azureEnviron) getManagementAPI() (*azureManagementContext, error) {
30 snap := env.getSnapshot()
31 subscription := snap.ecfg.ManagementSubscriptionId()
32- cert := snap.ecfg.ManagementCertificate()
33- return gwacl.NewManagementAPI(subscription, cert)
34-}
35-*/
36+ certData := snap.ecfg.ManagementCertificate()
37+ certFile, err := newTempCertFile([]byte(certData))
38+ if err != nil {
39+ return nil, err
40+ }
41+ // After this point, if we need to leave prematurely, we should clean
42+ // up that certificate file.
43+ mgtAPI, err := gwacl.NewManagementAPI(subscription, certFile.Path())
44+ if err != nil {
45+ certFile.Delete()
46+ return nil, err
47+ }
48+ context := azureManagementContext{
49+ ManagementAPI: mgtAPI,
50+ certFile: certFile,
51+ }
52+ return &context, nil
53+}
54+
55+// releaseManagementAPI frees up a context object obtained through
56+// getManagementAPI.
57+func (env *azureEnviron) releaseManagementAPI(context *azureManagementContext) {
58+ // Be tolerant to incomplete context objects, in case we ever get
59+ // called during cleanup of a failed attempt to create one.
60+ if context == nil || context.certFile == nil {
61+ return
62+ }
63+ // For now, all that needs doing is to delete the temporary certificate
64+ // file. We may do cleverer things later, such as connection pooling
65+ // where this method returns a context to the pool.
66+ context.certFile.Delete()
67+}
68
69 // getStorageContext obtains a context object for interfacing with Azure's
70 // storage API.
71
72=== modified file 'environs/azure/environ_test.go'
73--- environs/azure/environ_test.go 2013-06-20 08:30:01 +0000
74+++ environs/azure/environ_test.go 2013-06-20 17:02:46 +0000
75@@ -68,16 +68,31 @@
76 testing.TestLockingFunction(&env.Mutex, func() { env.Config() })
77 }
78
79-// TODO: Temporarily deactivating this code. Passing certificate in-memory
80-// may require gwacl change.
81-/*
82 func (EnvironSuite) TestGetManagementAPI(c *C) {
83 env := makeEnviron(c)
84- management, err := env.getManagementAPI()
85+ context, err := env.getManagementAPI()
86 c.Assert(err, IsNil)
87- c.Check(management, NotNil)
88-}
89-*/
90+ defer env.releaseManagementAPI(context)
91+ c.Check(context, NotNil)
92+ c.Check(context.ManagementAPI, NotNil)
93+ c.Check(context.certFile, NotNil)
94+}
95+
96+func (EnvironSuite) TestReleaseManagementAPIAcceptsNil(c *C) {
97+ env := makeEnviron(c)
98+ env.releaseManagementAPI(nil)
99+ // The real test is that this does not panic.
100+}
101+
102+func (EnvironSuite) TestReleaseManagementAPIAcceptsIncompleteContext(c *C) {
103+ env := makeEnviron(c)
104+ context := azureManagementContext{
105+ ManagementAPI: nil,
106+ certFile: nil,
107+ }
108+ env.releaseManagementAPI(&context)
109+ // The real test is that this does not panic.
110+}
111
112 func (EnvironSuite) TestGetStorageContext(c *C) {
113 env := makeEnviron(c)

Subscribers

People subscribed via source and target branches

to status/vote changes: