murano-dashboard/muranodashboard/panel/services/__init__.py

192 lines
6.6 KiB
Python

# Copyright (c) 2013 Mirantis, Inc.
#
# 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.
import os
import re
import time
import logging
from django.conf import settings
try:
from collections import OrderedDict
except ImportError: # python2.6
from ordereddict import OrderedDict
import yaml
from yaml.scanner import ScannerError
from django.utils.translation import ugettext_lazy as _
import copy
log = logging.getLogger(__name__)
_all_services = OrderedDict()
class Service(object):
def __init__(self, modified_on, **kwargs):
import muranodashboard.panel.services.forms as services
for key, value in kwargs.iteritems():
if key == 'forms':
self.forms = []
for form_data in value:
form_name, form_data = self.extract_form_data(form_data)
self.forms.append(
type(form_name, (services.ServiceConfigurationForm,),
{'service': self,
'fields_template': form_data['fields'],
'validators': form_data.get('validators', [])}))
else:
setattr(self, key, value)
self.modified_on = modified_on
self.cleaned_data = {}
@staticmethod
def extract_form_data(form_data):
form_name = form_data.keys()[0]
return form_name, form_data[form_name]
def update_cleaned_data(self, form, data):
if data:
# match = re.match('^.*-(\d)+$', form.prefix)
# index = int(match.group(1)) if match else None
# if index is not None:
# self.cleaned_data[index] = data
self.cleaned_data[form.__class__.__name__] = data
return self.cleaned_data
def import_all_services():
from muranodashboard.panel.services.helpers import decamelize
directory = getattr(settings, 'MURANO_SERVICES_DESC_PATH', None)
if directory is None:
directory = os.path.join(os.path.dirname(__file__), '../../services/')
file_list = [f for f in os.listdir(directory) if f.endswith('.yaml')]
log.debug("Removing non-existing service definitions from cache")
# TODO: this has O(n^2) complexity, should fix it if there are many defs
for filename in _all_services.keys():
try:
file_list.index(filename)
except ValueError:
del _all_services[filename]
log.info("Removed service '{0}' from cache".format(filename))
log.debug("Updating service definitions cache from '{0}'".format(
directory))
for filename in file_list:
service_file = os.path.join(directory, filename)
modified_on = os.path.getmtime(service_file)
if filename in _all_services:
if _all_services[filename].modified_on >= modified_on:
continue
try:
with open(service_file) as stream:
yaml_desc = yaml.load(stream)
except (OSError, ScannerError) as e:
log.warn("Failed to import service definition from {0},"
" reason: {1!s}".format(service_file, e))
continue
service = dict((decamelize(k), v) for (k, v) in yaml_desc.iteritems())
_all_services[filename] = Service(modified_on, **service)
log.info("Added service '{0}' from '{1}', modified on {2}".format(
_all_services[filename].name, service_file,
time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(modified_on))))
def iterate_over_services():
import_all_services()
for service in sorted(_all_services.values(), key=lambda v: v.name):
yield service.type, service, service.forms
def make_forms_getter(initial_forms=[]):
def _get_forms():
_forms = copy.copy(initial_forms)
for srv_type, service, forms in iterate_over_services():
for step, form in enumerate(forms):
_forms.append(('{0}-{1}'.format(srv_type, step), form))
return _forms
return _get_forms
def service_type_from_id(service_id):
match = re.match('(.*)-[0-9]+', service_id)
if match:
return match.group(1)
else: # if no number suffix found, it was service_type itself passed in
return service_id
def with_service(service_id, getter, default):
import_all_services()
service_type = service_type_from_id(service_id)
for srv_type, service, forms in iterate_over_services():
if srv_type == service_type:
return getter(service)
return default
def get_service_name(service_id):
return with_service(service_id, lambda service: service.name, '')
def get_service_field_descriptions(service_id, index):
def get_descriptions(service):
Form = service.forms[index]
descriptions = []
for field in Form.fields_template:
if 'description' in field:
title = field.get('descriptionTitle', field.get('label', ''))
descriptions.append((title, field['description']))
return descriptions
return with_service(service_id, get_descriptions, [])
def get_service_type(wizard):
cleaned_data = wizard.get_cleaned_data_for_step('service_choice') \
or {'service': 'none'}
return cleaned_data.get('service')
def get_service_choices():
return [(srv_type, service.name) for srv_type, service, forms in
iterate_over_services()]
get_forms = make_forms_getter()
def get_service_checkers():
import_all_services()
def make_comparator(srv_id):
def compare(wizard):
return service_type_from_id(srv_id) == get_service_type(wizard)
return compare
return [(srv_id, make_comparator(srv_id)) for srv_id, form
in get_forms()]
def get_service_descriptions():
descriptions = []
for srv_type, service, forms in iterate_over_services():
description = getattr(service, 'description', _("<b>Default service \
description</b>. If you want to see here something meaningful, please \
provide `description' field in service markup."))
descriptions.append((srv_type, description))
return descriptions