
Previously the dropdown choice selection of possible network interfaces was limiting. We are now using a free text field to remove this limitation. Change-Id: I1eb1e495282e7fa520c8225ba16fa61a32b3d24d Closes-bug: bz/1252553
282 lines
10 KiB
Python
282 lines
10 KiB
Python
# -*- coding: utf8 -*-
|
|
#
|
|
# 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 json
|
|
import logging
|
|
|
|
import django.forms
|
|
from django.utils.datastructures import SortedDict
|
|
from django.utils.translation import ugettext_lazy as _
|
|
import horizon.exceptions
|
|
import horizon.forms
|
|
import horizon.messages
|
|
|
|
from tuskar_ui import api
|
|
import tuskar_ui.forms
|
|
from tuskar_ui.utils import utils
|
|
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
|
|
VIRT_TYPE_CHOICES = [
|
|
('qemu', _("Virtualized (qemu)")),
|
|
('kvm', _("Baremetal (kvm)")),
|
|
]
|
|
|
|
CINDER_ISCSI_HELPER_CHOICES = [
|
|
('tgtadm', _('tgtadm')),
|
|
('lioadm', _('lioadm')),
|
|
]
|
|
|
|
|
|
class ParameterAwareMixin(object):
|
|
parameter = None
|
|
|
|
|
|
def parameter_fields(request, prefix=None, read_only=False):
|
|
fields = SortedDict()
|
|
plan = api.tuskar.Plan.get_the_plan(request)
|
|
parameters = plan.parameter_list(include_key_parameters=False)
|
|
|
|
for p in parameters:
|
|
if prefix and not p.name.startswith(prefix):
|
|
continue
|
|
Field = django.forms.CharField
|
|
field_kwargs = {}
|
|
widget = None
|
|
if read_only:
|
|
if p.hidden:
|
|
widget = tuskar_ui.forms.StaticTextPasswordWidget
|
|
else:
|
|
widget = tuskar_ui.forms.StaticTextWidget
|
|
else:
|
|
if p.hidden:
|
|
widget = django.forms.PasswordInput(render_value=True)
|
|
elif p.parameter_type == 'number':
|
|
Field = django.forms.IntegerField
|
|
elif p.parameter_type == 'boolean':
|
|
Field = django.forms.BooleanField
|
|
elif (p.parameter_type == 'string' and
|
|
p.get_constraint_by_type('allowed_values')):
|
|
Field = django.forms.ChoiceField
|
|
field_kwargs['choices'] = [
|
|
(choice, choice) for choice in
|
|
p.get_constraint_by_type('allowed_values')['definition']]
|
|
elif (p.parameter_type in ['json', 'comma_delimited_list'] or
|
|
'Certificate' in p.name):
|
|
widget = django.forms.Textarea
|
|
|
|
fields[p.name] = Field(
|
|
required=False,
|
|
label=_parameter_label(p),
|
|
initial=p.value,
|
|
widget=widget,
|
|
**field_kwargs
|
|
)
|
|
fields[p.name].__class__ = type('ParameterAwareField',
|
|
(ParameterAwareMixin, Field), {})
|
|
fields[p.name].parameter = p
|
|
return fields
|
|
|
|
|
|
def _parameter_label(parameter):
|
|
return tuskar_ui.forms.label_with_tooltip(
|
|
parameter.label or utils.de_camel_case(parameter.stripped_name),
|
|
parameter.description)
|
|
|
|
|
|
class ServiceConfig(horizon.forms.SelfHandlingForm):
|
|
def __init__(self, *args, **kwargs):
|
|
super(ServiceConfig, self).__init__(*args, **kwargs)
|
|
self.fields.update(parameter_fields(self.request, read_only=True))
|
|
|
|
def global_fieldset(self):
|
|
return tuskar_ui.forms.fieldset(self, prefix='^(?!.*::)')
|
|
|
|
def controller_fieldset(self):
|
|
return tuskar_ui.forms.fieldset(self, prefix='Controller-1')
|
|
|
|
def compute_fieldset(self):
|
|
return tuskar_ui.forms.fieldset(self, prefix='Compute-1')
|
|
|
|
def block_storage_fieldset(self):
|
|
return tuskar_ui.forms.fieldset(self, prefix='Cinder-Storage-1')
|
|
|
|
def object_storage_fieldset(self):
|
|
return tuskar_ui.forms.fieldset(self, prefix='Swift-Storage-1')
|
|
|
|
def ceph_storage_fieldset(self):
|
|
return tuskar_ui.forms.fieldset(self, prefix='Ceph-Storage-1')
|
|
|
|
def handle():
|
|
pass
|
|
|
|
|
|
class AdvancedEditServiceConfig(ServiceConfig):
|
|
def __init__(self, *args, **kwargs):
|
|
super(AdvancedEditServiceConfig, self).__init__(*args, **kwargs)
|
|
self.fields.update(parameter_fields(self.request))
|
|
|
|
def handle(self, request, data):
|
|
plan = api.tuskar.Plan.get_the_plan(self.request)
|
|
|
|
# TODO(bcrochet): Commenting this out.
|
|
# For advanced config, we should have a whitelist of which params
|
|
# must be synced across roles.
|
|
# data = self._sync_common_params_across_roles(plan, data)
|
|
|
|
try:
|
|
plan.patch(request, plan.uuid, data)
|
|
except Exception as e:
|
|
horizon.exceptions.handle(
|
|
request,
|
|
_("Unable to update the service configuration."))
|
|
LOG.exception(e)
|
|
return False
|
|
else:
|
|
horizon.messages.success(
|
|
request,
|
|
_("Service configuration updated."))
|
|
return True
|
|
|
|
@staticmethod
|
|
def _sync_common_params_across_roles(plan, parameters_dict):
|
|
for (p_key, p_value) in parameters_dict.iteritems():
|
|
for role in plan.role_list:
|
|
role_parameter_key = (role.parameter_prefix +
|
|
api.tuskar.strip_prefix(p_key))
|
|
if role_parameter_key in parameters_dict:
|
|
parameters_dict[role_parameter_key] = p_value
|
|
return parameters_dict
|
|
|
|
|
|
class SimpleEditServiceConfig(horizon.forms.SelfHandlingForm):
|
|
virt_type = django.forms.ChoiceField(
|
|
label=_("Deployment Type"),
|
|
choices=VIRT_TYPE_CHOICES,
|
|
required=True,
|
|
help_text=_('If you are testing OpenStack in a virtual machine, '
|
|
'you must configure Compute to use qemu without KVM '
|
|
'and hardware virtualization.'))
|
|
neutron_public_interface = django.forms.CharField(
|
|
label=_("Public Interface"),
|
|
required=True,
|
|
initial='eth0',
|
|
help_text=_('What interface to bridge onto br-ex for network nodes. '
|
|
'If you are testing OpenStack in a virtual machine'
|
|
'you must configure interface to eth0.'))
|
|
snmp_password = django.forms.CharField(
|
|
label=_("SNMP Password"),
|
|
required=True,
|
|
help_text=_('The user password for SNMPd with readonly '
|
|
'rights running on all Overcloud nodes'),
|
|
widget=django.forms.PasswordInput(render_value=True))
|
|
cloud_name = django.forms.CharField(
|
|
label=_("Cloud name"),
|
|
required=True,
|
|
initial="overcloud",
|
|
help_text=_('The DNS name of this cloud. '
|
|
'E.g. ci-overcloud.tripleo.org'))
|
|
cinder_iscsi_helper = django.forms.ChoiceField(
|
|
label=_("Cinder ISCSI helper"),
|
|
choices=CINDER_ISCSI_HELPER_CHOICES,
|
|
required=True,
|
|
help_text=_('The iSCSI helper to use with cinder.'))
|
|
ntp_server = django.forms.CharField(
|
|
label=_("NTP server"),
|
|
required=False,
|
|
initial="",
|
|
help_text=_('Address of the NTP server. If blank, public NTP servers '
|
|
'will be used.'))
|
|
extra_config = django.forms.CharField(
|
|
label=_("Extra Config"),
|
|
required=False,
|
|
widget=django.forms.Textarea(attrs={'rows': 2}),
|
|
help_text=("Additional configuration to inject into the cluster."
|
|
"The data format of this field is JSON."
|
|
"See http://git.io/PuwLXQ for more information."))
|
|
|
|
def clean_extra_config(self):
|
|
data = self.cleaned_data['extra_config']
|
|
try:
|
|
json.loads(data)
|
|
except Exception as json_error:
|
|
raise django.forms.ValidationError(
|
|
_("%(err_msg)s"), params={'err_msg': json_error.message})
|
|
return data
|
|
|
|
@staticmethod
|
|
def _load_additional_parameters(plan, data, form_key, param_name):
|
|
params = {}
|
|
param_value = data.get(form_key)
|
|
# Set the same parameter and value in all roles.
|
|
for role in plan.role_list:
|
|
key = role.parameter_prefix + param_name
|
|
if key in [parameter.name
|
|
for parameter in role.parameter_list(plan)]:
|
|
params[key] = param_value
|
|
|
|
return params
|
|
|
|
def handle(self, request, data):
|
|
plan = api.tuskar.Plan.get_the_plan(self.request)
|
|
compute_prefix = plan.get_role_by_name('Compute').parameter_prefix
|
|
controller_prefix = plan.get_role_by_name(
|
|
'Controller').parameter_prefix
|
|
cinder_prefix = plan.get_role_by_name(
|
|
'Cinder-Storage').parameter_prefix
|
|
|
|
virt_type = data.get('virt_type')
|
|
neutron_public_interface = data.get('neutron_public_interface')
|
|
cloud_name = data.get('cloud_name')
|
|
cinder_iscsi_helper = data.get('cinder_iscsi_helper')
|
|
ntp_server = data.get('ntp_server')
|
|
|
|
parameters = {
|
|
compute_prefix + 'NovaComputeLibvirtType': virt_type,
|
|
controller_prefix + 'CinderISCSIHelper': cinder_iscsi_helper,
|
|
cinder_prefix + 'CinderISCSIHelper': cinder_iscsi_helper,
|
|
controller_prefix + 'CloudName': cloud_name,
|
|
controller_prefix + 'NeutronPublicInterface':
|
|
neutron_public_interface,
|
|
compute_prefix + 'NeutronPublicInterface':
|
|
neutron_public_interface,
|
|
controller_prefix + 'NtpServer':
|
|
ntp_server,
|
|
compute_prefix + 'NtpServer':
|
|
ntp_server,
|
|
}
|
|
|
|
parameters.update(self._load_additional_parameters(
|
|
plan, data,
|
|
'snmp_password', 'SnmpdReadonlyUserPassword'))
|
|
parameters.update(self._load_additional_parameters(
|
|
plan, data,
|
|
'extra_config', 'ExtraConfig'))
|
|
|
|
try:
|
|
plan.patch(request, plan.uuid, parameters)
|
|
except Exception as e:
|
|
horizon.exceptions.handle(
|
|
request,
|
|
_("Unable to update the service configuration."))
|
|
LOG.exception(e)
|
|
return False
|
|
else:
|
|
horizon.messages.success(
|
|
request,
|
|
_("Service configuration updated."))
|
|
return True
|