summaryrefslogtreecommitdiff
path: root/frontend
diff options
context:
space:
mode:
authorshoward <showard@592f7852-d20e-0410-864c-8624ca9c26a4>2008-11-12 18:17:05 +0000
committershoward <showard@592f7852-d20e-0410-864c-8624ca9c26a4>2008-11-12 18:17:05 +0000
commit8bad6ed905449c8190f8c8e37826b738c0cdd842 (patch)
tree326531059c7fcf6dd657abb1dcb8661bd17a567f /frontend
parentd6f2a1a31f4f1d1c13f078ebcf568fd68195b9e3 (diff)
Add a checkbox 'exclude "only if needed" labels' to host lists in AFE, checked by default in the create job view.
-add exclude_only_if_needed_labels argument to get_hosts() and get_num_hosts() RPCs -move some code from tko.models.TestViewManager up into model_logic, since AFE now needs it to create a custom join for doing many-valued exclusion git-svn-id: svn://test.kernel.org/autotest/trunk@2405 592f7852-d20e-0410-864c-8624ca9c26a4
Diffstat (limited to 'frontend')
-rw-r--r--frontend/afe/model_logic.py47
-rw-r--r--frontend/afe/rpc_interface.py34
-rw-r--r--frontend/afe/rpc_utils.py16
-rw-r--r--frontend/client/src/autotest/afe/HostSelector.java1
-rw-r--r--frontend/client/src/autotest/afe/HostTableDecorator.java34
-rw-r--r--frontend/client/src/autotest/common/table/CheckboxFilter.java35
6 files changed, 132 insertions, 35 deletions
diff --git a/frontend/afe/model_logic.py b/frontend/afe/model_logic.py
index 3cf964e0..91558233 100644
--- a/frontend/afe/model_logic.py
+++ b/frontend/afe/model_logic.py
@@ -137,6 +137,53 @@ class ExtendedManager(dbmodels.Manager):
return new_joins, new_where, params
+ class _CustomSqlQ(dbmodels.Q):
+ def __init__(self):
+ self._joins = datastructures.SortedDict()
+ self._where, self._params = [], []
+
+
+ def add_join(self, table, condition, join_type, alias=None):
+ if alias is None:
+ alias = table
+ condition = ModelExtensions.escape_user_sql(condition)
+ self._joins[alias] = (table, join_type, condition)
+
+
+ def add_where(self, where, params=[]):
+ self._where.append(where)
+ self._params.extend(params)
+
+
+ def get_sql(self, opts):
+ return self._joins, self._where, self._params
+
+
+ def add_join(self, query_set, join_table, join_key,
+ local_join_key='id', join_condition='', suffix='',
+ exclude=False, force_left_join=False):
+ table_name = self.model._meta.db_table
+ join_alias = join_table + suffix
+ full_join_key = join_alias + '.' + join_key
+ full_join_condition = '%s = %s.%s' % (full_join_key, table_name,
+ local_join_key)
+ if join_condition:
+ full_join_condition += ' AND (' + join_condition + ')'
+ if exclude or force_left_join:
+ join_type = 'LEFT JOIN'
+ else:
+ join_type = 'INNER JOIN'
+
+ filter_object = self._CustomSqlQ()
+ filter_object.add_join(join_table,
+ full_join_condition,
+ join_type,
+ alias=join_alias)
+ if exclude:
+ filter_object.add_where(full_join_key + ' IS NULL')
+ return query_set.filter(filter_object).distinct()
+
+
def filter_custom_join(self, join_suffix, **kwargs):
"""
Just like Django filter(), but allows the user to specify a custom
diff --git a/frontend/afe/rpc_interface.py b/frontend/afe/rpc_interface.py
index 3b1f99c8..167f04d9 100644
--- a/frontend/afe/rpc_interface.py
+++ b/frontend/afe/rpc_interface.py
@@ -90,27 +90,33 @@ def delete_host(id):
models.Host.smart_get(id).delete()
-def get_hosts(multiple_labels=[], **filter_data):
+def get_hosts(multiple_labels=[], exclude_only_if_needed_labels=False,
+ **filter_data):
"""\
multiple_labels: match hosts in all of the labels given. Should be a
list of label names.
+ exclude_only_if_needed_labels: exclude hosts with at least one
+ "only_if_needed" label applied.
"""
- filter_data['extra_args'] = (
- rpc_utils.extra_host_filters(multiple_labels))
- hosts = models.Host.list_objects(filter_data)
- for host in hosts:
- host_obj = models.Host.objects.get(id=host['id'])
- host['labels'] = [label.name
- for label in host_obj.labels.all()]
+ hosts = rpc_utils.get_host_query(multiple_labels,
+ exclude_only_if_needed_labels,
+ filter_data)
+ host_dicts = []
+ for host_obj in hosts:
+ host_dict = host_obj.get_object_dict()
+ host_dict['labels'] = [label.name for label in host_obj.labels.all()]
platform = host_obj.platform()
- host['platform'] = platform and platform.name or None
- return rpc_utils.prepare_for_serialization(hosts)
+ host_dict['platform'] = platform and platform.name or None
+ host_dicts.append(host_dict)
+ return rpc_utils.prepare_for_serialization(host_dicts)
-def get_num_hosts(multiple_labels=[], **filter_data):
- filter_data['extra_args'] = (
- rpc_utils.extra_host_filters(multiple_labels))
- return models.Host.query_count(filter_data)
+def get_num_hosts(multiple_labels=[], exclude_only_if_needed_labels=False,
+ **filter_data):
+ hosts = rpc_utils.get_host_query(multiple_labels,
+ exclude_only_if_needed_labels,
+ filter_data)
+ return hosts.count()
# tests
diff --git a/frontend/afe/rpc_utils.py b/frontend/afe/rpc_utils.py
index 0e25d05c..014e3f3d 100644
--- a/frontend/afe/rpc_utils.py
+++ b/frontend/afe/rpc_utils.py
@@ -97,6 +97,22 @@ def extra_host_filters(multiple_labels=[]):
return extra_args
+def get_host_query(multiple_labels, exclude_only_if_needed_labels, filter_data):
+ query = models.Host.valid_objects.all()
+ if exclude_only_if_needed_labels:
+ only_if_needed_labels = models.Label.valid_objects.filter(
+ only_if_needed=True)
+ only_if_needed_ids = ','.join(
+ str(label['id']) for label in only_if_needed_labels.values('id'))
+ query = models.Host.objects.add_join(
+ query, 'hosts_labels', join_key='host_id',
+ join_condition='hosts_labels_exclude.label_id IN (%s)'
+ % only_if_needed_ids,
+ suffix='_exclude', exclude=True)
+ filter_data['extra_args'] = (extra_host_filters(multiple_labels))
+ return models.Host.query_objects(filter_data, initial_query=query)
+
+
class InconsistencyException(Exception):
'Raised when a list of objects does not have a consistent value'
diff --git a/frontend/client/src/autotest/afe/HostSelector.java b/frontend/client/src/autotest/afe/HostSelector.java
index 030d17ea..921f2e49 100644
--- a/frontend/client/src/autotest/afe/HostSelector.java
+++ b/frontend/client/src/autotest/afe/HostSelector.java
@@ -72,6 +72,7 @@ public class HostSelector {
availableTable.setClickable(true);
availableDecorator.lockedFilter.setSelectedChoice("No");
availableDecorator.aclFilter.setActive(true);
+ availableDecorator.excludeOnlyIfNeededFilter.setActive(true);
availableSelection = availableDecorator.addSelectionManager(false);
availableDecorator.addSelectionPanel(true);
diff --git a/frontend/client/src/autotest/afe/HostTableDecorator.java b/frontend/client/src/autotest/afe/HostTableDecorator.java
index 77df2cdd..fc5f1a97 100644
--- a/frontend/client/src/autotest/afe/HostTableDecorator.java
+++ b/frontend/client/src/autotest/afe/HostTableDecorator.java
@@ -3,17 +3,15 @@ package autotest.afe;
import autotest.common.StaticDataRepository;
import autotest.common.Utils;
import autotest.common.table.BooleanFilter;
-import autotest.common.table.FieldFilter;
+import autotest.common.table.CheckboxFilter;
import autotest.common.table.ListFilter;
import autotest.common.table.SearchFilter;
import autotest.common.table.TableDecorator;
import com.google.gwt.json.client.JSONArray;
+import com.google.gwt.json.client.JSONBoolean;
import com.google.gwt.json.client.JSONString;
import com.google.gwt.json.client.JSONValue;
-import com.google.gwt.user.client.ui.CheckBox;
-import com.google.gwt.user.client.ui.ClickListener;
-import com.google.gwt.user.client.ui.Widget;
class HostTableDecorator extends TableDecorator {
SearchFilter hostnameFilter;
@@ -21,38 +19,30 @@ class HostTableDecorator extends TableDecorator {
ListFilter statusFilter;
BooleanFilter lockedFilter;
AclAccessibleFilter aclFilter;
+ OnlyIfNeededFilter excludeOnlyIfNeededFilter;
- static class AclAccessibleFilter extends FieldFilter implements ClickListener {
- private CheckBox checkBox = new CheckBox("ACL accessible only");
+ static class AclAccessibleFilter extends CheckboxFilter {
private JSONValue username;
public AclAccessibleFilter() {
super("acl_group__users__login");
username = new JSONString(StaticDataRepository.getRepository().getCurrentUserLogin());
- checkBox.addClickListener(this);
- }
-
- public void onClick(Widget sender) {
- notifyListeners();
}
@Override
public JSONValue getMatchValue() {
return username;
}
-
- @Override
- public Widget getWidget() {
- return checkBox;
+ }
+
+ static class OnlyIfNeededFilter extends CheckboxFilter {
+ public OnlyIfNeededFilter() {
+ super("exclude_only_if_needed_labels");
}
@Override
- public boolean isActive() {
- return checkBox.isChecked();
- }
-
- public void setActive(boolean active) {
- checkBox.setChecked(active);
+ public JSONValue getMatchValue() {
+ return JSONBoolean.getInstance(true);
}
}
@@ -73,6 +63,7 @@ class HostTableDecorator extends TableDecorator {
statusFilter.setChoices(statusStrings);
lockedFilter = new BooleanFilter("locked");
aclFilter = new AclAccessibleFilter();
+ excludeOnlyIfNeededFilter = new OnlyIfNeededFilter();
addFilter("Hostname", hostnameFilter);
addControl("Platform", labelFilter.getPlatformWidget());
@@ -80,5 +71,6 @@ class HostTableDecorator extends TableDecorator {
addFilter("Status", statusFilter);
addFilter("Locked", lockedFilter);
addFilter("ACL accessible only", aclFilter);
+ addFilter("Exclude only_if_needed labels", excludeOnlyIfNeededFilter);
}
}
diff --git a/frontend/client/src/autotest/common/table/CheckboxFilter.java b/frontend/client/src/autotest/common/table/CheckboxFilter.java
new file mode 100644
index 00000000..1a92e044
--- /dev/null
+++ b/frontend/client/src/autotest/common/table/CheckboxFilter.java
@@ -0,0 +1,35 @@
+// Copyright 2008 Google Inc. All Rights Reserved.
+
+package autotest.common.table;
+
+
+import com.google.gwt.user.client.ui.CheckBox;
+import com.google.gwt.user.client.ui.ClickListener;
+import com.google.gwt.user.client.ui.Widget;
+
+public abstract class CheckboxFilter extends FieldFilter implements ClickListener {
+ private CheckBox checkBox = new CheckBox();
+
+ public CheckboxFilter(String fieldName) {
+ super(fieldName);
+ checkBox.addClickListener(this);
+ }
+
+ public void onClick(Widget sender) {
+ notifyListeners();
+ }
+
+ @Override
+ public Widget getWidget() {
+ return checkBox;
+ }
+
+ @Override
+ public boolean isActive() {
+ return checkBox.isChecked();
+ }
+
+ public void setActive(boolean active) {
+ checkBox.setChecked(active);
+ }
+} \ No newline at end of file