Merge lp:~gmb/maas/rpc-get-secrets into lp:~maas-committers/maas/trunk

Proposed by Graham Binns
Status: Rejected
Rejected by: Andres Rodriguez
Proposed branch: lp:~gmb/maas/rpc-get-secrets
Merge into: lp:~maas-committers/maas/trunk
Diff against target: 201 lines (+98/-0)
4 files modified
src/maasserver/rpc/regionservice.py (+25/-0)
src/maasserver/rpc/tests/test_regionservice.py (+50/-0)
src/provisioningserver/rpc/exceptions.py (+5/-0)
src/provisioningserver/rpc/region.py (+18/-0)
To merge this branch: bzr merge lp:~gmb/maas/rpc-get-secrets
Reviewer Review Type Date Requested Status
Julian Edwards (community) Disapprove
Review via email: mp+232379@code.launchpad.net

Commit message

Add an RPC call, GetSecrets, which given a cluster UUID returns the API credentials for that cluster.

This is for use in Pserv services that need to use the API (for the sake of simplicity whilst we're removing Celery and Rabbit).

To post a comment you must log in.
Revision history for this message
Graham Binns (gmb) wrote :

Marking WIP. Needs to handle error conditions.

Revision history for this message
Graham Binns (gmb) wrote :

Over-eager hacker is over-eager :). Now reviewable, though.

Revision history for this message
Julian Edwards (julian-edwards) wrote :

Please no! Just use RPC for everything.

review: Disapprove
Revision history for this message
Graham Binns (gmb) wrote :

On 27 August 2014 13:31, Julian Edwards <email address hidden>
wrote:

> Please no! Just use RPC for everything.
>

Okay.

Revision history for this message
Graham Binns (gmb) wrote :

(Besides, accidentally mixed up some branches. Would have been BAD.)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/maasserver/rpc/regionservice.py'
2--- src/maasserver/rpc/regionservice.py 2014-08-26 14:29:13 +0000
3+++ src/maasserver/rpc/regionservice.py 2014-08-27 15:09:21 +0000
4@@ -24,12 +24,15 @@
5 from textwrap import dedent
6 import threading
7
8+from apiclient.creds import convert_tuple_to_string
9 from crochet import reactor
10 from django.db import connection
11 from maasserver import (
12 eventloop,
13 locks,
14 )
15+from maasserver.models.nodegroup import NodeGroup
16+from maasserver.models.user import get_creds_tuple
17 from maasserver.rpc import (
18 bootsources,
19 configuration,
20@@ -74,6 +77,17 @@
21 from zope.interface import implementer
22
23
24+@transactional
25+def get_cluster_api_credentials(cluster_uuid):
26+ """Return the API creds for a cluster as a string."""
27+ try:
28+ the_cluster = NodeGroup.objects.get_by_natural_key(cluster_uuid)
29+ except NodeGroup.DoesNotExist:
30+ raise exceptions.NoSuchCluster(
31+ "No cluster found with UUID %s." % cluster_uuid)
32+ return convert_tuple_to_string(get_creds_tuple(the_cluster.api_token))
33+
34+
35 class Region(amp.AMP):
36 """The RPC protocol supported by a region controller.
37
38@@ -212,6 +226,17 @@
39 d.addCallback(lambda args: {})
40 return d
41
42+ @region.GetSecrets.responder
43+ def get_secrets(self, cluster_uuid):
44+ """get_secrets()
45+
46+ Implementation of
47+ :py:class:`~provisioningserver.rpc.region.GetSecrets`.
48+ """
49+ d = deferToThread(get_cluster_api_credentials, cluster_uuid)
50+ d.addCallback(lambda creds: {b"api_credentials": creds})
51+ return d
52+
53
54 @implementer(IConnection)
55 class RegionServer(Region):
56
57=== modified file 'src/maasserver/rpc/tests/test_regionservice.py'
58--- src/maasserver/rpc/tests/test_regionservice.py 2014-08-26 17:32:40 +0000
59+++ src/maasserver/rpc/tests/test_regionservice.py 2014-08-27 15:09:21 +0000
60@@ -14,6 +14,7 @@
61 __metaclass__ = type
62 __all__ = []
63
64+
65 from collections import defaultdict
66 from contextlib import closing
67 from itertools import product
68@@ -22,6 +23,7 @@
69 import random
70 import threading
71
72+from apiclient.creds import convert_tuple_to_string
73 from crochet import wait_for_reactor
74 from django.db import connection
75 from django.db.utils import ProgrammingError
76@@ -37,6 +39,7 @@
77 from maasserver.models.event import Event
78 from maasserver.models.eventtype import EventType
79 from maasserver.models.node import Node
80+from maasserver.models.user import get_creds_tuple
81 from maasserver.rpc import regionservice
82 from maasserver.rpc.regionservice import (
83 Region,
84@@ -66,6 +69,7 @@
85 exceptions,
86 )
87 from provisioningserver.rpc.exceptions import (
88+ NoSuchCluster,
89 NoSuchEventType,
90 NoSuchNode,
91 )
92@@ -74,6 +78,7 @@
93 GetBootSources,
94 GetBootSourcesV2,
95 GetProxies,
96+ GetSecrets,
97 Identify,
98 ListNodePowerParameters,
99 MarkNodeBroken,
100@@ -1420,3 +1425,48 @@
101
102 # If the RPC service is down, _get_addresses() returns nothing.
103 self.assertItemsEqual([], service._get_addresses())
104+
105+
106+class TestRegionProtocol_GetSecrets(MAASTestCase):
107+
108+ def test_identify_is_registered(self):
109+ protocol = Region()
110+ responder = protocol.locateResponder(GetSecrets.commandName)
111+ self.assertIsNot(responder, None)
112+
113+ @transactional
114+ def create_cluster(self):
115+ return factory.make_node_group()
116+
117+ @wait_for_reactor
118+ @inlineCallbacks
119+ def test_returns_api_secrets_for_cluster(self):
120+ cluster = yield deferToThread(self.create_cluster)
121+ expected_api_credentials = convert_tuple_to_string(
122+ get_creds_tuple(cluster.api_token))
123+
124+ response = yield call_responder(
125+ Region(), GetSecrets,
126+ {
127+ b'cluster_uuid': cluster.uuid,
128+ }
129+ )
130+ self.assertEqual(
131+ expected_api_credentials, response['api_credentials'])
132+
133+ @wait_for_reactor
134+ @inlineCallbacks
135+ def test_errors_if_cluster_not_found(self):
136+ cluster_uuid = factory.make_UUID()
137+ d = call_responder(
138+ Region(), GetSecrets,
139+ {
140+ b'cluster_uuid': cluster_uuid,
141+ }
142+ )
143+
144+ def check(error):
145+ self.assertIsInstance(error, Failure)
146+ self.assertIsInstance(error.value, NoSuchCluster)
147+
148+ yield d.addErrback(check)
149
150=== modified file 'src/provisioningserver/rpc/exceptions.py'
151--- src/provisioningserver/rpc/exceptions.py 2014-08-22 11:23:35 +0000
152+++ src/provisioningserver/rpc/exceptions.py 2014-08-27 15:09:21 +0000
153@@ -17,6 +17,7 @@
154 "CannotCreateHostMap",
155 "CannotRemoveHostMap",
156 "NoConnectionsAvailable",
157+ "NoSuchCluster",
158 "NoSuchEventType",
159 "NoSuchNode",
160 "NoSuchOperatingSystem",
161@@ -61,3 +62,7 @@
162
163 class CannotRemoveHostMap(Exception):
164 """The host map could not be removed."""
165+
166+
167+class NoSuchCluster(Exception):
168+ """The specified cluster was not found."""
169
170=== modified file 'src/provisioningserver/rpc/region.py'
171--- src/provisioningserver/rpc/region.py 2014-08-25 17:19:56 +0000
172+++ src/provisioningserver/rpc/region.py 2014-08-27 15:09:21 +0000
173@@ -29,6 +29,7 @@
174 )
175 from provisioningserver.rpc.common import Identify
176 from provisioningserver.rpc.exceptions import (
177+ NoSuchCluster,
178 NoSuchEventType,
179 NoSuchNode,
180 )
181@@ -208,3 +209,20 @@
182 NoSuchNode: b"NoSuchNode",
183 NoSuchEventType: b"NoSuchEventType"
184 }
185+
186+
187+class GetSecrets(amp.Command):
188+ """Get the API secrets for a cluster.
189+
190+ :since: 1.7
191+ """
192+
193+ arguments = [
194+ (b"cluster_uuid", amp.Unicode()),
195+ ]
196+ response = [
197+ (b"api_credentials", amp.Unicode()),
198+ ]
199+ errors = {
200+ NoSuchCluster: b"NoSuchCluster",
201+ }