Change datagrid field to work with units templates.

Now datagrid uses dcInstances value converted to units (though, still 2 hacks
are needed - to JSON-stringify input data and destringify output data). This seems
appropriate to be done, when we will throw away djblets package.

Datagrid uses data from another form as initial data (thus make useful MRN-831).

Also one change is made to unitTemplates data: every occurrence of '#' in strings
is replaced with current unit 1-based index, as in unitNamingPattern.

Change-Id: I283a67e437d1495257e4c39b18e558072875ffea
This commit is contained in:
Timur Sufiev 2013-08-22 20:15:24 +04:00
parent c2e54c51ac
commit 907a862d40
7 changed files with 51 additions and 46 deletions

View File

@ -53,8 +53,8 @@ class RadioColumn(Column):
class NodeDataGrid(DataGrid):
name = Column('Node', sortable=False)
is_sync = CheckColumn('Sync')
is_primary = RadioColumn('Primary')
isSync = CheckColumn('Sync')
isMaster = RadioColumn('Primary')
def __init__(self, request, data):
self.pk = PK()
@ -68,7 +68,7 @@ class NodeDataGrid(DataGrid):
super(NodeDataGrid, self).__init__(request, FakeQuerySet(
Node, items=items), optimize_sorts=False)
self.default_sort = []
self.default_columns = ['name', 'is_sync', 'is_primary']
self.default_columns = ['name', 'isSync', 'isMaster']
# hack
def load_state(self, render_context=None):

View File

@ -73,6 +73,5 @@ class FakeQuerySet(EmptyQuerySet):
class Node(models.Model):
id = models.IntegerField(primary_key=True)
name = models.CharField(max_length=20)
is_primary = models.BooleanField(default=False)
is_sync = models.BooleanField(default=False)
is_async = models.BooleanField(default=False)
isMaster = models.BooleanField(default=False)
isSync = models.BooleanField(default=False)

View File

@ -6,7 +6,15 @@ description: >-
Microsoft SQL Failover Cluster Server
unitTemplates:
- {}
- isMaster: true
isSync: true
name: 'node#'
- isMaster: false
isSync: true
name: 'node#'
- isMaster: false
isSync: false
name: 'node#'
forms:
- serviceConfiguration:
@ -130,7 +138,7 @@ forms:
minValue: 2
maxValue: 5
initial: 2
attributeNames: units
attributeNames: false
helpText: Enter an integer value between 2 and 5
description: Microsoft SQL Failover Cluster includes up to 5 instances.
- name: unitNamingPattern
@ -153,6 +161,7 @@ forms:
- name: nodes
type: datagrid
label: Nodes
initial: {YAQL: $.clusterConfiguration.dcInstances}
description: >-
Configure cluster instances. Cluster node quantity can be set
with 'Add' and 'Remove' buttons. Configure Sync mode by

View File

@ -30,10 +30,10 @@ import copy
def with_request(func):
def update(self, initial):
def update(self, initial, **kwargs):
request = initial.get('request')
if request:
func(self, request, initial)
func(self, request, **kwargs)
else:
raise forms.ValidationError("Can't get a request information")
return update
@ -128,14 +128,27 @@ class InstanceCountField(IntegerField):
def postclean(self, form, data):
value = []
if hasattr(self, 'value'):
templates = form.get_unit_templates(data)
for dc in range(self.value):
templates = form.get_unit_templates(data)
if dc < len(templates) - 1:
value.append(templates[dc])
template = templates[dc]
else:
value.append(templates[-1])
template = templates[-1]
value.append(self.interpolate_number(template, dc + 1))
return value
@staticmethod
def interpolate_number(spec, number):
"""Replaces all '#' occurrences with given number."""
def interpolate(spec):
if type(spec) == dict:
return dict((k, interpolate(v)) for (k, v) in spec.iteritems())
elif type(spec) in (str, unicode) and '#' in spec:
return spec.replace('#', '{0}').format(number)
else:
return spec
return interpolate(spec)
class DataGridField(forms.MultiValueField, CustomPropertiesField):
def __init__(self, *args, **kwargs):
@ -148,16 +161,12 @@ class DataGridField(forms.MultiValueField, CustomPropertiesField):
return data_list[1]
@with_request
def update(self, request, initial):
def update(self, request, **kwargs):
self.widget.update_request(request)
nodes = []
instance_count = initial.get('instance_count')
if instance_count:
for index in xrange(instance_count):
nodes.append({'name': 'node' + str(index + 1),
'is_sync': index < 2,
'is_primary': index == 0})
self.initial = json.dumps(nodes)
# hack to use json string instead of python dict get by YAQL
data = kwargs['form'].service.cleaned_data
data['clusterConfiguration']['dcInstances'] = json.dumps(
data['clusterConfiguration']['dcInstances'])
class ChoiceField(forms.ChoiceField, CustomPropertiesField):
@ -166,7 +175,7 @@ class ChoiceField(forms.ChoiceField, CustomPropertiesField):
class DomainChoiceField(ChoiceField):
@with_request
def update(self, request, initial):
def update(self, request, **kwargs):
self.choices = [("", "Not in domain")]
link = request.__dict__['META']['HTTP_REFERER']
environment_id = re.search(
@ -179,7 +188,7 @@ class DomainChoiceField(ChoiceField):
class FlavorChoiceField(ChoiceField):
@with_request
def update(self, request, initial):
def update(self, request, **kwargs):
self.choices = [(flavor.name, flavor.name) for flavor in
novaclient(request).flavors.list()]
for flavor in self.choices:
@ -190,7 +199,7 @@ class FlavorChoiceField(ChoiceField):
class ImageChoiceField(ChoiceField):
@with_request
def update(self, request, initial):
def update(self, request, **kwargs):
try:
# public filter removed
images, _more = glance.image_list_detailed(request)
@ -228,7 +237,7 @@ class ImageChoiceField(ChoiceField):
class AZoneChoiceField(ChoiceField):
@with_request
def update(self, request, initial):
def update(self, request, **kwargs):
try:
availability_zones = novaclient(request).availability_zones.\
list(detailed=False)
@ -273,7 +282,7 @@ class ClusterIPField(CharField):
return perform_checking
@with_request
def update(self, request, initial):
def update(self, request, **kwargs):
try:
network_list = novaclient(request).networks.list()
ip_ranges = [network.cidr for network in network_list]

View File

@ -40,7 +40,7 @@ class UpdatableFieldsForm(forms.Form):
for name, field in self.fields.iteritems():
if hasattr(field, 'update'):
field.update(self.initial)
field.update(self.initial, form=self)
if not field.required:
field.widget.attrs['placeholder'] = 'Optional'

View File

@ -61,13 +61,9 @@ class Wizard(ModalFormMixin, SessionWizardView):
for form in form_list[1:]:
form.extract_attributes(attributes)
# hack to fill units with data from nodes datagrid
# hack to destringify nodes into units
if 'nodes' in attributes:
units = []
for node in json.loads(attributes['nodes']):
units.append({'isMaster': node['is_primary'],
'isSync': node['is_sync']})
attributes['units'] = units
attributes['units'] = json.loads(attributes['nodes'])
del attributes['nodes']
try:
@ -80,8 +76,8 @@ class Wizard(ModalFormMixin, SessionWizardView):
except Exception:
redirect = reverse("horizon:project:murano:index")
exceptions.handle(self.request,
_('Sorry, you can\'t create service right now.',
redirect=redirect))
_('Sorry, you can\'t create service right now.'),
redirect=redirect)
else:
message = "The %s service successfully created." % slug
messages.success(self.request, message)
@ -91,14 +87,6 @@ class Wizard(ModalFormMixin, SessionWizardView):
init_dict = {}
if step != 'service_choice':
init_dict['request'] = self.request
# hack to pass number of nodes from one form to another
if step == 'ms-sql-server-cluster-2':
form_id = 'ms-sql-server-cluster-1'
form_data = self.storage.data['step_data'].get(form_id, {})
instance_count = form_data.get(form_id + '-dcInstances')
if instance_count:
init_dict['instance_count'] = int(instance_count[0])
return self.initial_dict.get(step, init_dict)
def get_context_data(self, form, **kwargs):

View File

@ -122,8 +122,8 @@ $(function() {
}
data.push({
name: trimLabel($(tr).children().eq(0).text()),
is_sync: getInputVal($(tr).children().eq(1)),
is_primary: getInputVal($(tr).children().eq(2))
isSync: getInputVal($(tr).children().eq(1)),
isMaster: getInputVal($(tr).children().eq(2))
})
});
$('input.gridfield-hidden').val(JSON.stringify(data));