← Back to team overview

openstack team mailing list archive

Re: cfg usage - option registration, global objects

 

Hi Mark,

Please forgive the top-posting! I always get way too wordy with
inline replies.

Regarding configuration, I think there is another option I'd like us
to adopt. We should implement the code as in your option #1, but then
implement convenience factories that give the appearance of option #3
or #2, or both, you pick. From your examples it might look something
like this:

    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)

    def connection_from_global_conf():
        return Connection(CONF.broker_hostname, CONF.broker_port)

I think its pretty necessary that we don't do option #3 directly.
There are some important use cases to consider, like migrating from
one rpc implementation to another where you might want an adapter
that can relay messages from one to the other. Also, cells with
kombu at least requires that one process be able to talk to multiple
brokers.

Regarding incubation, I suppose I am confused. At what point during
incubation do other projects start to use the shared library? I would
imagine the answer to be "after incubation" but it sounds like there
are several projects very eager to adopt rpc as soon as it lands in
openstack common, even before incubation is complete.

If incubation happens before the calcifying effects of shared use
set in, then it sounds like a great place to address the other
rpc-specific concerns we've talked about. Otherwise I guess we're
stuck where I thought we were, where the bar needs to be set pretty
high to initially land in os-common.

"Mark McLoughlin" <markmc@xxxxxxxxxx> said:

> 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