diff --git a/adjutant/actions/utils.py b/adjutant/actions/utils.py index 1b28471..9c32a26 100644 --- a/adjutant/actions/utils.py +++ b/adjutant/actions/utils.py @@ -8,6 +8,25 @@ from django.template import loader from django.conf import settings +def validate_steps(validation_steps): + """Helper function for validation in actions + + Takes a list of validation functions or validation function results. + If function, will call it first, otherwise checks if valid. Will break + and return False on first validation failure, or return True if all valid. + + It is best to pass in the functions and let this call them so that it + doesn't keep validating after the first invalid result. + """ + for step in validation_steps: + if callable(step): + if not step(): + return False + if not step: + return False + return True + + def send_email(to_addresses, context, conf, task): """ Function for sending emails from actions diff --git a/adjutant/actions/v1/projects.py b/adjutant/actions/v1/projects.py index cbb6213..4f5d8e3 100644 --- a/adjutant/actions/v1/projects.py +++ b/adjutant/actions/v1/projects.py @@ -18,6 +18,7 @@ from django.utils import timezone from adjutant.common import user_store from adjutant.common.utils import str_datetime +from adjutant.actions.utils import validate_steps from adjutant.actions.v1.base import ( BaseAction, UserNameAction, UserMixin, ProjectMixin) @@ -40,10 +41,11 @@ class NewProjectAction(BaseAction, ProjectMixin, UserMixin): super(NewProjectAction, self).__init__(*args, **kwargs) def _validate(self): - self.action.valid = ( - self._validate_domain_id() and - self._validate_parent_project() and - self._validate_project_absent()) + self.action.valid = validate_steps([ + self._validate_domain_id, + self._validate_parent_project, + self._validate_project_absent, + ]) self.action.save() def _validate_domain_id(self): @@ -137,11 +139,12 @@ class NewProjectWithUserAction(UserNameAction, ProjectMixin, UserMixin): super(NewProjectWithUserAction, self).__init__(*args, **kwargs) def _validate(self): - self.action.valid = ( - self._validate_domain_id() and - self._validate_parent_project() and - self._validate_project_absent() and - self._validate_user()) + self.action.valid = validate_steps([ + self._validate_domain_id, + self._validate_parent_project, + self._validate_project_absent, + self._validate_user, + ]) self.action.save() def _validate_user(self): @@ -420,14 +423,16 @@ class AddDefaultUsersToProjectAction(BaseAction, ProjectMixin, UserMixin): return all_found def _pre_validate(self): - self.action.valid = self._validate_users() + self.action.valid = validate_steps([ + self._validate_users, + ]) self.action.save() def _validate(self): - self.action.valid = ( - self._validate_users() and - self._validate_project_id() - ) + self.action.valid = validate_steps([ + self._validate_users, + self._validate_project_id, + ]) self.action.save() def _pre_approve(self): diff --git a/adjutant/actions/v1/resources.py b/adjutant/actions/v1/resources.py index 0d2419d..a67c19a 100644 --- a/adjutant/actions/v1/resources.py +++ b/adjutant/actions/v1/resources.py @@ -13,6 +13,7 @@ # under the License. from adjutant.actions.v1.base import BaseAction, ProjectMixin, QuotaMixin +from adjutant.actions.utils import validate_steps from adjutant.common import openstack_clients, user_store from adjutant.api import models from adjutant.common.quota import QuotaManager @@ -70,12 +71,12 @@ class NewDefaultNetworkAction(BaseAction, ProjectMixin): return True def _validate(self): - self.action.valid = ( - self._validate_region() and - self._validate_project_id() and - self._validate_defaults() and - self._validate_keystone_user() - ) + self.action.valid = validate_steps([ + self._validate_region, + self._validate_project_id, + self._validate_defaults, + self._validate_keystone_user, + ]) self.action.save() def _create_network(self): @@ -199,18 +200,18 @@ class NewProjectDefaultNetworkAction(NewDefaultNetworkAction): def _pre_validate(self): # Note: Don't check project here as it doesn't exist yet. - self.action.valid = ( - self._validate_region() and - self._validate_defaults() - ) + self.action.valid = validate_steps([ + self._validate_region, + self._validate_defaults, + ]) self.action.save() def _validate(self): - self.action.valid = ( - self._validate_region() and - self._validate_project_id() and - self._validate_defaults() - ) + self.action.valid = validate_steps([ + self._validate_region, + self._validate_project_id, + self._validate_defaults, + ]) self.action.save() def _pre_approve(self): @@ -347,12 +348,12 @@ class UpdateProjectQuotasAction(BaseAction, QuotaMixin): def _validate(self): # Make sure the project id is valid and can be used - self.action.valid = ( - self._validate_project_id() and - self._validate_quota_size_exists() and - self._validate_regions_exist() and - self._validate_usage_lower_than_quota() - ) + self.action.valid = validate_steps([ + self._validate_project_id, + self._validate_quota_size_exists, + self._validate_regions_exist, + self._validate_usage_lower_than_quota, + ]) self.action.save() def _pre_approve(self): @@ -393,9 +394,9 @@ class SetProjectQuotaAction(UpdateProjectQuotasAction): def _validate(self): # Make sure the project id is valid and can be used - self.action.valid = ( - self._validate_project_id() - ) + self.action.valid = validate_steps([ + self._validate_project_id, + ]) self.action.save() def _pre_approve(self): diff --git a/adjutant/actions/v1/users.py b/adjutant/actions/v1/users.py index 8b70542..396d3f8 100644 --- a/adjutant/actions/v1/users.py +++ b/adjutant/actions/v1/users.py @@ -18,6 +18,7 @@ from django.db import models from adjutant.common import user_store from adjutant.actions.v1.base import ( UserNameAction, UserIdAction, UserMixin, ProjectMixin) +from adjutant.actions.utils import validate_steps class NewUserAction(UserNameAction, ProjectMixin, UserMixin): @@ -91,13 +92,13 @@ class NewUserAction(UserNameAction, ProjectMixin, UserMixin): return True def _validate(self): - self.action.valid = ( - self._validate_role_permissions() and - self._validate_keystone_user() and - self._validate_domain_id() and - self._validate_project_id() and - self._validate_target_user() - ) + self.action.valid = validate_steps([ + self._validate_role_permissions, + self._validate_keystone_user, + self._validate_domain_id, + self._validate_project_id, + self._validate_target_user, + ]) self.action.save() def _pre_approve(self): @@ -203,11 +204,11 @@ class ResetUserPasswordAction(UserNameAction, UserMixin): def _validate(self): # Here, the order of validation matters # as each one adds new class variables - self.action.valid = all([ - self._validate_domain_name(), - self._validate_username_exists(), - self._validate_user_roles(), - self._validate_user_email(), + self.action.valid = validate_steps([ + self._validate_domain_name, + self._validate_username_exists, + self._validate_user_roles, + self._validate_user_email, ]) self.action.save() @@ -311,14 +312,14 @@ class EditUserRolesAction(UserIdAction, ProjectMixin, UserMixin): return new_roles_manageable and current_roles_manageable def _validate(self): - self.action.valid = ( - self._validate_keystone_user() and - self._validate_role_permissions() and - self._validate_domain_id() and - self._validate_project_id() and - self._validate_target_user() and - self._validate_user_roles() - ) + self.action.valid = validate_steps([ + self._validate_keystone_user, + self._validate_role_permissions, + self._validate_domain_id, + self._validate_project_id, + self._validate_target_user, + self._validate_user_roles, + ]) self.action.save() def _pre_approve(self): @@ -384,8 +385,10 @@ class UpdateUserEmailAction(UserIdAction, UserMixin): return self.new_email def _validate(self): - self.action.valid = (self._validate_user() and - self._validate_email_not_in_use()) + self.action.valid = validate_steps([ + self._validate_user, + self._validate_email_not_in_use, + ]) self.action.save() def _validate_user(self):