Merge lp:~hazmat/pyjuju/ostack-diablo-hp-compat into lp:pyjuju

Proposed by Kapil Thangavelu
Status: Merged
Merged at revision: 606
Proposed branch: lp:~hazmat/pyjuju/ostack-diablo-hp-compat
Merge into: lp:pyjuju
Diff against target: 184 lines (+67/-19)
3 files modified
juju/providers/openstack/client.py (+11/-5)
juju/providers/openstack/ports.py (+27/-10)
juju/providers/openstack/tests/test_ports.py (+29/-4)
To merge this branch: bzr merge lp:~hazmat/pyjuju/ostack-diablo-hp-compat
Reviewer Review Type Date Requested Status
Jim Baker (community) Approve
Review via email: mp+140815@code.launchpad.net

Description of the change

Openstack security group api compat with hpcloud

It looks like the issue is the server security group details don't have rule
information in the diablo/hpcloud api fallback which caused problems for juju
when trying to determine what ports where open in the group (couldn't close
ports, and attempted to open ports multiple times). The simple workaround is a
specific path for hpcloud that fetches the group detail info separately if
server group details don't have rule info.

Verified against folsom/canonistack and hpcloud/diablo.

https://bugs.launchpad.net/juju/+bug/1092343

https://codereview.appspot.com/6966047/

To post a comment you must log in.
Revision history for this message
Kapil Thangavelu (hazmat) wrote :
Download full text (3.3 KiB)

Reviewers: mp+140815_code.launchpad.net,

Message:
Please take a look.

Description:
Openstack security group api compat with hpcloud

It looks like the issue is the server security group details don't have
rule
information in the diablo/hpcloud api fallback which caused problems for
juju
when trying to determine what ports where open in the group (couldn't
close
ports, and attempted to open ports multiple times). The simple
workaround is a
specific path for hpcloud that fetches the group detail info separately
if
server group details don't have rule info.

https://bugs.launchpad.net/juju/+bug/1092343

https://code.launchpad.net/~hazmat/juju/ostack-diablo-hp-compat/+merge/140815

(do not edit description out of merge proposal)

Please review this at https://codereview.appspot.com/6966047/

Affected files:
   A [revision details]
   M juju/providers/openstack/client.py
   M juju/providers/openstack/ports.py

Index: [revision details]
=== added file '[revision details]'
--- [revision details] 2012-01-01 00:00:00 +0000
+++ [revision details] 2012-01-01 00:00:00 +0000
@@ -0,0 +1,2 @@
+Old revision: <email address hidden>
+New revision: <email address hidden>

Index: juju/providers/openstack/client.py
=== modified file 'juju/providers/openstack/client.py'
--- juju/providers/openstack/client.py 2012-10-26 14:52:35 +0000
+++ juju/providers/openstack/client.py 2012-12-20 03:54:46 +0000
@@ -411,12 +411,18 @@
          d = self.get(
              ["servers", server_id, "os-security-groups"],
              root="security_groups")
- # 2012-07-12: Workaround lack of this api in HP cloud
- d.addErrback(
- lambda f: self.get_server(server_id).addCallback(
- operator.itemgetter("security_groups")))
+
+ # 2012-07-12: kt Workaround lack of this api in HP cloud
+ def _get_group_fallback(f):
+ log.debug("Falling back to older/diablo sec groups api")
+ return self.get_server(server_id).addCallback(
+ operator.itemgetter("security_groups"))
+ d.addErrback(_get_group_fallback)
          return d

+ def get_security_group_details(self, group_id):
+ return self.get(["os-security-groups", group_id], "security_group")
+
      def list_security_groups(self):
          return self.get(["os-security-groups"], "security_groups")

Index: juju/providers/openstack/ports.py
=== modified file 'juju/providers/openstack/ports.py'
--- juju/providers/openstack/ports.py 2012-09-19 05:34:00 +0000
+++ juju/providers/openstack/ports.py 2012-12-20 03:54:46 +0000
@@ -55,9 +55,20 @@
          group_name = self._machine_group_name(machine_id)
          server_id = machine.instance_id
          groups = yield self.nova.get_server_security_groups(server_id)
+
+ found = False
          for group in groups:
              if group['name'] == group_name:
- returnValue(group)
+ found = group
+ break
+
+ # 2012/12/19: kt diablo/hpcloud compatibility
+ if found and not 'rules' in group:
+ group = yield self.nova.get_security_group_details(group['id'])
+
+...

Read more...

Revision history for this message
Jim Baker (jimbaker) wrote :

+1, LGTM. The workaround would be clearer if inlineCallbacks were used in the original code, but no point changing the style now with this fix. Assumes the obvious trivial test that has been promised on #juju.

review: Approve
Revision history for this message
Martin Packman (gz) wrote :

With the latest rev looks okay, would really like a test of some kind though. Am more than a little worried about deployment quirks like this being missed in the reimplimentation in juju-core, a clear-ish test with the observed behaviour would make for reasonably easy porting.

Revision history for this message
Kapil Thangavelu (hazmat) wrote :

added test and pushed again.

On Tue, Jan 8, 2013 at 11:14 AM, Martin Packman <
<email address hidden>> wrote:

> With the latest rev looks okay, would really like a test of some kind
> though. Am more than a little worried about deployment quirks like this
> being missed in the reimplimentation in juju-core, a clear-ish test with
> the observed behaviour would make for reasonably easy porting.
> --
>
> https://code.launchpad.net/~hazmat/juju/ostack-diablo-hp-compat/+merge/140815
> You are the owner of lp:~hazmat/juju/ostack-diablo-hp-compat.
>

Revision history for this message
Kapil Thangavelu (hazmat) wrote :

There's a caveat to this work around which needs consideration/verification
namely that empty groups on essex/folsom still return a rules entry in the
dict.

On Tue, Jan 8, 2013 at 1:21 PM, Kapil Thangavelu <
<email address hidden>> wrote:

> added test and pushed again.
>
>
> On Tue, Jan 8, 2013 at 11:14 AM, Martin Packman <
> <email address hidden>> wrote:
>
>> With the latest rev looks okay, would really like a test of some kind
>> though. Am more than a little worried about deployment quirks like this
>> being missed in the reimplimentation in juju-core, a clear-ish test with
>> the observed behaviour would make for reasonably easy porting.
>> --
>>
>> https://code.launchpad.net/~hazmat/juju/ostack-diablo-hp-compat/+merge/140815
>> You are the owner of lp:~hazmat/juju/ostack-diablo-hp-compat.
>>
>
>

Revision history for this message
Kapil Thangavelu (hazmat) wrote :
609. By Kapil Thangavelu

pep8/pyflakes cleanups

Revision history for this message
Kapil Thangavelu (hazmat) wrote :

*** Submitted:

Openstack security group api compat with hpcloud

It looks like the issue is the server security group details don't have
rule
information in the diablo/hpcloud api fallback which caused problems for
juju
when trying to determine what ports where open in the group (couldn't
close
ports, and attempted to open ports multiple times). The simple
workaround is a
specific path for hpcloud that fetches the group detail info separately
if
server group details don't have rule info.

Verified against folsom/canonistack and hpcloud/diablo.

https://bugs.launchpad.net/juju/+bug/1092343

R=
CC=
https://codereview.appspot.com/6966047

https://codereview.appspot.com/6966047/

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'juju/providers/openstack/client.py'
2--- juju/providers/openstack/client.py 2012-10-26 14:52:35 +0000
3+++ juju/providers/openstack/client.py 2013-01-13 18:47:19 +0000
4@@ -391,7 +391,7 @@
5 return self.delete(["servers", server_id], code=204)
6
7 def run_server(self, image_id, flavor_id, name, security_group_names=None,
8- user_data=None, scheduler_hints=None):
9+ user_data=None, scheduler_hints=None):
10 server = {
11 'name': name,
12 'flavorRef': flavor_id,
13@@ -411,12 +411,18 @@
14 d = self.get(
15 ["servers", server_id, "os-security-groups"],
16 root="security_groups")
17- # 2012-07-12: Workaround lack of this api in HP cloud
18- d.addErrback(
19- lambda f: self.get_server(server_id).addCallback(
20- operator.itemgetter("security_groups")))
21+
22+ # 2012-07-12: kt Workaround lack of this api in HP cloud
23+ def _get_group_fallback(f):
24+ log.debug("Falling back to older/diablo sec groups api")
25+ return self.get_server(server_id).addCallback(
26+ operator.itemgetter("security_groups"))
27+ d.addErrback(_get_group_fallback)
28 return d
29
30+ def get_security_group_details(self, group_id):
31+ return self.get(["os-security-groups", group_id], "security_group")
32+
33 def list_security_groups(self):
34 return self.get(["os-security-groups"], "security_groups")
35
36
37=== modified file 'juju/providers/openstack/ports.py'
38--- juju/providers/openstack/ports.py 2012-09-19 05:34:00 +0000
39+++ juju/providers/openstack/ports.py 2013-01-13 18:47:19 +0000
40@@ -55,21 +55,34 @@
41 group_name = self._machine_group_name(machine_id)
42 server_id = machine.instance_id
43 groups = yield self.nova.get_server_security_groups(server_id)
44+
45+ found = False
46 for group in groups:
47 if group['name'] == group_name:
48- returnValue(group)
49+ found = group
50+ break
51+
52+ # 2012/12/19: kt diablo/hpcloud compatibility
53+ if found and not 'rules' in group:
54+ group = yield self.nova.get_security_group_details(group['id'])
55+ found = True
56+
57+ if found:
58+ returnValue(group)
59+
60 raise errors.ProviderInteractionError(
61 "Missing security group %r for machine %r" %
62- (group_name, server_id))
63+ (group_name, server_id))
64
65 @inlineCallbacks
66 def open_port(self, machine, machine_id, port, protocol="tcp"):
67 """Allow access to a port for the given machine only"""
68 group = yield self._get_machine_group(machine, machine_id)
69- yield self.nova.add_security_group_rule(group['id'],
70+ yield self.nova.add_security_group_rule(
71+ group['id'],
72 ip_protocol=protocol, from_port=port, to_port=port)
73 log.debug("Opened %s/%s on machine %r",
74- port, protocol, machine.instance_id)
75+ port, protocol, machine.instance_id)
76
77 @inlineCallbacks
78 def close_port(self, machine, machine_id, port, protocol="tcp"):
79@@ -78,13 +91,14 @@
80 for rule in group["rules"]:
81 if (port == rule["from_port"] == rule["to_port"] and
82 rule["ip_protocol"] == protocol):
83+
84 yield self.nova.delete_security_group_rule(rule["id"])
85 log.debug("Closed %s/%s on machine %r",
86 port, protocol, machine.instance_id)
87 return
88 raise errors.ProviderInteractionError(
89 "Couldn't close unopened %s/%s on machine %r",
90- port, protocol, machine.instance_id)
91+ port, protocol, machine.instance_id)
92
93 @inlineCallbacks
94 def get_opened_ports(self, machine, machine_id):
95@@ -113,11 +127,12 @@
96 juju_group = self._juju_group_name()
97 if not juju_group in groups_by_name:
98 log.debug("Creating juju security group %s", juju_group)
99- sg = yield self.nova.create_security_group(juju_group,
100+ sg = yield self.nova.create_security_group(
101+ juju_group,
102 "juju group for %s" % (self.tag,))
103 # Add external ssh access
104- yield self.nova.add_security_group_rule(sg['id'],
105- ip_protocol="tcp", from_port=22, to_port=22)
106+ yield self.nova.add_security_group_rule(
107+ sg['id'], ip_protocol="tcp", from_port=22, to_port=22)
108 # Add internal group access
109 yield self.nova.add_security_group_rule(
110 parent_group_id=sg['id'], group_id=sg['id'],
111@@ -131,7 +146,8 @@
112 yield self.nova.delete_security_group(
113 groups_by_name[machine_group])
114 log.debug("Creating machine security group %s", machine_group)
115- yield self.nova.create_security_group(machine_group,
116+ yield self.nova.create_security_group(
117+ machine_group,
118 "juju group for %s machine %s" % (self.tag, machine_id))
119
120 returnValue([juju_group, machine_group])
121@@ -157,7 +173,8 @@
122 server_id = machine.instance_id
123 groups = yield self.nova.get_server_security_groups(server_id)
124 juju_group = self._juju_group_name()
125- groups_by_name = dict((g['name'], g['id']) for g in groups
126+ groups_by_name = dict(
127+ (g['name'], g['id']) for g in groups
128 if g['name'].startswith(juju_group))
129 if juju_group not in groups_by_name:
130 # Not a juju machine, shouldn't touch
131
132=== modified file 'juju/providers/openstack/tests/test_ports.py'
133--- juju/providers/openstack/tests/test_ports.py 2012-09-19 05:34:00 +0000
134+++ juju/providers/openstack/tests/test_ports.py 2013-01-13 18:47:19 +0000
135@@ -39,10 +39,10 @@
136
137 def test_open_port(self):
138 """Opening a port adds the rule to the appropriate security group"""
139- self.expect_nova_get("servers/1000/os-security-groups",
140+ self.expect_nova_get(
141+ "servers/1000/os-security-groups",
142 response={'security_groups': [
143- {'name': "juju-testing-1", 'id': 1},
144- ]})
145+ {'name': "juju-testing-1", 'id': 1, 'rules': []}]})
146 self.expect_create_rule(1, "tcp", 80)
147 self.mocker.replay()
148
149@@ -52,9 +52,34 @@
150
151 def _check_log(_):
152 self.assertIn("Opened 80/tcp on machine '1000'",
153- log.getvalue())
154+ log.getvalue())
155 return deferred.addCallback(_check_log)
156
157+ def test_diablo_hpcloud_ccompatbility(self):
158+ """Verify compatibility workarounds for hpcloud/diablo."""
159+ self.expect_nova_get(
160+ "servers/1000/os-security-groups",
161+ response={'security_groups': [
162+ {'name': "juju-testing-1", 'id': 1}]})
163+
164+ self.expect_nova_get(
165+ "os-security-groups/1",
166+ response={'security_group': {
167+ 'name': "juju-testing-1",
168+ 'id': 1,
169+ 'rules': [{
170+ 'id': 1,
171+ 'parent_group_id': 1,
172+ 'ip_protocol': 'tcp',
173+ 'from_port': 80,
174+ 'to_port': 80}]}})
175+
176+ self.mocker.replay()
177+
178+ machine = NovaProviderMachine('1000', "server1000.testing.invalid")
179+ deferred = self.get_provider().get_opened_ports(machine, "1")
180+ return deferred.addCallback(self.assertEqual, set([(80, "tcp")]))
181+
182 def test_open_port_missing_group(self):
183 """Missing security group raises an error on deleting port"""
184 self.expect_nova_get("servers/1000/os-security-groups",

Subscribers

People subscribed via source and target branches

to status/vote changes: