From 7e83d0876ddb84a45e130eeba28bc40ef53c074b Mon Sep 17 00:00:00 2001 From: Yaron Yogev Date: Thu, 27 Jul 2017 09:02:54 +0300 Subject: Calipso initial release for OPNFV Change-Id: I7210c244b0c10fa80bfa8c77cb86c9d6ddf8bc88 Signed-off-by: Yaron Yogev --- app/api/responders/resource/environment_configs.py | 381 +++++++++++++++++++++ 1 file changed, 381 insertions(+) create mode 100644 app/api/responders/resource/environment_configs.py (limited to 'app/api/responders/resource/environment_configs.py') diff --git a/app/api/responders/resource/environment_configs.py b/app/api/responders/resource/environment_configs.py new file mode 100644 index 0000000..bee6a4d --- /dev/null +++ b/app/api/responders/resource/environment_configs.py @@ -0,0 +1,381 @@ +############################################################################### +# Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) # +# and others # +# # +# All rights reserved. This program and the accompanying materials # +# are made available under the terms of the Apache License, Version 2.0 # +# which accompanies this distribution, and is available at # +# http://www.apache.org/licenses/LICENSE-2.0 # +############################################################################### +from api.validation import regex +from api.validation.data_validate import DataValidate +from api.responders.responder_base import ResponderBase +from bson.objectid import ObjectId +from datetime import datetime +from utils.constants import EnvironmentFeatures +from utils.inventory_mgr import InventoryMgr + + +class EnvironmentConfigs(ResponderBase): + def __init__(self): + super(EnvironmentConfigs, self).__init__() + self.inv = InventoryMgr() + self.ID = "name" + self.PROJECTION = { + self.ID: True, + "_id": False, + "name": True, + "distribution": True + } + self.COLLECTION = "environments_config" + self.CONFIGURATIONS_NAMES = ["mysql", "OpenStack", + "CLI", "AMQP", "Monitoring", + "NFV_provider", "ACI"] + self.OPTIONAL_CONFIGURATIONS_NAMES = ["AMQP", "Monitoring", + "NFV_provider", "ACI"] + + self.provision_types = self.\ + get_constants_by_name("environment_provision_types") + self.env_types = self.get_constants_by_name("env_types") + self.monitoring_types = self.\ + get_constants_by_name("environment_monitoring_types") + self.distributions = self.\ + get_constants_by_name("distributions") + self.mechanism_drivers = self.\ + get_constants_by_name("mechanism_drivers") + self.operational_values = self.\ + get_constants_by_name("environment_operational_status") + self.type_drivers = self.\ + get_constants_by_name("type_drivers") + + self.CONFIGURATIONS_REQUIREMENTS = { + "mysql": { + "name": self.require(str, mandatory=True), + "host": self.require(str, + validate=DataValidate.REGEX, + requirement=[regex.IP, regex.HOSTNAME], + mandatory=True), + "password": self.require(str, mandatory=True), + "port": self.require(int, + True, + DataValidate.REGEX, + regex.PORT, + mandatory=True), + "user": self.require(str, mandatory=True) + }, + "OpenStack": { + "name": self.require(str, mandatory=True), + "admin_token": self.require(str, mandatory=True), + "host": self.require(str, + validate=DataValidate.REGEX, + requirement=[regex.IP, regex.HOSTNAME], + mandatory=True), + "port": self.require(int, + True, + validate=DataValidate.REGEX, + requirement=regex.PORT, + mandatory=True), + "pwd": self.require(str, mandatory=True), + "user": self.require(str, mandatory=True) + }, + "CLI": { + "name": self.require(str, mandatory=True), + "host": self.require(str, + validate=DataValidate.REGEX, + requirement=[regex.IP, regex.HOSTNAME], + mandatory=True), + "user": self.require(str, mandatory=True), + "pwd": self.require(str), + "key": self.require(str, + validate=DataValidate.REGEX, + requirement=regex.PATH) + }, + "AMQP": { + "name": self.require(str, mandatory=True), + "host": self.require(str, + validate=DataValidate.REGEX, + requirement=[regex.IP, regex.HOSTNAME], + mandatory=True), + "password": self.require(str, mandatory=True), + "port": self.require(int, + True, + validate=DataValidate.REGEX, + requirement=regex.PORT, + mandatory=True), + "user": self.require(str, mandatory=True) + }, + "Monitoring": { + "name": self.require(str, mandatory=True), + "config_folder": self.require(str, + validate=DataValidate.REGEX, + requirement=regex.PATH, + mandatory=True), + "provision": self.require(str, + validate=DataValidate.LIST, + requirement=self.provision_types, + mandatory=True), + "env_type": self.require(str, + validate=DataValidate.LIST, + requirement=self.env_types, + mandatory=True), + "api_port": self.require(int, True, mandatory=True), + "rabbitmq_pass": self.require(str, mandatory=True), + "rabbitmq_user": self.require(str, mandatory=True), + "rabbitmq_port": self.require(int, + True, + validate=DataValidate.REGEX, + requirement=regex.PORT, + mandatory=True), + "ssh_port": self.require(int, + True, + validate=DataValidate.REGEX, + requirement=regex.PORT), + "ssh_user": self.require(str), + "ssh_password": self.require(str), + "server_ip": self.require(str, + validate=DataValidate.REGEX, + requirement=[regex.IP, regex.HOSTNAME], + mandatory=True), + "server_name": self.require(str, mandatory=True), + "type": self.require(str, + validate=DataValidate.LIST, + requirement=self.monitoring_types, + mandatory=True) + }, + "NFV_provider": { + "name": self.require(str, mandatory=True), + "host": self.require(str, + validate=DataValidate.REGEX, + requirement=[regex.IP, regex.HOSTNAME], + mandatory=True), + "nfv_token": self.require(str, mandatory=True), + "port": self.require(int, + True, + DataValidate.REGEX, + regex.PORT, + True), + "user": self.require(str, mandatory=True), + "pwd": self.require(str, mandatory=True) + }, + "ACI": { + "name": self.require(str, mandatory=True), + "host": self.require(str, + validate=DataValidate.REGEX, + requirement=[regex.IP, regex.HOSTNAME], + mandatory=True), + "user": self.require(str, mandatory=True), + "pwd": self.require(str, mandatory=True) + } + } + self.AUTH_REQUIREMENTS = { + "view-env": self.require(list, mandatory=True), + "edit-env": self.require(list, mandatory=True) + } + + def on_get(self, req, resp): + self.log.debug("Getting environment config") + filters = self.parse_query_params(req) + + filters_requirements = { + "name": self.require(str), + "distribution": self.require(str, False, + DataValidate.LIST, + self.distributions), + "mechanism_drivers": self.require([str, list], + False, + DataValidate.LIST, + self.mechanism_drivers), + "type_drivers": self.require(str, False, + DataValidate.LIST, + self.type_drivers), + "user": self.require(str), + "listen": self.require(bool, True), + "scanned": self.require(bool, True), + "monitoring_setup_done": self.require(bool, True), + "operational": self.require(str, False, + DataValidate.LIST, + self.operational_values), + "page": self.require(int, True), + "page_size": self.require(int, True) + } + + self.validate_query_data(filters, filters_requirements) + page, page_size = self.get_pagination(filters) + + query = self.build_query(filters) + + if self.ID in query: + environment_config = self.get_object_by_id(self.COLLECTION, query, + [ObjectId, datetime], self.ID) + self.set_successful_response(resp, environment_config) + else: + objects_ids = self.get_objects_list(self.COLLECTION, query, + page, page_size, self.PROJECTION) + self.set_successful_response(resp, {'environment_configs': objects_ids}) + + def build_query(self, filters): + query = {} + filters_keys = ["name", "distribution", "type_drivers", "user", + "listen", "monitoring_setup_done", "scanned", + "operational"] + self.update_query_with_filters(filters, filters_keys, query) + mechanism_drivers = filters.get("mechanism_drivers") + if mechanism_drivers: + if type(mechanism_drivers) != list: + mechanism_drivers = [mechanism_drivers] + query['mechanism_drivers'] = {'$all': mechanism_drivers} + + return query + + def on_post(self, req, resp): + self.log.debug("Creating a new environment config") + + error, env_config = self.get_content_from_request(req) + if error: + self.bad_request(error) + + environment_config_requirement = { + "app_path": self.require(str, mandatory=True), + "configuration": self.require(list, mandatory=True), + "distribution": self.require(str, False, DataValidate.LIST, + self.distributions, True), + "listen": self.require(bool, True, mandatory=True), + "user": self.require(str), + "mechanism_drivers": self.require(list, False, DataValidate.LIST, + self.mechanism_drivers, True), + "name": self.require(str, mandatory=True), + "operational": self.require(str, True, DataValidate.LIST, + self.operational_values, mandatory=True), + "scanned": self.require(bool, True), + "last_scanned": self.require(str), + "type": self.require(str, mandatory=True), + "type_drivers": self.require(str, False, DataValidate.LIST, + self.type_drivers, True), + "enable_monitoring": self.require(bool, True), + "monitoring_setup_done": self.require(bool, True), + "auth": self.require(dict) + } + self.validate_query_data(env_config, + environment_config_requirement, + can_be_empty_keys=["last_scanned"] + ) + self.check_and_convert_datetime("last_scanned", env_config) + # validate the configurations + configurations = env_config['configuration'] + config_validation = self.validate_environment_config(configurations) + + if not config_validation['passed']: + self.bad_request(config_validation['error_message']) + + err_msg = self.validate_env_config_with_supported_envs(env_config) + if err_msg: + self.bad_request(err_msg) + + err_msg = self.validate_env_config_with_constraints(env_config) + if err_msg: + self.bad_request(err_msg) + + if "auth" in env_config: + err_msg = self.validate_data(env_config.get("auth"), + self.AUTH_REQUIREMENTS) + if err_msg: + self.bad_request("auth error: " + err_msg) + + if "scanned" not in env_config: + env_config["scanned"] = False + + self.write(env_config, self.COLLECTION) + self.set_successful_response(resp, + {"message": "created environment_config " + "for {0}" + .format(env_config["name"])}, + "201") + + def validate_environment_config(self, configurations): + configurations_of_names = {} + validation = {"passed": True} + if [config for config in configurations + if 'name' not in config]: + validation['passed'] = False + validation['error_message'] = "configuration must have name" + return validation + + unknown_configs = [config['name'] for config in configurations + if config['name'] not in self.CONFIGURATIONS_NAMES] + if unknown_configs: + validation['passed'] = False + validation['error_message'] = 'Unknown configurations: {0}'. \ + format(' and '.join(unknown_configs)) + return validation + + for name in self.CONFIGURATIONS_NAMES: + configs = self.get_configuration_by_name(name, configurations) + if configs: + if len(configs) > 1: + validation["passed"] = False + validation["error_message"] = "environment configurations can " \ + "only contain one " \ + "configuration for {0}".format(name) + return validation + configurations_of_names[name] = configs[0] + else: + if name not in self.OPTIONAL_CONFIGURATIONS_NAMES: + validation["passed"] = False + validation['error_message'] = "configuration for {0} " \ + "is mandatory".format(name) + return validation + + for name, config in configurations_of_names.items(): + error_message = self.validate_configuration(name, config) + if error_message: + validation['passed'] = False + validation['error_message'] = "{0} error: {1}".\ + format(name, error_message) + break + if name is 'CLI': + if 'key' not in config and 'pwd' not in config: + validation['passed'] = False + validation['error_message'] = 'CLI error: either key ' \ + 'or pwd must be provided' + return validation + + def validate_env_config_with_supported_envs(self, env_config): + # validate the environment config with supported environments + matches = { + 'environment.distribution': env_config['distribution'], + 'environment.type_drivers': env_config['type_drivers'], + 'environment.mechanism_drivers': {'$in': env_config['mechanism_drivers']} + } + + err_prefix = 'configuration not accepted: ' + if not self.inv.is_feature_supported_in_env(matches, + EnvironmentFeatures.SCANNING): + return err_prefix + 'scanning is not supported in this environment' + + configs = env_config['configuration'] + if not self.inv.is_feature_supported_in_env(matches, + EnvironmentFeatures.MONITORING) \ + and self.get_configuration_by_name('Monitoring', configs): + return err_prefix + 'monitoring is not supported in this environment, ' \ + 'please remove the Monitoring configuration' + + if not self.inv.is_feature_supported_in_env(matches, + EnvironmentFeatures.LISTENING) \ + and self.get_configuration_by_name('AMQP', configs): + return err_prefix + 'listening is not supported in this environment, ' \ + 'please remove the AMQP configuration' + + return None + + def validate_env_config_with_constraints(self, env_config): + if env_config['listen'] and \ + not self.get_configuration_by_name('AMQP', env_config['configuration']): + return 'configuration not accepted: ' \ + 'must provide AMQP configuration to listen the environment' + + def get_configuration_by_name(self, name, configurations): + return [config for config in configurations if config['name'] == name] + + def validate_configuration(self, name, configuration): + return self.validate_data(configuration, + self.CONFIGURATIONS_REQUIREMENTS[name]) -- cgit 1.2.3-korg