class ExecutionStepsView(generic.CRUDView): NAME = "execution_step" MODEL_NAME = "execution_step" decorators = [ auth.require_authorization("api", "view_execution"), auth.require_authorization("api", "view_execution_steps"), auth.require_authentication ] @classmethod def register_to(cls, application): main_endpoint = generic.make_endpoint( ExecutionView.ENDPOINT, "<{0}:item_id>".format(ExecutionView.PARAMETER_TYPE), "steps" ) application.add_url_rule( main_endpoint, view_func=cls.as_view(cls.NAME), methods=["GET"] ) @validators.with_model(execution.ExecutionModel) def get(self, item_id, item): return execution_step.ExecutionStep.list_models( str(item_id), self.pagination )
class ExecutionStepsLog(generic.View): NAME = "execution_step_log" decorators = [ auth.require_authorization("api", "view_execution"), auth.require_authorization("api", "view_execution_steps"), auth.require_authentication ] @classmethod def register_to(cls, application): main_endpoint = generic.make_endpoint( ExecutionView.ENDPOINT, "<{0}:item_id>".format(ExecutionView.PARAMETER_TYPE), "log" ) application.add_url_rule( main_endpoint, view_func=cls.as_view(cls.NAME), methods=["GET"] ) @validators.with_model(execution.ExecutionModel) def get(self, item_id, item): logfile = item.logfile if not logfile: raise http_exceptions.NotFound() download = self.request_query.get("download", "no") try: download = distutils.util.strtobool(download) except Exception: download = False request_json = False for header in "Accept", "Content-Type": header = self.request_headers.get(header) or "" if header == "application/json": request_json = True break if not download and request_json: def generator(): fileobj = codecs.getreader("utf-8")(logfile, errors="ignore") result = fileobj.read(1024) while result: yield result result = fileobj.read(1024) return {"data": "".join(generator())} response = generic.fs_response(logfile, download, cache_for=LOG_CACHE_TIMEOUT) response = response.make_conditional(flask.request.environ) return response
def require_create_server_authorization(func): """Special authorization decorator for server create.""" normal_decorated_func = auth.require_authorization("api", "create_server") normal_decorated_func = normal_decorated_func(func) normal_decorated_func = auth.require_authentication(normal_decorated_func) @functools.wraps(func) def decorator(*args, **kwargs): token_id = flask.request.headers.get("Authorization") if token_id == CONF["api"]["server_discovery_token"]: return func(*args, **kwargs) return normal_decorated_func(*args, **kwargs) return decorator
class PermissionView(generic.ModelView): decorators = [ auth.require_authorization("api", "view_role"), auth.require_authentication ] NAME = "permission" ENDPOINT = "/permission/" def get(self): known_permissions = [{ "name": key, "permissions": sorted(value) } for key, value in role.PermissionSet.KNOWN_PERMISSIONS.items()] return {"items": known_permissions}
class PlaybookConfigurationView(generic.VersionedCRUDView): """Implementation of view for /v1/playbook_configuration API.""" decorators = [ auth.require_authorization("api", "view_playbook_configuration"), auth.require_authentication ] NAME = "playbook_configuration" MODEL_NAME = "playbook_configuration" ENDPOINT = "/playbook_configuration/" PARAMETER_TYPE = "uuid" def get_all(self): return playbook_configuration.PlaybookConfigurationModel.list_models( self.pagination ) @validators.with_model(playbook_configuration.PlaybookConfigurationModel) def get_item(self, item_id, item, *args): return item @auth.require_authorization("api", "view_playbook_configuration_version") def get_versions(self, item_id): return playbook_configuration.PlaybookConfigurationModel.list_versions( str(item_id), self.pagination ) @auth.require_authorization("api", "view_playbook_configuration_version") def get_version(self, item_id, version): model = playbook_configuration.PlaybookConfigurationModel.find_version( str(item_id), int(version) ) if not model: LOG.info("Cannot find model with ID %s", item_id) raise http_exceptions.NotFound return model @auth.require_authorization("api", "edit_playbook_configuration") @validators.with_model(playbook_configuration.PlaybookConfigurationModel) @validators.require_schema(MODEL_SCHEMA) @validators.no_updates_on_default_fields def put(self, item_id, item): for fieldname in "configuration", "name": if fieldname in self.request_json["data"]: setattr(item, fieldname, self.request_json["data"][fieldname]) item.initiator_id = self.initiator_id try: item.save() except base_exceptions.CannotUpdateDeletedModel as exc: LOG.warning( "Cannot update playbook configuration %s (deleted at %s, " "version %s)", item_id, item.time_deleted, item.version ) raise http_exceptions.CannotUpdateDeletedModel() from exc except base_exceptions.UniqueConstraintViolationError as exc: LOG.warning("Cannot update playbook configuration %s " "(unique constraint violation)", self.request_json["data"]["name"]) raise http_exceptions.CannotUpdateModelWithSuchParameters() \ from exc LOG.info("Playbook configuration %s was updated by %s", item_id, self.initiator_id) return item @auth.require_authorization("api", "create_playbook_configuration") @validators.require_schema(POST_SCHEMA) def post(self): cluster_model = self.get_cluster_model(self.request_json["cluster_id"]) servers_for_playbook = self.get_servers_for_playbook( self.request_json["playbook_id"], self.request_json["server_ids"], cluster_model ) try: pcmodel = playbook_configuration.PlaybookConfigurationModel.create( name=self.request_json["name"], playbook_id=self.request_json["playbook_id"], cluster=cluster_model, servers=servers_for_playbook, initiator_id=self.initiator_id ) except base_exceptions.UniqueConstraintViolationError as exc: LOG.warning( "Cannot create cluster %s (unique constraint " "violation)", self.request_json["name"] ) raise http_exceptions.ImpossibleToCreateSuchModel() from exc LOG.info("Playbook configuration %s (%s) created by %s", self.request_json["name"], pcmodel.model_id, self.initiator_id) return pcmodel @auth.require_authorization("api", "delete_playbook_confuiguration") @validators.with_model(playbook_configuration.PlaybookConfigurationModel) def delete(self, item_id, item): try: item.delete() except base_exceptions.CannotUpdateDeletedModel as exc: LOG.warning("Cannot delete deleted role %s", item_id) raise http_exceptions.CannotUpdateDeletedModel() from exc LOG.info("Playbook configuration %s was deleted by %s", item_id, self.initiator_id) return item def get_servers_for_playbook(self, playbook_id, suggested_servers, cluster_model): plugs = plugins.get_public_playbook_plugins() if playbook_id not in plugs: raise http_exceptions.UnknownPlaybookError(playbook_id) plug = plugs[playbook_id]() if plug.REQUIRED_SERVER_LIST: if not suggested_servers: raise http_exceptions.ServerListIsRequiredForPlaybookError( playbook_id ) servers = server.ServerModel.find_by_model_id(*suggested_servers) if not isinstance(servers, list): servers = [servers] if len(servers) != len(set(suggested_servers)): raise ValueError( "All suggested servers were not found. " "Suggested servers were {0}".format(suggested_servers)) deleted_servers = [srv for srv in servers if srv.time_deleted] if deleted_servers: raise ValueError( "Some servers were deleted: {0}".format( ", ".join(srv.model_id for srv in deleted_servers))) return servers return cluster_model.server_list def get_cluster_model(self, cluster_id): cluster_model = cluster.ClusterModel.find_by_model_id(cluster_id) if not (cluster_model and not cluster_model.time_deleted): raise http_exceptions.UnknownClusterError(cluster_id) return cluster_model
class ExecutionView(generic.VersionedCRUDView): """Implementation of view for /v1/execution API.""" decorators = [ auth.require_authorization("api", "view_execution"), auth.require_authentication ] NAME = "execution" MODEL_NAME = "execution" ENDPOINT = "/execution/" PARAMETER_TYPE = "uuid" def get_all(self): return execution.ExecutionModel.list_models(self.pagination) @validators.with_model(execution.ExecutionModel) def get_item(self, item_id, item, *args): return item @auth.require_authorization("api", "view_execution_version") def get_versions(self, item_id): return execution.ExecutionModel.list_versions( str(item_id), self.pagination ) def get_version(self, item_id, version): model = execution.ExecutionModel.find_version( str(item_id), int(version) ) if not model: LOG.info("Cannot find model with ID %s", item_id) raise http_exceptions.NotFound return model @auth.require_authorization("api", "create_execution") @validators.require_schema(POST_SCHEMA) def post(self): pc_id = self.request_json["playbook_configuration"]["id"] pc_version = self.request_json["playbook_configuration"]["version"] config = playbook_configuration.PlaybookConfigurationModel config = config.find_version(pc_id, pc_version) if not config: LOG.warning( "Cannot find playbook configuration %s of version %s", pc_id, pc_version ) raise http_exceptions.UnknownPlaybookConfiguration( pc_id, pc_version ) auth.check_auth_permission(flask.g.token.user, "playbook", config.playbook_id) model = execution.ExecutionModel.create(config, self.initiator_id) LOG.info( "Created execution %s for playbook configuration %s of " "version %s", model.model_id, config.model_id, config.version ) try: tsk = task.PlaybookPluginTask( config.playbook_id, config._id, model.model_id ) tsk.create() except Exception as exc: LOG.error("Cannot create task for execution %s: %s", model.model_id, exc) model.state = execution.ExecutionState.failed model.save() raise else: LOG.info("Created task for execution %s: %s", model.model_id, tsk._id) return model @auth.require_authorization("api", "delete_execution") @validators.with_model(execution.ExecutionModel) def delete(self, item_id, item): if item.state == execution.ExecutionState.created: try: return self.cancel_created_execution(item) except base_exceptions.UniqueConstraintViolationError: LOG.debug("Execution %s already changed it's state") item = execution.ExecutionModel.find_by_model_id(item_id) if item.state == execution.ExecutionState.started: item = self.cancel_started_execution(item) return item def cancel_created_execution(self, item): item.initiator_id = self.initiator_id item.state = execution.ExecutionState.canceled item.save() LOG.info("Not started execution %s was canceled", item.model_id) return item def cancel_started_execution(self, item): item.initiator_id = self.initiator_id item.state = execution.ExecutionState.canceling item.save() LOG.info("Execution %s is cancelling now", item.model_id) tsk = task.CancelPlaybookPluginTask(item.model_id) tsk.create() LOG.info("Task for cancelling execution %s is %s", item.model_id, tsk._id) return item
class RoleView(generic.VersionedCRUDView): """Implementation of view for /v1/role API.""" decorators = [ auth.require_authorization("api", "view_role"), auth.require_authentication ] NAME = "role" MODEL_NAME = "role" ENDPOINT = "/role/" PARAMETER_TYPE = "uuid" def get_all(self): return role.RoleModel.list_models(self.pagination) @validators.with_model(role.RoleModel) def get_item(self, item_id, item, *args): return item @auth.require_authorization("api", "view_role_versions") def get_versions(self, item_id): return role.RoleModel.list_versions(str(item_id), self.pagination) @auth.require_authorization("api", "view_role_versions") def get_version(self, item_id, version): model = role.RoleModel.find_version(str(item_id), int(version)) if not model: LOG.info("Cannot find model with ID %s", item_id) raise http_exceptions.NotFound return model @auth.require_authorization("api", "edit_role") @validators.with_model(role.RoleModel) @validators.require_schema(MODEL_SCHEMA) @validators.no_updates_on_default_fields def put(self, item_id, item): try: for key, value in self.request_json["data"].items(): setattr(item, key, value) item.initiator_id = self.initiator_id item.save() except base_exceptions.CannotUpdateDeletedModel as exc: LOG.warning( "Cannot update deleted role %s (deleted at %s, " "version %s)", item_id, item.time_deleted, item.version ) raise http_exceptions.CannotUpdateDeletedModel() from exc except base_exceptions.UniqueConstraintViolationError as exc: LOG.warning("Cannot update role %s (unique constraint " "violation)", self.request_json["data"]["name"]) raise http_exceptions.CannotUpdateModelWithSuchParameters() \ from exc except ValueError as exc: LOG.warning("Incorrect permissions for role %s: %s", item_id, exc) raise http_exceptions.BadRequest from exc LOG.info("Role %s was updated by %s", item_id, self.initiator_id) return item @auth.require_authorization("api", "create_role") @validators.require_schema(POST_SCHEMA) def post(self): try: role_model = role.RoleModel.make_role( self.request_json["name"], self.request_json["permissions"], initiator_id=self.initiator_id ) except base_exceptions.UniqueConstraintViolationError as exc: LOG.warning("Cannot create role %s (unique constraint violation)", self.request_json["name"]) raise http_exceptions.ImpossibleToCreateSuchModel() from exc except base_exceptions.UniqueConstraintViolationError as exc: raise http_exceptions.UniqueConstraintViolationError() from exc except ValueError as exc: LOG.warning("Incorrect permissions for role %s: %s", self.request_json["name"], exc) raise http_exceptions.BadRequest from exc LOG.info("Role %s (%s) created by %s", self.request_json["name"], role_model.model_id, self.initiator_id) return role_model @auth.require_authorization("api", "delete_role") @validators.with_model(role.RoleModel) def delete(self, item_id, item): try: item.delete() except base_exceptions.CannotUpdateDeletedModel as exc: LOG.warning("Cannot delete deleted role %s", item_id) raise http_exceptions.CannotUpdateDeletedModel() from exc except base_exceptions.CannotDeleteRoleWithActiveUsers as exc: LOG.warning("Cannot delete role %s with active users", item_id) raise http_exceptions.CannotDeleteRoleWithActiveUsers() from exc LOG.info("Role %s was deleted by %s", item_id, self.initiator_id) return item
class UserView(generic.VersionedCRUDView): """Implementation of view for /v1/user/.""" decorators = [ auth.require_authorization("api", "view_user"), auth.require_authentication ] NAME = "user" MODEL_NAME = "user" ENDPOINT = "/user/" PARAMETER_TYPE = "uuid" def get_all(self): return user.UserModel.list_models(self.pagination) @validators.with_model(user.UserModel) def get_item(self, item_id, item, *args): return item @auth.require_authorization("api", "view_user_versions") def get_versions(self, item_id): return user.UserModel.list_versions(str(item_id), self.pagination) @auth.require_authorization("api", "view_user_versions") def get_version(self, item_id, version): model = user.UserModel.find_version(str(item_id), int(version)) if not model: LOG.warning("Cannot find version %s of user model %s", version, item_id) raise http_exceptions.NotFound return model @auth.require_authorization("api", "edit_user") @validators.with_model(user.UserModel) @validators.require_schema(MODEL_SCHEMA) @validators.no_updates_on_default_fields def put(self, item_id, item): for key, value in self.request_json["data"].items(): setattr(item, key, value) item.initiator_id = self.initiator_id try: item.save() except base_exceptions.CannotUpdateDeletedModel as exc: LOG.warning( "Cannot update deleted model %s (deleted at %s, " "version %s)", item.model_id, item.time_deleted, item.version) raise http_exceptions.CannotUpdateDeletedModel() from exc except base_exceptions.UniqueConstraintViolationError as exc: LOG.warning( "Cannot update user %s (unique constraint " "violation)", self.request_json["data"]["login"]) raise http_exceptions.CannotUpdateModelWithSuchParameters() \ from exc LOG.info("User model %s was updated to version %s by %s", item.model_id, item.version, self.initiator_id) return item @auth.require_authorization("api", "create_user") @validators.require_schema(POST_SCHEMA) def post(self): new_password = passwords.generate_password() try: user_model = user.UserModel.make_user( self.request_json["login"], new_password, self.request_json["email"], self.request_json["full_name"], self.request_json["role_id"], initiator_id=self.initiator_id) except base_exceptions.UniqueConstraintViolationError as exc: LOG.warning( "Cannot create new user %s: violation of unique constraint", self.request_json["login"]) raise http_exceptions.ImpossibleToCreateSuchModel() from exc LOG.info("User %s was created by %s", user_model.model_id, self.initiator_id) notify_about_new_password(user_model, new_password) return user_model @auth.require_authorization("api", "delete_user") @validators.with_model(user.UserModel) def delete(self, item_id, item): try: item.delete() except base_exceptions.CannotUpdateDeletedModel as exc: LOG.warning("Cannot delete deleted user %s", item_id) raise http_exceptions.CannotUpdateDeletedModel() from exc LOG.info("User %s was deleted by %s", item_id, self.initiator_id) return item
class ClusterView(generic.VersionedCRUDView): """Implementation of view for /v1/cluster API.""" decorators = [ auth.require_authorization("api", "view_cluster"), auth.require_authentication ] NAME = "cluster" MODEL_NAME = "cluster" ENDPOINT = "/cluster/" PARAMETER_TYPE = "uuid" def get_all(self): return cluster.ClusterModel.list_models(self.pagination) @validators.with_model(cluster.ClusterModel) def get_item(self, item_id, item, *args): return item @auth.require_authorization("api", "view_cluster_versions") def get_versions(self, item_id): return cluster.ClusterModel.list_versions(str(item_id), self.pagination) @auth.require_authorization("api", "view_cluster_versions") def get_version(self, item_id, version): model = cluster.ClusterModel.find_version(str(item_id), int(version)) if not model: LOG.info("Cannot find model with ID %s", item_id) raise http_exceptions.NotFound return model @auth.require_authorization("api", "edit_cluster") @validators.with_model(cluster.ClusterModel) @validators.require_schema(MODEL_SCHEMA) @validators.no_updates_on_default_fields def put(self, item_id, item): if "name" in self.request_json["data"]: item.name = self.request_json["data"]["name"] item.initiator_id = self.initiator_id try: item.save() except base_exceptions.CannotUpdateDeletedModel as exc: LOG.warning( "Cannot update cluster %s (deleted at %s, " "version %s)", item_id, item.time_deleted, item.version) raise http_exceptions.CannotUpdateDeletedModel() from exc except base_exceptions.UniqueConstraintViolationError as exc: LOG.warning( "Cannot update cluster %s (unique constraint " "violation)", self.request_json["data"]["name"]) raise http_exceptions.CannotUpdateModelWithSuchParameters() \ from exc LOG.info("Cluster %s was updated by %s", item_id, self.initiator_id) return item @auth.require_authorization("api", "create_cluster") @validators.require_schema(POST_SCHEMA) def post(self): try: cluster_model = cluster.ClusterModel.create( self.request_json["name"], initiator_id=self.initiator_id) except base_exceptions.UniqueConstraintViolationError as exc: LOG.warning( "Cannot create cluster %s (unique constraint " "violation)", self.request_json["name"]) raise http_exceptions.ImpossibleToCreateSuchModel() from exc LOG.info("Cluster %s (%s) created by %s", self.request_json["name"], cluster_model.model_id, self.initiator_id) return cluster_model @auth.require_authorization("api", "delete_cluster") @validators.with_model(cluster.ClusterModel) def delete(self, item_id, item): try: item.delete() except base_exceptions.CannotUpdateDeletedModel as exc: LOG.warning("Cannot delete deleted role %s", item_id) raise http_exceptions.CannotUpdateDeletedModel() from exc except base_exceptions.CannotDeleteClusterWithServers as exc: raise http_exceptions.CannotDeleteClusterWithServers from exc LOG.info("Cluster %s was deleted by %s", item_id, self.initiator_id) return item