openstack team mailing list archive
-
openstack team
-
Mailing list archive
-
Message #12589
Re: cfg usage - option registration, global objects
Hi Mark,
On Thu, 2012-05-31 at 10:48 -0400, Mark Washenberger wrote:
>
> "Jay Pipes" <jaypipes@xxxxxxxxx> said:
> > On 05/29/2012 04:04 AM, Mark McLoughlin wrote:
> >> Adopting this pattern across all projects will actually help
> >> openstack-common more generally. For example, Russell is moving the RPC
> >> code into openstack-common and it has a bunch of configuration options.
> >> If it can assume a global configuration object, things become much
> >> easier.
> >
> > Unfortunately, what this leads to is interdependencies between the
> > openstack-common-rpc code and the openstack-common-cfg code. :( Now, if
> > someone wants to use the openstack RPC code in their own project, they
> > have to switch their way of configuring stuff to use global config
> > objects. Tight coupling means less adherence to the "do one thing and do
> > it well" mantra of *nix utilities and libraries and in general isn't
> > good software design.
>
>
> I personally would consider a rigid connection between the rpc library and
> the configuration to be inappropriate in the context of openstack common.
This is a fairly general design question for openstack-common.
If the behaviour of any given API should be dependent on the
configuration of the service (i.e. in nova.conf, glance-api.conf,
keystone.conf), then how should we design the API to handle that?
Three options:
1) The API knows nothing about cfg:
class Connection(object):
def __init__(self, broker_hostname, broker_port):
self.cnx = self.connect(broker_hostname, broker_port)
def cast(self, topic, msg):
self.cnx.cast(topic, msg)
2) The API is passed a ConfigOpts instance:
class Connection(object):
def __init__(self, conf):
self.cnx = self.connect(conf.broker_hostname,
conf.broker_port)
def cast(self, topic, msg):
self.cnx.cast(topic, msg)
3) The API uses the global config object
class Connection(object):
def __init__(self):
self.cnx = self.connect(CONF.broker_hostname,
CONF.broker_port)
def cast(self, topic, msg):
self.cnx.cast(topic, msg)
I see (1) as having value if we want the API to be usable outside
OpenStack. That might be worthwhile long term, but openstack-common's
goal is to provide APIs shared between OpenStack projects.
(2) and (3) have the huge benefit of configuration consistency - the
same configuration keys, defaults, etc. shared across projects.
(2) has value if there are cases where we want to use a non-global cfg
object. Quantum might have this use case if it continues parsing plugin
configuration separately from its main configuration. We'll see.
(3) has value if all use cases are using a global object.
I can see us getting to a point where we support both (2) and (3). I'm
dubious of the value of (1) in the medium term, but maybe we might find
a compelling use case for it.
> I'm also very happy to contribute modifications that would eliminate that
> connection.
>
> There are a few other reasons I'm concerned about nova's rpc implementation
> becoming the de facto standard. It has grown up organically and as such has
> some significant issues we should probably address before we create a
> precedent that other projects must adopt it to be good community members.
"other projects must adopt it to be good community members" - that's an
interesting take, not the way I'd put it.
I think I'd say that if a project wants to do RPC, it makes more sense
to improve the RPC API in openstack-common to meet its needs rather than
start a from-scratch implementation or, worse, copy and paste what's
there and customize it.
> From a brief scan, it seems to me that a restructured implementation of rpc
> that lands in common should
>
> * not be tied up with eventlet on the consumer side
Sounds like a good and achievable goal. Is there or will there soon be
an OpenStack project that needs has this requirement in order to be able
to use this code?
> * let the consumer code decide when to ack a message
> (although maybe the concept of acking doesn't exist for all implementations?)
What's the use case?
> * not depend on a global singleton _RPC_IMPL
I agree.
> * leave out/refactor some unused or non-general aspects, such as multicall,
> fanout_cast_to_server, notify, and fanout_cast (not so sure about that last one)
i.e. leave out stuff that is specific to Nova? How about if e.g. Cinder
was using it?
Don't forget that openstack-common has this notion of "incubating" APIs.
Everything is in incubation at the moment. I'd say cfg is the closest to
coming out of incubation.
I expect to do a pretty detailed review of the patch to add rpc to
openstack-common and make some API design recommendations. But I think
we'll have to balance some of those design ideas between "stuff we
really should fix before it goes into openstack-common" vs "stuff that
would need to be fixed before the API comes out of incubation".
Cheers,
Mark.
Follow ups
References