Re: [openstack-dev] [Neutron] Seeking opinions on scope of code refactoring...

2014-05-27 Thread Paul Michali (pcm)
Thanks for the comments Mandeep!  Responses in-line #PCM

On May 23, 2014, at 8:57 PM, Mandeep Dhami dh...@noironetworks.com wrote:

 My preferences:
 
 For where, I'd go with Gary's recommendation (A) for two reasons (1) 
 Consistency and (2) I don't think it will create any boilerplate requirements 
 since the abstract class provides the default implementation.

#PCM Actually, (A) requires a lot of additional code that doesn’t currently 
exist today. ABC methods would be needed for each validation. In addition, to 
be consistent, there should be an abstract method for the apply function, and a 
“pass” implementation on each of the concrete classes. Overall, it is adding a 
lot of code, for arguably little benefit.


 
 For naming, I'd prefer to go with ML2 terminology for two reasons (1) Again 
 Consistency, and (2) it is then clear what actions are happening within a 
 transaction or outside of it. With a validation function no transaction 
 fence is implied by it's name - but for any validation that depends on what 
 currently exists in the database, these transaction semantics are important.

#PCM I’m still struggling with the naming for question #2.  I must admit, I 
like the naming of validate/apply because it makes it clear as to what is 
happening with the calls. With pre-commit/post-commit, it doesn’t indicate what 
the functions are actually doing, and in one case (for the Cisco VPN service 
driver) the post-commit will actually be doing a database commit in addition to 
applying the changes to the device driver (so both the postcommt and apply 
naming don’t clearly indicate the actions - an alternative would be to call the 
driver for the commit phase too, but this is a rare case).

To muddy it up a bit more, the main functions have no indication in the name 
that they deal with persisting to the database. The hierarchy currently is 
(using create_vpnservice...

class VPNPluginBase(service_base.ServicePluginBase):   # ABC with Northbound 
API definition
@abc.abstractmethod
def create_vpnservice(self, context, vpnservice):
pass

class VPNPluginDb(vpnaas.VPNPluginBase, base_db.CommonDbMixin):  # DBase 
concrete class
def create_vpnservice(self, context, vpnservice):
vpns = vpnservice['vpnservice']
tenant_id = self._get_tenant_id_for_create(context, vpns)
with context.session.begin(subtransactions=True):
…

class VPNPlugin(vpn_db.VPNPluginDb):
…
class VPNDriverPlugin(VPNPlugin, vpn_db.VPNPluginRpcDbMixin):  # Plugin child 
class
def create_vpnservice(self, context, vpnservice):
driver = self._get_driver_for_vpnservice(vpnservice)
super(VPNDriverPlugin, self).create_vpnservice(context, vpnservice)
driver.create_vpnservice(context, vpnservice)

class VpnDriver(object):  # ABC for service driver
# Nothing for create_vpnservice()

class IPsecVPNDriver(service_drivers.VpnDriver):  # Service driver class
# Nothing for create_vpnservice()


In the proposals, we talking about a sequence of this (2X) at the plugin:

def create_vpnservice(self, context, vpnservice):
driver = self._get_driver_for_vpnservice(vpnservice)
driver.create_vpnservice_precommit(vpnservice)
super(VPNDriverPlugin, self).create_vpnservice(context, vpnservice)
driver.create_vpnservice_postcommit(context, vpnservice)

versus this (2Y)…

def create_vpnservice(self, context, vpnservice):
driver = self._get_driver_for_vpnservice(vpnservice)
driver.validate_create_vpnservice(vpnservice)
super(VPNDriverPlugin, self).create_vpnservice(context, vpnservice)
driver.apply_create_vpnservice(context, vpnservice)


The former makes is clearer that there is a database operation in-between 
(implied by the naming). The latter makes it clearer what the service driver is 
doing before and after.  In both cases, the ABC for the service driver 
(VpnDriver) could have the default validation/precommit actions, and the 
service driver (IPsecVPNDriver) could optionally have any provider 
validation/precommit and would have the mandatory apply/post-commit actions.

Maybe I could do a WIP patch out for review to give something for concrete 
commenting…


Regards,

PCM



 
 Regards,
 Mandeep
 
 
 
 On Fri, May 23, 2014 at 4:25 PM, Paul Michali (pcm) p...@cisco.com wrote:
 Thanks for the comment Carl. See @PCM inline
 
 
 PCM (Paul Michali)
 
 MAIL …..…. p...@cisco.com
 IRC ……..… pcm_ (irc.freenode.com)
 TW ………... @pmichali
 GPG Key … 4525ECC253E31A83
 Fingerprint .. 307A 96BB 1A4C D2C7 931D 8D2D 4525 ECC2 53E3 1A83
 
 
 
 On May 23, 2014, at 6:09 PM, Carl Baldwin c...@ecbaldwin.net wrote:
 
 Paul,
 
 On Fri, May 23, 2014 at 8:24 AM, Paul Michali (pcm) p...@cisco.com wrote:
 Hi,
 
 I’m working on a task for a BP to separate validation from persistence logic
 in L3 services code (VPN currently), so that providers can override/extend
 the validation logic (before persistence).
 
 So I’ve separated 

Re: [openstack-dev] [Neutron] Seeking opinions on scope of code refactoring...

2014-05-27 Thread Paul Michali (pcm)
So I hit some more complexity, when I got to the IPSec connection resource’s 
update API…

I was doing code like this:

In VPN plugin:
def create_ipsec_site_connection(self, context, ipsec_site_connection):
driver = self._get_driver_for_ipsec_site_connection(
context, ipsec_site_connection)
driver.validate_create_ipsec_site_connection(context,
 ipsec_site_connection)
ipsec_site_connection = super(
VPNDriverPlugin, self).create_ipsec_site_connection(
context, ipsec_site_connection)
driver.apply_create_ipsec_site_connection(context,
  ipsec_site_connection)
return ipsec_site_connection


In ABC for service drvier:

def validate_create_ipsec_site_connection(self, context,
  ipsec_site_connection):
ipsec_sitecon = ipsec_site_connection['ipsec_site_connection']
dpd = ipsec_sitecon.get('dpd', {})
ipsec_sitecon['dpd_action'] = dpd.get('action', 'hold')
ipsec_sitecon['dpd_interval'] = dpd.get('interval', 30)
ipsec_sitecon['dpd_timeout'] = dpd.get('timeout', 120)
self._check_dpd(ipsec_sitecon)
self._check_mtu(context,
ipsec_sitecon['mtu'],
ipsec_sitecon['vpnservice_id'])

However, when considering the update_ipsec_site_connection() API, I realized 
that there could be multiple requests coming in to change the same connection’s 
attributes. In this case, validating and then persisting has the issue of 
incompatible changes being committed (e.g. one client changes DPD interval, and 
another client changes DPD timeout, such that they fail the _check_mtu() call).

I’m wondering what the thoughts are, regarding how to handle this. One way, I 
guess, may be do call the service driver validation from within the database 
logic, like this:

In VPN plugin
def create_ipsec_site_connection(self, context, ipsec_site_connection):
driver = self._get_driver_for_ipsec_site_connection(
context, ipsec_site_connection)
ipsec_site_connection = super(
VPNDriverPlugin, self).create_ipsec_site_connection(
context, ipsec_site_connection)
driver.apply_create_ipsec_site_connection(context,
  ipsec_site_connection)
return ipsec_site_connection

In Database (pseudo-code)
def create_ipsec_site_connection(self, context, ipsec_site_connection):
ipsec_sitecon = ipsec_site_connection['ipsec_site_connection']
tenant_id = self._get_tenant_id_for_create(context, ipsec_sitecon)
with context.session.begin(subtransactions=True):
# I guess this would actually call the child class method to
# get the driver?
driver = self._get_driver_for_ipsec_site_connection(
context, ipsec_sitecon)
driver.validate_create_ipsec_site_connection(context, ipsec_sitecon)

The database method is a base class of the VPN plugin class, so I’m thinking, 
although awkward, it could work. Can’t say I’m comfortable with the call flow 
here.  Probably could add an abstract method for 
_get_driver_for_ipsec_site_connection(), so that it cannot be called with an 
instance of the database class.

I’m not seeing a really clean solution here.


Any thoughts?

PCM (Paul Michali)

MAIL …..…. p...@cisco.com
IRC ……..… pcm_ (irc.freenode.com)
TW ………... @pmichali
GPG Key … 4525ECC253E31A83
Fingerprint .. 307A 96BB 1A4C D2C7 931D 8D2D 4525 ECC2 53E3 1A83



On May 27, 2014, at 7:37 AM, Paul Michali (pcm) p...@cisco.com wrote:

 Thanks for the comments Mandeep!  Responses in-line #PCM
 
 On May 23, 2014, at 8:57 PM, Mandeep Dhami dh...@noironetworks.com wrote:
 
 My preferences:
 
 For where, I'd go with Gary's recommendation (A) for two reasons (1) 
 Consistency and (2) I don't think it will create any boilerplate 
 requirements since the abstract class provides the default implementation.
 
 #PCM Actually, (A) requires a lot of additional code that doesn’t currently 
 exist today. ABC methods would be needed for each validation. In addition, to 
 be consistent, there should be an abstract method for the apply function, and 
 a “pass” implementation on each of the concrete classes. Overall, it is 
 adding a lot of code, for arguably little benefit.
 
 
 
 For naming, I'd prefer to go with ML2 terminology for two reasons (1) Again 
 Consistency, and (2) it is then clear what actions are happening within a 
 transaction or outside of it. With a validation function no transaction 
 fence is implied by it's name - but for any validation that depends on what 
 currently exists in the database, these transaction semantics are important.
 
 #PCM I’m still struggling with the naming for question #2.  I must admit, I 
 like the naming of validate/apply because 

Re: [openstack-dev] [Neutron] Seeking opinions on scope of code refactoring...

2014-05-27 Thread Carl Baldwin
Paul, do you have enough to be able to put up a WIP in gerrit?  This
discussion is getting to the point where having a discussion in gerrit
will be beneficial.

Carl

On Tue, May 27, 2014 at 12:37 PM, Paul Michali (pcm) p...@cisco.com wrote:
 So I hit some more complexity, when I got to the IPSec connection resource’s
 update API…

 I was doing code like this:

 In VPN plugin:
 def create_ipsec_site_connection(self, context, ipsec_site_connection):
 driver = self._get_driver_for_ipsec_site_connection(
 context, ipsec_site_connection)
 driver.validate_create_ipsec_site_connection(context,
  ipsec_site_connection)
 ipsec_site_connection = super(
 VPNDriverPlugin, self).create_ipsec_site_connection(
 context, ipsec_site_connection)
 driver.apply_create_ipsec_site_connection(context,
   ipsec_site_connection)
 return ipsec_site_connection


 In ABC for service drvier:

 def validate_create_ipsec_site_connection(self, context,
   ipsec_site_connection):
 ipsec_sitecon = ipsec_site_connection['ipsec_site_connection']
 dpd = ipsec_sitecon.get('dpd', {})
 ipsec_sitecon['dpd_action'] = dpd.get('action', 'hold')
 ipsec_sitecon['dpd_interval'] = dpd.get('interval', 30)
 ipsec_sitecon['dpd_timeout'] = dpd.get('timeout', 120)
 self._check_dpd(ipsec_sitecon)
 self._check_mtu(context,
 ipsec_sitecon['mtu'],
 ipsec_sitecon['vpnservice_id'])


 However, when considering the update_ipsec_site_connection() API, I realized
 that there could be multiple requests coming in to change the same
 connection’s attributes. In this case, validating and then persisting has
 the issue of incompatible changes being committed (e.g. one client changes
 DPD interval, and another client changes DPD timeout, such that they fail
 the _check_mtu() call).

 I’m wondering what the thoughts are, regarding how to handle this. One way,
 I guess, may be do call the service driver validation from within the
 database logic, like this:

 In VPN plugin
 def create_ipsec_site_connection(self, context, ipsec_site_connection):
 driver = self._get_driver_for_ipsec_site_connection(
 context, ipsec_site_connection)
 ipsec_site_connection = super(
 VPNDriverPlugin, self).create_ipsec_site_connection(
 context, ipsec_site_connection)
 driver.apply_create_ipsec_site_connection(context,
   ipsec_site_connection)
 return ipsec_site_connection

 In Database (pseudo-code)
 def create_ipsec_site_connection(self, context, ipsec_site_connection):
 ipsec_sitecon = ipsec_site_connection['ipsec_site_connection']
 tenant_id = self._get_tenant_id_for_create(context, ipsec_sitecon)
 with context.session.begin(subtransactions=True):
 # I guess this would actually call the child class method to
 # get the driver?
 driver = self._get_driver_for_ipsec_site_connection(
 context, ipsec_sitecon)
 driver.validate_create_ipsec_site_connection(context,
 ipsec_sitecon)


 The database method is a base class of the VPN plugin class, so I’m
 thinking, although awkward, it could work. Can’t say I’m comfortable with
 the call flow here.  Probably could add an abstract method for
 _get_driver_for_ipsec_site_connection(), so that it cannot be called with an
 instance of the database class.

 I’m not seeing a really clean solution here.


 Any thoughts?

 PCM (Paul Michali)

 MAIL …..…. p...@cisco.com
 IRC ……..… pcm_ (irc.freenode.com)
 TW ………... @pmichali
 GPG Key … 4525ECC253E31A83
 Fingerprint .. 307A 96BB 1A4C D2C7 931D 8D2D 4525 ECC2 53E3 1A83



 On May 27, 2014, at 7:37 AM, Paul Michali (pcm) p...@cisco.com wrote:

 Thanks for the comments Mandeep!  Responses in-line #PCM

 On May 23, 2014, at 8:57 PM, Mandeep Dhami dh...@noironetworks.com wrote:

 My preferences:

 For where, I'd go with Gary's recommendation (A) for two reasons (1)
 Consistency and (2) I don't think it will create any boilerplate
 requirements since the abstract class provides the default implementation.


 #PCM Actually, (A) requires a lot of additional code that doesn’t currently
 exist today. ABC methods would be needed for each validation. In addition,
 to be consistent, there should be an abstract method for the apply function,
 and a “pass” implementation on each of the concrete classes. Overall, it is
 adding a lot of code, for arguably little benefit.



 For naming, I'd prefer to go with ML2 terminology for two reasons (1) Again
 Consistency, and (2) it is then clear what actions are happening within a
 transaction or outside of it. With a validation function no 

[openstack-dev] [Neutron] Seeking opinions on scope of code refactoring...

2014-05-23 Thread Paul Michali (pcm)
Hi,

I’m working on a task for a BP to separate validation from persistence logic in 
L3 services code (VPN currently), so that providers can override/extend the 
validation logic (before persistence).

So I’ve separated the code for one of the create APIs, placed the default 
validation into an ABC class (as a non-abstract method) that the service 
drivers inherit from, and modified the plugin to invoke the validation function 
in the service driver, before doing the persistence step.

The flow goes like this…

def create_vpnservice(self, context, vpnservice):
driver = self._get_driver_for_vpnservice(vpnservice)
driver.validate_create_vpnservice(context, vpnservice)
super(VPNDriverPlugin, self).create_vpnservice(context, vpnservice)
driver.apply_create_vpnservice(context, vpnservice)

If the service driver has a validation routine, it’ll be invoked, otherwise, 
the default method in the ABC for the service driver will be called and will 
handle the “baseline” validation. I also renamed the service driver method that 
is used for applying the changes to the device driver as apply_* instead of 
using the same name as is used for persistence (e.g. create_vpnservice - 
apply_create_vpnservice).

The questions I have is…

1) Should I create new validation methods A) for every create (and update?) API 
(regardless of whether they currently have any validation logic, B) for 
resources that have some validation logic already, or C) only for resources 
where there are providers with different validation needs?  I was thinking (B), 
but would like to hear peoples’ thoughts.

2) I’ve added validation_* and modified the other service driver call to 
apply_*. Should I instead, use the ML2 terminology of pre commit_* and post 
commit_*? I personally favor the former, as it is more descriptive of what is 
happening in the methods, but I understand the desire for consistency with 
other code.

3) Should I create validation methods for code, where defaults are being set 
for missing (optional) information? For example, VPN IKE Policy lifetime being 
set to units=seconds, value=3600, if not set. Currently, provider 
implementations have same defaults, but could potentially use different 
defaults. The alternative is to leave this in the persistence code and not 
allow it to be changed. This could be deferred, if 1C is chosen above.

Looking forward to your thoughts...


Thanks!

PCM (Paul Michali)

MAIL …..…. p...@cisco.com
IRC ……..… pcm_ (irc.freenode.com)
TW ………... @pmichali
GPG Key … 4525ECC253E31A83
Fingerprint .. 307A 96BB 1A4C D2C7 931D 8D2D 4525 ECC2 53E3 1A83





signature.asc
Description: Message signed with OpenPGP using GPGMail
___
OpenStack-dev mailing list
OpenStack-dev@lists.openstack.org
http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev


Re: [openstack-dev] [Neutron] Seeking opinions on scope of code refactoring...

2014-05-23 Thread Gary Duan
Hi, Paul,

If the backend driver maintains its own database, I think the pre_commit
and post_commit approach has an advantage. The typical code flow is able to
keep the driver and plugin database consistent.

Regarding question 1, where validation methods should be added, I am
leaning towards A, but I also agree validation hooks can be added later
when they are needed. It's more important to get provider and flavor logic
officially supported for services.

Thanks,
Gary



On Fri, May 23, 2014 at 7:24 AM, Paul Michali (pcm) p...@cisco.com wrote:

 Hi,

 I’m working on a task for a BP to separate validation from persistence
 logic in L3 services code (VPN currently), so that providers can
 override/extend the validation logic (before persistence).

 So I’ve separated the code for one of the create APIs, placed the default
 validation into an ABC class (as a non-abstract method) that the service
 drivers inherit from, and modified the plugin to invoke the validation
 function in the service driver, before doing the persistence step.

 The flow goes like this…

 def create_vpnservice(self, context, vpnservice):
 driver = self._get_driver_for_vpnservice(vpnservice)
 *driver.validate_create_vpnservice(context, vpnservice)*
 super(VPNDriverPlugin, self).create_vpnservice(context, vpnservice)
 driver.apply_create_vpnservice(context, vpnservice)

 If the service driver has a validation routine, it’ll be invoked,
 otherwise, the default method in the ABC for the service driver will be
 called and will handle the “baseline” validation. I also renamed the
 service driver method that is used for applying the changes to the device
 driver as apply_* instead of using the same name as is used for persistence
 (e.g. create_vpnservice - apply_create_vpnservice).

 The questions I have is…

 1) Should I create new validation methods A) for every create (and
 update?) API (regardless of whether they currently have any validation
 logic, B) for resources that have some validation logic already, or C) only
 for resources where there are providers with different validation needs?  I
 was thinking (B), but would like to hear peoples’ thoughts.

 2) I’ve added validation_* and modified the other service driver call to
 apply_*. Should I instead, use the ML2 terminology of pre commit_* and post
 commit_*? I personally favor the former, as it is more descriptive of what
 is happening in the methods, but I understand the desire for consistency
 with other code.

 3) Should I create validation methods for code, where defaults are being
 set for missing (optional) information? For example, VPN IKE Policy
 lifetime being set to units=seconds, value=3600, if not set. Currently,
 provider implementations have same defaults, but *could* potentially use
 different defaults. The alternative is to leave this in the persistence
 code and not allow it to be changed. This could be deferred, if 1C is
 chosen above.

 Looking forward to your thoughts...


 Thanks!

 PCM (Paul Michali)

 MAIL …..…. p...@cisco.com
 IRC ……..… pcm_ (irc.freenode.com)
 TW ………... @pmichali
 GPG Key … 4525ECC253E31A83
 Fingerprint .. 307A 96BB 1A4C D2C7 931D 8D2D 4525 ECC2 53E3 1A83




 ___
 OpenStack-dev mailing list
 OpenStack-dev@lists.openstack.org
 http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev


___
OpenStack-dev mailing list
OpenStack-dev@lists.openstack.org
http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev


Re: [openstack-dev] [Neutron] Seeking opinions on scope of code refactoring...

2014-05-23 Thread Paul Michali (pcm)
Thanks for the comments Gary!

Typically, the device driver (backend) and service driver, for a provider won’t 
have any database requirements (at least for VPN). For the Cisco VPN, the 
service driver has one additional table that it maintains for mapping, but even 
in that case, there is no modification to the built in tables for the VPN 
plugin.

So, the action is validation, persist, apply, with the validation possibly 
having a provider override/extend, the apply always having a provider action, 
and the persistence always being the “core” persistence.  It’s a question of 
being validate, persist/commit, apply, or pre-commit, commit/persist, 
post-commit, for naming.

Regards,


PCM (Paul Michali)

MAIL …..…. p...@cisco.com
IRC ……..… pcm_ (irc.freenode.com)
TW ………... @pmichali
GPG Key … 4525ECC253E31A83
Fingerprint .. 307A 96BB 1A4C D2C7 931D 8D2D 4525 ECC2 53E3 1A83



On May 23, 2014, at 12:40 PM, Gary Duan garyd...@gmail.com wrote:

 Hi, Paul,
 
 If the backend driver maintains its own database, I think the pre_commit and 
 post_commit approach has an advantage. The typical code flow is able to keep 
 the driver and plugin database consistent.
 
 Regarding question 1, where validation methods should be added, I am leaning 
 towards A, but I also agree validation hooks can be added later when they are 
 needed. It's more important to get provider and flavor logic officially 
 supported for services.
 
 Thanks,
 Gary
 
 
 
 On Fri, May 23, 2014 at 7:24 AM, Paul Michali (pcm) p...@cisco.com wrote:
 Hi,
 
 I’m working on a task for a BP to separate validation from persistence logic 
 in L3 services code (VPN currently), so that providers can override/extend 
 the validation logic (before persistence).
 
 So I’ve separated the code for one of the create APIs, placed the default 
 validation into an ABC class (as a non-abstract method) that the service 
 drivers inherit from, and modified the plugin to invoke the validation 
 function in the service driver, before doing the persistence step.
 
 The flow goes like this…
 
 def create_vpnservice(self, context, vpnservice):
 driver = self._get_driver_for_vpnservice(vpnservice)
 driver.validate_create_vpnservice(context, vpnservice)
 super(VPNDriverPlugin, self).create_vpnservice(context, vpnservice)
 driver.apply_create_vpnservice(context, vpnservice)
 
 If the service driver has a validation routine, it’ll be invoked, otherwise, 
 the default method in the ABC for the service driver will be called and will 
 handle the “baseline” validation. I also renamed the service driver method 
 that is used for applying the changes to the device driver as apply_* instead 
 of using the same name as is used for persistence (e.g. create_vpnservice - 
 apply_create_vpnservice).
 
 The questions I have is…
 
 1) Should I create new validation methods A) for every create (and update?) 
 API (regardless of whether they currently have any validation logic, B) for 
 resources that have some validation logic already, or C) only for resources 
 where there are providers with different validation needs?  I was thinking 
 (B), but would like to hear peoples’ thoughts.
 
 2) I’ve added validation_* and modified the other service driver call to 
 apply_*. Should I instead, use the ML2 terminology of pre commit_* and post 
 commit_*? I personally favor the former, as it is more descriptive of what is 
 happening in the methods, but I understand the desire for consistency with 
 other code.
 
 3) Should I create validation methods for code, where defaults are being set 
 for missing (optional) information? For example, VPN IKE Policy lifetime 
 being set to units=seconds, value=3600, if not set. Currently, provider 
 implementations have same defaults, but could potentially use different 
 defaults. The alternative is to leave this in the persistence code and not 
 allow it to be changed. This could be deferred, if 1C is chosen above.
 
 Looking forward to your thoughts...
 
 
 Thanks!
 
 PCM (Paul Michali)
 
 MAIL …..…. p...@cisco.com
 IRC ……..… pcm_ (irc.freenode.com)
 TW ………... @pmichali
 GPG Key … 4525ECC253E31A83
 Fingerprint .. 307A 96BB 1A4C D2C7 931D 8D2D 4525 ECC2 53E3 1A83
 
 
 
 
 ___
 OpenStack-dev mailing list
 OpenStack-dev@lists.openstack.org
 http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev
 
 
 ___
 OpenStack-dev mailing list
 OpenStack-dev@lists.openstack.org
 http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev



signature.asc
Description: Message signed with OpenPGP using GPGMail
___
OpenStack-dev mailing list
OpenStack-dev@lists.openstack.org
http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev


Re: [openstack-dev] [Neutron] Seeking opinions on scope of code refactoring...

2014-05-23 Thread Robert Kukura


On 5/23/14, 3:07 PM, Paul Michali (pcm) wrote:

Thanks for the comments Gary!

Typically, the device driver (backend) and service driver, for a 
provider won't have any database requirements (at least for VPN). For 
the Cisco VPN, the service driver has one additional table that it 
maintains for mapping, but even in that case, there is no modification 
to the built in tables for the VPN plugin.
If these sorts of additional tables might use foreign keys, cascaded 
deletes, etc., it probably make sense to go with the precommit approach 
to make these explicitly part of the transactions.


-Bob


So, the action is validation, persist, apply, with the validation 
possibly having a provider override/extend, the apply always having a 
provider action, and the persistence always being the core 
persistence.  It's a question of being validate, persist/commit, 
apply, or pre-commit, commit/persist, post-commit, for naming.


Regards,


PCM (Paul Michali)

MAIL . p...@cisco.com mailto:p...@cisco.com
IRC ... pcm_ (irc.freenode.com http://irc.freenode.com)
TW  @pmichali
GPG Key ... 4525ECC253E31A83
Fingerprint .. 307A 96BB 1A4C D2C7 931D 8D2D 4525 ECC2 53E3 1A83



On May 23, 2014, at 12:40 PM, Gary Duan garyd...@gmail.com 
mailto:garyd...@gmail.com wrote:



Hi, Paul,

If the backend driver maintains its own database, I think the 
pre_commit and post_commit approach has an advantage. The typical 
code flow is able to keep the driver and plugin database consistent.


Regarding question 1, where validation methods should be added, I am 
leaning towards A, but I also agree validation hooks can be added 
later when they are needed. It's more important to get provider and 
flavor logic officially supported for services.


Thanks,
Gary



On Fri, May 23, 2014 at 7:24 AM, Paul Michali (pcm) p...@cisco.com 
mailto:p...@cisco.com wrote:


Hi,

I'm working on a task for a BP to separate validation from
persistence logic in L3 services code (VPN currently), so that
providers can override/extend the validation logic (before
persistence).

So I've separated the code for one of the create APIs, placed the
default validation into an ABC class (as a non-abstract method)
that the service drivers inherit from, and modified the plugin to
invoke the validation function in the service driver, before
doing the persistence step.

The flow goes like this...

def create_vpnservice(self, context, vpnservice):
driver = self._get_driver_for_vpnservice(vpnservice)
*driver.validate_create_vpnservice(context, vpnservice)*
super(VPNDriverPlugin, self).create_vpnservice(context,
vpnservice)
driver.apply_create_vpnservice(context, vpnservice)

If the service driver has a validation routine, it'll be invoked,
otherwise, the default method in the ABC for the service driver
will be called and will handle the baseline validation. I also
renamed the service driver method that is used for applying the
changes to the device driver as apply_* instead of using the same
name as is used for persistence (e.g. create_vpnservice -
apply_create_vpnservice).

The questions I have is...

1) Should I create new validation methods A) for every create
(and update?) API (regardless of whether they currently have any
validation logic, B) for resources that have some validation
logic already, or C) only for resources where there are providers
with different validation needs?  I was thinking (B), but would
like to hear peoples' thoughts.

2) I've added validation_* and modified the other service driver
call to apply_*. Should I instead, use the ML2 terminology of pre
commit_* and post commit_*? I personally favor the former, as it
is more descriptive of what is happening in the methods, but I
understand the desire for consistency with other code.

3) Should I create validation methods for code, where defaults
are being set for missing (optional) information? For example,
VPN IKE Policy lifetime being set to units=seconds, value=3600,
if not set. Currently, provider implementations have same
defaults, but *could* potentially use different defaults. The
alternative is to leave this in the persistence code and not
allow it to be changed. This could be deferred, if 1C is chosen
above.

Looking forward to your thoughts...


Thanks!

PCM (Paul Michali)

MAIL . p...@cisco.com mailto:p...@cisco.com
IRC ... pcm_ (irc.freenode.com http://irc.freenode.com/)
TW  @pmichali
GPG Key ... 4525ECC253E31A83
Fingerprint .. 307A 96BB 1A4C D2C7 931D 8D2D 4525 ECC2 53E3 1A83




___
OpenStack-dev mailing list
OpenStack-dev@lists.openstack.org
mailto:OpenStack-dev@lists.openstack.org
http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev



Re: [openstack-dev] [Neutron] Seeking opinions on scope of code refactoring...

2014-05-23 Thread Paul Michali (pcm)

On May 23, 2014, at 3:35 PM, Robert Kukura kuk...@noironetworks.com wrote:

 
 On 5/23/14, 3:07 PM, Paul Michali (pcm) wrote:
 Thanks for the comments Gary!
 
 Typically, the device driver (backend) and service driver, for a provider 
 won’t have any database requirements (at least for VPN). For the Cisco VPN, 
 the service driver has one additional table that it maintains for mapping, 
 but even in that case, there is no modification to the built in tables for 
 the VPN plugin.
 If these sorts of additional tables might use foreign keys, cascaded deletes, 
 etc., it probably make sense to go with the precommit approach to make these 
 explicitly part of the transactions.

Hi Bob,

In the Cisco case, it is a single table that has a key that is the IPSec 
site-to-site connection UUID, and then two numerical ID fields that are used to 
map OpenStack IPSec and IKE policy IDs to Cisco CSR ID numbers (they don’t 
support UUIDs). It’s the only table I’ve come across so far, so, not a common 
thing.


PCM (Paul Michali)

MAIL …..…. p...@cisco.com
IRC ……..… pcm_ (irc.freenode.com)
TW ………... @pmichali
GPG Key … 4525ECC253E31A83
Fingerprint .. 307A 96BB 1A4C D2C7 931D 8D2D 4525 ECC2 53E3 1A83


 
 -Bob
 
 So, the action is validation, persist, apply, with the validation possibly 
 having a provider override/extend, the apply always having a provider 
 action, and the persistence always being the “core” persistence.  It’s a 
 question of being validate, persist/commit, apply, or pre-commit, 
 commit/persist, post-commit, for naming.
 
 Regards,
 
 
 PCM (Paul Michali)
 
 MAIL …..…. p...@cisco.com
 IRC ……..… pcm_ (irc.freenode.com)
 TW ………... @pmichali
 GPG Key … 4525ECC253E31A83
 Fingerprint .. 307A 96BB 1A4C D2C7 931D 8D2D 4525 ECC2 53E3 1A83
 
 
 
 On May 23, 2014, at 12:40 PM, Gary Duan garyd...@gmail.com wrote:
 
 Hi, Paul,
 
 If the backend driver maintains its own database, I think the pre_commit 
 and post_commit approach has an advantage. The typical code flow is able to 
 keep the driver and plugin database consistent.
 
 Regarding question 1, where validation methods should be added, I am 
 leaning towards A, but I also agree validation hooks can be added later 
 when they are needed. It's more important to get provider and flavor logic 
 officially supported for services.
 
 Thanks,
 Gary
 
 
 
 On Fri, May 23, 2014 at 7:24 AM, Paul Michali (pcm) p...@cisco.com wrote:
 Hi,
 
 I’m working on a task for a BP to separate validation from persistence 
 logic in L3 services code (VPN currently), so that providers can 
 override/extend the validation logic (before persistence).
 
 So I’ve separated the code for one of the create APIs, placed the default 
 validation into an ABC class (as a non-abstract method) that the service 
 drivers inherit from, and modified the plugin to invoke the validation 
 function in the service driver, before doing the persistence step.
 
 The flow goes like this…
 
 def create_vpnservice(self, context, vpnservice):
 driver = self._get_driver_for_vpnservice(vpnservice)
 driver.validate_create_vpnservice(context, vpnservice)
 super(VPNDriverPlugin, self).create_vpnservice(context, vpnservice)
 driver.apply_create_vpnservice(context, vpnservice)
 
 If the service driver has a validation routine, it’ll be invoked, 
 otherwise, the default method in the ABC for the service driver will be 
 called and will handle the “baseline” validation. I also renamed the 
 service driver method that is used for applying the changes to the device 
 driver as apply_* instead of using the same name as is used for persistence 
 (e.g. create_vpnservice - apply_create_vpnservice).
 
 The questions I have is…
 
 1) Should I create new validation methods A) for every create (and update?) 
 API (regardless of whether they currently have any validation logic, B) for 
 resources that have some validation logic already, or C) only for resources 
 where there are providers with different validation needs?  I was thinking 
 (B), but would like to hear peoples’ thoughts.
 
 2) I’ve added validation_* and modified the other service driver call to 
 apply_*. Should I instead, use the ML2 terminology of pre commit_* and post 
 commit_*? I personally favor the former, as it is more descriptive of what 
 is happening in the methods, but I understand the desire for consistency 
 with other code.
 
 3) Should I create validation methods for code, where defaults are being 
 set for missing (optional) information? For example, VPN IKE Policy 
 lifetime being set to units=seconds, value=3600, if not set. Currently, 
 provider implementations have same defaults, but could potentially use 
 different defaults. The alternative is to leave this in the persistence 
 code and not allow it to be changed. This could be deferred, if 1C is 
 chosen above.
 
 Looking forward to your thoughts...
 
 
 Thanks!
 
 PCM (Paul Michali)
 
 MAIL …..…. p...@cisco.com
 IRC ……..… pcm_ (irc.freenode.com)
 TW 

Re: [openstack-dev] [Neutron] Seeking opinions on scope of code refactoring...

2014-05-23 Thread Carl Baldwin
Paul,

On Fri, May 23, 2014 at 8:24 AM, Paul Michali (pcm) p...@cisco.com wrote:
 Hi,

 I’m working on a task for a BP to separate validation from persistence logic
 in L3 services code (VPN currently), so that providers can override/extend
 the validation logic (before persistence).

 So I’ve separated the code for one of the create APIs, placed the default
 validation into an ABC class (as a non-abstract method) that the service
 drivers inherit from, and modified the plugin to invoke the validation
 function in the service driver, before doing the persistence step.

 The flow goes like this…

 def create_vpnservice(self, context, vpnservice):
 driver = self._get_driver_for_vpnservice(vpnservice)
 driver.validate_create_vpnservice(context, vpnservice)
 super(VPNDriverPlugin, self).create_vpnservice(context, vpnservice)
 driver.apply_create_vpnservice(context, vpnservice)

 If the service driver has a validation routine, it’ll be invoked, otherwise,
 the default method in the ABC for the service driver will be called and will
 handle the “baseline” validation. I also renamed the service driver method
 that is used for applying the changes to the device driver as apply_*
 instead of using the same name as is used for persistence (e.g.
 create_vpnservice - apply_create_vpnservice).

 The questions I have is…

 1) Should I create new validation methods A) for every create (and update?)
 API (regardless of whether they currently have any validation logic, B) for
 resources that have some validation logic already, or C) only for resources
 where there are providers with different validation needs?  I was thinking
 (B), but would like to hear peoples’ thoughts.

I think B.  C may leave a little too much inconsistency.  A feels like
extra boiler-plate.  Would there be any benefit to creating a higher
level abstraction for the create/update API calls?  I'm not suggesting
you do so but if you did then you could add a validation method to
that interface with a default pass.  Otherwise, I'd stick with B until
there is a need for more.

 2) I’ve added validation_* and modified the other service driver call to
 apply_*. Should I instead, use the ML2 terminology of pre commit_* and post
 commit_*? I personally favor the former, as it is more descriptive of what
 is happening in the methods, but I understand the desire for consistency
 with other code.

I'm on the fence.  ML2 is not where I'm most familiar and I don't know
the history behind that design.  Without considering ML2 and
consistency, I think I like your terminology better.

 3) Should I create validation methods for code, where defaults are being set
 for missing (optional) information? For example, VPN IKE Policy lifetime
 being set to units=seconds, value=3600, if not set. Currently, provider
 implementations have same defaults, but could potentially use different
 defaults. The alternative is to leave this in the persistence code and not
 allow it to be changed. This could be deferred, if 1C is chosen above.

I'm tempted to say punt on this until there is a need for it.

Carl

 Looking forward to your thoughts...


 Thanks!

 PCM (Paul Michali)

 MAIL …..…. p...@cisco.com
 IRC ……..… pcm_ (irc.freenode.com)
 TW ………... @pmichali
 GPG Key … 4525ECC253E31A83
 Fingerprint .. 307A 96BB 1A4C D2C7 931D 8D2D 4525 ECC2 53E3 1A83




 ___
 OpenStack-dev mailing list
 OpenStack-dev@lists.openstack.org
 http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev


___
OpenStack-dev mailing list
OpenStack-dev@lists.openstack.org
http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev


Re: [openstack-dev] [Neutron] Seeking opinions on scope of code refactoring...

2014-05-23 Thread Paul Michali (pcm)
Thanks for the comment Carl. See @PCM inline


PCM (Paul Michali)

MAIL …..…. p...@cisco.com
IRC ……..… pcm_ (irc.freenode.com)
TW ………... @pmichali
GPG Key … 4525ECC253E31A83
Fingerprint .. 307A 96BB 1A4C D2C7 931D 8D2D 4525 ECC2 53E3 1A83



On May 23, 2014, at 6:09 PM, Carl Baldwin c...@ecbaldwin.net wrote:

 Paul,
 
 On Fri, May 23, 2014 at 8:24 AM, Paul Michali (pcm) p...@cisco.com wrote:
 Hi,
 
 I’m working on a task for a BP to separate validation from persistence logic
 in L3 services code (VPN currently), so that providers can override/extend
 the validation logic (before persistence).
 
 So I’ve separated the code for one of the create APIs, placed the default
 validation into an ABC class (as a non-abstract method) that the service
 drivers inherit from, and modified the plugin to invoke the validation
 function in the service driver, before doing the persistence step.
 
 The flow goes like this…
 
def create_vpnservice(self, context, vpnservice):
driver = self._get_driver_for_vpnservice(vpnservice)
driver.validate_create_vpnservice(context, vpnservice)
super(VPNDriverPlugin, self).create_vpnservice(context, vpnservice)
driver.apply_create_vpnservice(context, vpnservice)
 
 If the service driver has a validation routine, it’ll be invoked, otherwise,
 the default method in the ABC for the service driver will be called and will
 handle the “baseline” validation. I also renamed the service driver method
 that is used for applying the changes to the device driver as apply_*
 instead of using the same name as is used for persistence (e.g.
 create_vpnservice - apply_create_vpnservice).
 
 The questions I have is…
 
 1) Should I create new validation methods A) for every create (and update?)
 API (regardless of whether they currently have any validation logic, B) for
 resources that have some validation logic already, or C) only for resources
 where there are providers with different validation needs?  I was thinking
 (B), but would like to hear peoples’ thoughts.
 
 I think B.  C may leave a little too much inconsistency.  A feels like
 extra boiler-plate.  Would there be any benefit to creating a higher
 level abstraction for the create/update API calls?  I'm not suggesting
 you do so but if you did then you could add a validation method to
 that interface with a default pass.  Otherwise, I'd stick with B until
 there is a need for more.

@PCM Yeah, there is somewhat of an abstraction. In VPN, for the service 
drivers, they all inherit from an ABC. For the apply, there are already 
abstract methods in the ABC, so that the service driver is forced to provide a 
function (of course it is inconsistent currently - they are there for VPN 
services, but not for IPSec connections, which are provided in the service 
driver). For the validation, I was creating methods in the ABC, with 
implementations, but not abstract, so that the service driver could provide a 
function, if it wanted to extend or override (and call super, if desired), or 
leave it out and the base class function would be used.

So, I guess it’s at two points, the validate and apply methods, where we should 
probably be consistent with providing base class methods for all that present 
in the service driver.


 
 2) I’ve added validation_* and modified the other service driver call to
 apply_*. Should I instead, use the ML2 terminology of pre commit_* and post
 commit_*? I personally favor the former, as it is more descriptive of what
 is happening in the methods, but I understand the desire for consistency
 with other code.
 
 I'm on the fence.  ML2 is not where I'm most familiar and I don't know
 the history behind that design.  Without considering ML2 and
 consistency, I think I like your terminology better.

@PCM I’m in the same camp. I don’t know ML2 well, and I like the explicit 
terminology. It *seems* like ML2 is dealing with this all at the same level of 
abstraction (pre-commit, commit, post-commit all for the same plugin or 
driver), whereas with L3 services, it is at two levels (validate at service 
driver and then plugin, commit at plugin, apply at service driver only). I 
guess I can leave it and see what happens at review…I have some asbestos here 
somewhere.


 
 3) Should I create validation methods for code, where defaults are being set
 for missing (optional) information? For example, VPN IKE Policy lifetime
 being set to units=seconds, value=3600, if not set. Currently, provider
 implementations have same defaults, but could potentially use different
 defaults. The alternative is to leave this in the persistence code and not
 allow it to be changed. This could be deferred, if 1C is chosen above.
 
 I'm tempted to say punt on this until there is a need for it.

@PCM I think you’re right. It may turn out to be YAGNI.

Thanks!

PCM


 
 Carl
 
 Looking forward to your thoughts...
 
 
 Thanks!
 
 PCM (Paul Michali)
 
 MAIL …..…. p...@cisco.com
 IRC ……..… pcm_ (irc.freenode.com)
 TW ………... 

Re: [openstack-dev] [Neutron] Seeking opinions on scope of code refactoring...

2014-05-23 Thread Mandeep Dhami
My preferences:

For where, I'd go with Gary's recommendation (A) for two reasons (1)
Consistency and (2) I don't think it will create any boilerplate
requirements since the abstract class provides the default implementation.

For naming, I'd prefer to go with ML2 terminology for two reasons (1) Again
Consistency, and (2) it is then clear what actions are happening within a
transaction or outside of it. With a validation function no transaction
fence is implied by it's name - but for any validation that depends on
what currently exists in the database, these transaction semantics are
important.

Regards,
Mandeep



On Fri, May 23, 2014 at 4:25 PM, Paul Michali (pcm) p...@cisco.com wrote:

 Thanks for the comment Carl. See @PCM inline


 PCM (Paul Michali)

 MAIL …..…. p...@cisco.com
 IRC ……..… pcm_ (irc.freenode.com)
 TW ………... @pmichali
 GPG Key … 4525ECC253E31A83
 Fingerprint .. 307A 96BB 1A4C D2C7 931D 8D2D 4525 ECC2 53E3 1A83



 On May 23, 2014, at 6:09 PM, Carl Baldwin c...@ecbaldwin.net wrote:

 Paul,

 On Fri, May 23, 2014 at 8:24 AM, Paul Michali (pcm) p...@cisco.com wrote:

 Hi,

 I’m working on a task for a BP to separate validation from persistence
 logic
 in L3 services code (VPN currently), so that providers can override/extend
 the validation logic (before persistence).

 So I’ve separated the code for one of the create APIs, placed the default
 validation into an ABC class (as a non-abstract method) that the service
 drivers inherit from, and modified the plugin to invoke the validation
 function in the service driver, before doing the persistence step.

 The flow goes like this…

def create_vpnservice(self, context, vpnservice):
driver = self._get_driver_for_vpnservice(vpnservice)
driver.validate_create_vpnservice(context, vpnservice)
super(VPNDriverPlugin, self).create_vpnservice(context, vpnservice)
driver.apply_create_vpnservice(context, vpnservice)

 If the service driver has a validation routine, it’ll be invoked,
 otherwise,
 the default method in the ABC for the service driver will be called and
 will
 handle the “baseline” validation. I also renamed the service driver method
 that is used for applying the changes to the device driver as apply_*
 instead of using the same name as is used for persistence (e.g.
 create_vpnservice - apply_create_vpnservice).

 The questions I have is…

 1) Should I create new validation methods A) for every create (and update?)
 API (regardless of whether they currently have any validation logic, B) for
 resources that have some validation logic already, or C) only for resources
 where there are providers with different validation needs?  I was thinking
 (B), but would like to hear peoples’ thoughts.


 I think B.  C may leave a little too much inconsistency.  A feels like
 extra boiler-plate.  Would there be any benefit to creating a higher
 level abstraction for the create/update API calls?  I'm not suggesting
 you do so but if you did then you could add a validation method to
 that interface with a default pass.  Otherwise, I'd stick with B until
 there is a need for more.


 @PCM Yeah, there is somewhat of an abstraction. In VPN, for the service
 drivers, they all inherit from an ABC. For the apply, there are already
 abstract methods in the ABC, so that the service driver is forced to
 provide a function (of course it is inconsistent currently - they are there
 for VPN services, but not for IPSec connections, which are provided in the
 service driver). For the validation, I was creating methods in the ABC,
 with implementations, but not abstract, so that the service driver could
 provide a function, if it wanted to extend or override (and call super, if
 desired), or leave it out and the base class function would be used.

 So, I guess it’s at two points, the validate and apply methods, where we
 should probably be consistent with providing base class methods for all
 that present in the service driver.



 2) I’ve added validation_* and modified the other service driver call to
 apply_*. Should I instead, use the ML2 terminology of pre commit_* and post
 commit_*? I personally favor the former, as it is more descriptive of what
 is happening in the methods, but I understand the desire for consistency
 with other code.


 I'm on the fence.  ML2 is not where I'm most familiar and I don't know
 the history behind that design.  Without considering ML2 and
 consistency, I think I like your terminology better.


 @PCM I’m in the same camp. I don’t know ML2 well, and I like the explicit
 terminology. It *seems* like ML2 is dealing with this all at the same level
 of abstraction (pre-commit, commit, post-commit all for the same plugin or
 driver), whereas with L3 services, it is at two levels (validate at service
 driver and then plugin, commit at plugin, apply at service driver only). I
 guess I can leave it and see what happens at review…I have some asbestos
 here somewhere.



 3) Should I create validation methods