Merge ~james-page/openstack-charm-layer-dev:master into ~openstack-charmers-layers/openstack-charm-layer-dev:master

Proposed by James Page on 2015-12-04
Status: Needs review
Proposed branch: ~james-page/openstack-charm-layer-dev:master
Merge into: ~openstack-charmers-layers/openstack-charm-layer-dev:master
Diff against target: 256 lines (+153/-30)
5 files modified
.gitignore (+2/-0)
Makefile (+1/-1)
charm/reactive/testcharm.py (+137/-17)
charm/templates/rabbit.conf (+12/-12)
tox.ini (+1/-0)
Reviewer Review Type Date Requested Status
Openstack Charmers Layers 2015-12-04 Pending
Review via email: mp+279563@code.launchpad.net
To post a comment you must log in.
0cf698b... by James Page on 2015-12-04

Add localized layers support

Unmerged commits

0cf698b... by James Page on 2015-12-04

Add localized layers support

ffc2ca2... by James Page on 2015-12-04

An idea for interface adapters

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/.gitignore b/.gitignore
2index cfac03f..bec5c14 100644
3--- a/.gitignore
4+++ b/.gitignore
5@@ -1,2 +1,4 @@
6 build
7 .tox
8+interfaces
9+layers
10diff --git a/Makefile b/Makefile
11index 8eab509..1bd85e5 100644
12--- a/Makefile
13+++ b/Makefile
14@@ -3,5 +3,5 @@
15 clean:
16 rm -Rf build
17
18-generate:
19+generate: clean
20 tox -e generate
21diff --git a/charm/reactive/testcharm.py b/charm/reactive/testcharm.py
22index ea6c0b6..240dcac 100644
23--- a/charm/reactive/testcharm.py
24+++ b/charm/reactive/testcharm.py
25@@ -12,6 +12,130 @@ def setup_database(database):
26 database.configure('mydatabase2', 'myusername2', host, prefix="second")
27 #database.configure('mydatabase', 'myusername', host)
28
29+class OpenStackRelationAdapter(object):
30+ """
31+ Base adapter class for all OpenStack related adapters.
32+ """
33+
34+ interface_type = None
35+ """
36+ The generic type of the interface the adapter is wrapping.
37+ """
38+
39+ def __init__(self, relation):
40+ self.relation = relation
41+ self._setup_properties()
42+
43+ @property
44+ def relation_name(self):
45+ """
46+ Name of the relation this adapter is handling.
47+ """
48+ return self._relation.relation_name
49+
50+ def _setup_properties(self):
51+ """
52+ Setup property based accessors for an interfaces
53+ auto accessors
54+ """
55+ for field in self.relation.auto_accessors:
56+ meth_name = field.replace('-', '_')
57+ # TODO: see if we can make this dynamic, rather
58+ # than making all calls on setup.
59+ self.__dict__[meth_name] = getattr(self.relation,
60+ meth_name)()
61+
62+
63+class RabbitMQRelationAdapter(OpenStackRelationAdapter):
64+ """
65+ Adapter for the RabbitMQRequires relation interface.
66+ """
67+
68+ interface_type = "messaging"
69+
70+ @property
71+ def host(self):
72+ """
73+ Hostname that should be used to access RabbitMQ.
74+ """
75+ if self.vip:
76+ return self.vip
77+ else:
78+ return self.private_address
79+
80+ @property
81+ def hosts(self):
82+ """
83+ Comma separated list of hosts that should be used
84+ to access RabbitMQ.
85+ """
86+ hosts = self.relation.rabbitmq_hosts()
87+ if len(hosts) > 1:
88+ return ','.join(hosts)
89+ else:
90+ return None
91+
92+ @property
93+ def vhost(self):
94+ return self.relation.vhost()
95+
96+ @property
97+ def username(self):
98+ return self.relation.username()
99+
100+
101+class OpenStackInterfaceAdapters(object):
102+ """
103+ Base adapters class for OpenStack Charms, used to aggregate
104+ the relations associated with a particular charm so that their
105+ properties can be accessed using dot notation, e.g:
106+
107+ adapters.amqp.private_address
108+ """
109+
110+ interface_adapters = {}
111+ """
112+ Dictionary mapping relation names to adapter classes, e.g:
113+
114+ interface_adapters = {
115+ 'amqp': RabbitMQRelationAdapter,
116+ }
117+
118+ By default, interfaces will be wrapped in an OpenStackRelationAdapter.
119+ """
120+
121+ def __init__(self, interfaces):
122+ self._relations = []
123+ for interface in interfaces:
124+ relation_name = interface.relation_name
125+ if relation_name in self.interface_adapters:
126+ self.__dict__[relation_name] = (
127+ self.interface_adapters[relation_name](interface)
128+ )
129+ else:
130+ self.__dict__[relation_name] = (
131+ OpenStackRelationAdapter(interface)
132+ )
133+ self._relations.append(relation_name)
134+
135+ def __iter__(self):
136+ """
137+ Iterate over the relations presented to the charm.
138+ """
139+ for relation in self._relations:
140+ yield relation, self.__dict__[relation]
141+
142+
143+class TestCharmAdapters(OpenStackInterfaceAdapters):
144+ """
145+ Adapters class for the TestCharm charm.
146+ """
147+
148+ interface_adapters = {
149+ 'amqp': RabbitMQRelationAdapter,
150+ }
151+
152+
153 @when('database.available')
154 def use_database(database):
155 # base data provided by testcharm
156@@ -44,36 +168,32 @@ def use_database_ssl(database):
157 log("ssl_cert=%s" % database.ssl_cert())
158 log("ssl_key=%s" % database.ssl_key())
159
160+
161 @when('amqp.connected')
162 def setup_amqp_req(amqp):
163 log("AMQP Connected")
164 amqp.configure('bob', 'myvhost')
165
166+
167 @when('amqp.available')
168-def conf_amqp_req(amqp):
169+def conf_amqp_req(*args):
170 log("AMQP Available")
171- log("hostname=%s" % amqp.hostname())
172- log("vhost=%s" % amqp.vhost())
173- log("username=%s" % amqp.username())
174- log("password=%s" % amqp.password())
175- ctxt = {
176- 'amqp': amqp,
177- }
178- rabbits = amqp.rabbitmq_hosts()
179- if len(rabbits) > 1:
180- ctxt['rabbitmq_hosts'] = ','.join(rabbits)
181- elif len(rabbits) == 1:
182- ctxt['rabbitmq_host'] = rabbits[0]
183+ adapters = TestCharmAdapters(args)
184+ log("hostname=%s" % adapters.amqp.private_address)
185+ log("vhost=%s" % adapters.amqp.vhost)
186+ log("username=%s" % adapters.amqp.username)
187+ log("password=%s" % adapters.amqp.password)
188 render(source='rabbit.conf',
189 target='/tmp/rabbit.conf',
190- context=ctxt
191+ context=adapters
192 )
193
194 @when('amqp.available.ssl')
195-def conf_amqp_ssl(amqp):
196+def conf_amqp_ssl(*args):
197 log("AMQP Available SSL")
198- log("ssl_port=%s" % amqp.ssl_port())
199- log("ssl_ca=%s" % amqp.ssl_ca())
200+ adapters = TestCharmAdapters(args)
201+ print(adapters.amqp.ssl_port)
202+ print(adapters.amqp.ssl_ca)
203
204 @when('database.connected')
205 @when_not('database.available')
206diff --git a/charm/templates/rabbit.conf b/charm/templates/rabbit.conf
207index 269bea5..3ad2371 100644
208--- a/charm/templates/rabbit.conf
209+++ b/charm/templates/rabbit.conf
210@@ -1,22 +1,22 @@
211-{% if rabbitmq_host or rabbitmq_hosts -%}
212+{% if amqp.host or amqp.hosts -%}
213 [oslo_messaging_rabbit]
214-rabbit_userid = {{ amqp.username() }}
215-rabbit_virtual_host = {{ amqp.vhost() }}
216-rabbit_password = {{ amqp.password() }}
217-{% if rabbitmq_hosts -%}
218-rabbit_hosts = {{ rabbitmq_hosts }}
219-{% if amqp.ha_queues() -%}
220+rabbit_userid = {{ amqp.username }}
221+rabbit_virtual_host = {{ amqp.vhost }}
222+rabbit_password = {{ amqp.password }}
223+{% if amqp.hosts -%}
224+rabbit_hosts = {{ amqp.hosts }}
225+{% if amqp.ha_queues -%}
226 rabbit_ha_queues = True
227 rabbit_durable_queues = False
228 {% endif -%}
229 {% else -%}
230-rabbit_host = {{ rabbitmq_host }}
231+rabbit_host = {{ amqp.host }}
232 {% endif -%}
233-{% if amqp.ssl_data_complete() == True -%}
234+{% if amqp.ssl_port -%}
235 rabbit_use_ssl = True
236-rabbit_port = {{ amqp.ssl_port() }}
237-{% if amqp.ssl_ca() -%}
238-kombu_ssl_ca_certs = {{ amqp.ssl_ca() }}
239+rabbit_port = {{ amqp.ssl_port }}
240+{% if amqp.ssl_ca -%}
241+kombu_ssl_ca_certs = {{ amqp.ssl_ca }}
242 {% endif -%}
243 {% endif -%}
244 {% endif -%}
245diff --git a/tox.ini b/tox.ini
246index 92c070a..8e8b8ba 100644
247--- a/tox.ini
248+++ b/tox.ini
249@@ -7,6 +7,7 @@ setenv = VIRTUAL_ENV={envdir}
250 PYTHONHASHSEED=0
251 TERM=linux
252 INTERFACE_PATH={toxinidir}/interfaces
253+ LAYER_PATH={toxinidir}/layers
254 JUJU_REPOSITORY={toxinidir}/build
255 passenv = http_proxy https_proxy
256 install_command =

Subscribers

People subscribed via source and target branches