# Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. from fuel_external_git import json_schema from fuel_external_git.objects import ChangesWhitelistRule from fuel_external_git.objects import ChangesWhitelistRuleCollection from fuel_external_git.objects import GitRepo from fuel_external_git.objects import GitRepoCollection from nailgun.api.v1.handlers.base import CollectionHandler from nailgun.api.v1.handlers.base import handle_errors from nailgun.api.v1.handlers.base import serialize from nailgun.api.v1.handlers.base import SingleHandler from nailgun.api.v1.handlers.base import validate from nailgun.api.v1.validators import base from nailgun import errors from nailgun import objects REPOS_DIR = '/var/lib/fuel_repos' class GitRepoValidator(base.BasicValidator): single_schema = json_schema.gitrepo_single_schema collection_schema = json_schema.gitrepo_collection_schema _blocked_for_update = ( 'env_id', ) @classmethod def _validate_master_mgmt(self, data, instance=None): d = self.validate_json(data) if instance: repo_id = instance.id else: repo_id = d.get('id', None) if d.get('manage_master', False): for repo in GitRepoCollection.all(): if repo.manage_master and repo_id != repo.id: raise errors.InvalidData( ("Repo {} already marked for Fuel Master management. " "Disable it first".format(repo.id)), log_message=True) return d @classmethod def validate(self, data): return self._validate_master_mgmt(data) @classmethod def validate_update(self, data, instance): d = self._validate_master_mgmt(data, instance) env_id = d.get('env_id') if env_id: cluster = objects.Cluster.get_by_uid(env_id) if not cluster: raise errors.InvalidData( "Invalid cluster ID", log_message=True) for k in self._blocked_for_update: if k in d and getattr(instance, k) != d[k]: raise errors.InvalidData( u"Changing '{0}' for git repo is prohibited".format(k), log_message=True ) return d class ChangesWhitelistRuleValidator(base.BasicValidator): single_schema = json_schema.changeswhitelistrule_single_schema collection_schema = json_schema.changeswhitelistrule_collection_schema _blocked_for_update = ( 'env_id', ) @classmethod def validate_update(self, data, instance): d = self.validate_json(data) for k in self._blocked_for_update: if k in d and getattr(instance, k) != d[k]: raise errors.InvalidData( u"Changing '{0}' for white list is prohibited".format(k), log_message=True ) return d # TODO(dnikishov): investigate if there's a more simple way to do this @classmethod def validate_one_or_multiple(self, data): d = self.validate_json(data) if not isinstance(d, list): d = [d] for item in d: self.validate_schema(item, self.single_schema) return d # This is required for inherited handlers to work @classmethod def validate_delete(self, *args, **kwargs): pass class GitRepoCollectionHandler(CollectionHandler): collection = GitRepoCollection validator = GitRepoValidator class GitRepoHandler(SingleHandler): single = GitRepo validator = GitRepoValidator @handle_errors @validate @serialize def GET(self, cluster_id, obj_id): """:returns: JSONized REST object. :http: * 200 (OK) * 404 (dashboard entry not found in db) """ self.get_object_or_404(objects.Cluster, cluster_id) obj = self.get_object_or_404(self.single, obj_id) return self.single.to_json(obj) @handle_errors @validate @serialize def PUT(self, cluster_id, obj_id): """:returns: JSONized REST object. :http: * 200 (OK) * 400 (invalid object data specified) * 404 (object not found in db) """ obj = self.get_object_or_404(self.single, obj_id) data = self.checked_data( self.validator.validate_update, instance=obj ) self.single.update(obj, data) return self.single.to_json(obj) def PATCH(self, cluster_id, obj_id): """:returns: JSONized REST object. :http: * 200 (OK) * 400 (invalid object data specified) * 404 (object not found in db) """ return self.PUT(cluster_id, obj_id) @handle_errors @serialize def DELETE(self, cluster_id, obj_id): """:returns: JSONized REST object. :http: * 204 (OK) * 404 (object not found in db) """ d_e = self.get_object_or_404(self.single, obj_id) self.single.delete(d_e) raise self.http(204) class ChangesWhitelistRuleHandler(SingleHandler): single = ChangesWhitelistRule validator = ChangesWhitelistRuleValidator class ChangesWhitelistRuleCollectionHandler(CollectionHandler): collection = ChangesWhitelistRuleCollection validator = ChangesWhitelistRuleValidator @handle_errors @validate @serialize def GET(self, env_id): """:returns: JSONized REST object. :http: * 200 (OK) * 404 (dashboard entry not found in db) """ env_id = int(env_id) self.get_object_or_404(objects.Cluster, env_id) rules = self.collection.get_by_env_id(env_id) if rules: rules = self.collection.to_list(rules) return rules @handle_errors @serialize def POST(self, env_id): """:returns: JSONized REST object. :http: * 201 (object successfully created) * 400 (invalid object data specified) * 409 (object with such parameters already exists) """ env_id = int(env_id) data = self.checked_data( validate_method=self.validator.validate_one_or_multiple ) for item in data: item['env_id'] = env_id rules = self.collection.get_by_env_id(env_id) existing_rules = [] if rules: rules = self.collection.to_list(rules) existing_rules = filter( lambda i: len(filter(lambda o: i['fuel_task'] == o['fuel_task'] and i['rule'] == o['rule'], rules)) > 0, data ) if existing_rules: raise self.http(409, existing_rules) new_objs = [] try: for item in data: new_objs.append(self.collection.create(item)) except errors.CannotCreate as exc: raise self.http(400, exc.message) raise self.http(201, self.collection.to_json(new_objs))