Merge branch 'master' of ssh://git.planet-lab.org/git/plstackapi into HEAD
diff --git a/planetstack/apigen/api.template.py b/planetstack/apigen/api.template.py
index b17f135..2cfb54a 100644
--- a/planetstack/apigen/api.template.py
+++ b/planetstack/apigen/api.template.py
@@ -70,9 +70,9 @@
id = serializers.Field()
{% for ref in object.refs %}
{% if ref.multi %}
- {{ ref.plural }} = serializers.HyperlinkedRelatedField(many=True, read_only=True, view_name='{{ ref }}-detail')
+ {{ ref.plural }} = serializers.PrimaryKeyRelatedField(many=True, read_only=True) #, view_name='{{ ref }}-detail')
{% else %}
- {{ ref }} = serializers.HyperlinkedRelatedField(read_only=True, view_name='{{ ref }}-detail')
+ {{ ref }} = serializers.PrimaryKeyRelatedField(read_only=True) #, view_name='{{ ref }}-detail')
{% endif %}
{% endfor %}
humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
diff --git a/planetstack/apigen/modelgen b/planetstack/apigen/modelgen
old mode 100755
new mode 100644
index 8a647b1..77d1e67
--- a/planetstack/apigen/modelgen
+++ b/planetstack/apigen/modelgen
@@ -111,8 +111,6 @@
cobj = copy.deepcopy(obj)
cobj.multi = True
cobj.plural_name = related_name
- #if (str(refobj)=='slice' and related_name=='networks'):
- # pdb.set_trace()
refobj.refs.append(cobj)
else:
obj.props.append(f.name)
@@ -126,7 +124,7 @@
related_name = f.related_query_name()
if related_model_name in self.keys():
- # pdb.set_trace()
+ #print "XXX1", obj, f, related_name, related_model_name
refobj = self[related_model_name]
cobj = copy.deepcopy(obj)
cobj.multi=True
@@ -137,17 +135,12 @@
continue
if (related_name!='+' and related_name.lower()!=str(obj).lower()):
- cobj = copy.deepcopy(obj)
+ #print "XXX2", obj, f, related_name, related_model_name, refobj.plural_name
+ refobj = self[related_model_name]
+ cobj = copy.deepcopy(refobj)
cobj.multi = True
- cobj.plural_name = related_name
- #if (str(refobj)=='slice' and related_name=='networks'):
- # pdb.set_trace()
- refobj.refs.append(cobj)
-
- #if (related_name=='networks'):
- #pdb.set_trace()
- #print str(refobj)
+ obj.refs.append(cobj)
diff --git a/planetstack/core/xoslib/static/js/xosAdminSite.js b/planetstack/core/xoslib/static/js/xosAdminSite.js
index 3aa33d3..c44dc58 100644
--- a/planetstack/core/xoslib/static/js/xosAdminSite.js
+++ b/planetstack/core/xoslib/static/js/xosAdminSite.js
@@ -1,4 +1,4 @@
-OBJS = ['deployment', 'image', 'networkTemplate', 'network', 'networkSliver', 'networkDeployment', 'node', 'service', 'site', 'slice', 'sliceDeployment', 'slicePrivilege', 'sliver', 'user', 'sliceRole', 'userDeployment'];
+OBJS = ['deployment', 'image', 'networkTemplate', 'network', 'networkSliver', 'networkDeployment', 'node', 'service', 'site', 'slice', 'sliceDeployment', 'slicePrivilege', 'sliver', 'user', 'sliceRole', 'userDeployment', 'flavor', 'imageDeployment'];
NAV_OBJS = ['deployment', 'site', 'slice', 'user'];
REWRITES = {"/admin/core/deployment/": "#deployments",
@@ -87,23 +87,29 @@
collection_name = name + "s";
region_name = name + "List";
+ if (window["XOSDetailView_" + name]) {
+ detailClass = window["XOSDetailView_" + name].extend({template: "#xos-detail-template",
+ app: XOSAdminApp});
+ } else {
+ detailClass = genericDetailClass;
+ }
if ($(detail_template).length) {
- detailClass = XOSDetailView.extend({
+ detailClass = detailClass.extend({
template: detail_template,
- app: XOSAdminApp,
});
- } else {
- detailClass = genericDetailClass;
}
XOSAdminApp[collection_name + "DetailView"] = detailClass;
- if ($(add_child_template).length) {
- addClass = XOSDetailView.extend({
+ if (window["XOSDetailView_" + name]) {
+ addClass = window["XOSDetailView_" + name].extend({template: "#xos-add-template",
+ app: XOSAdminApp});
+ } else {
+ addClass = genericAddChildClass;
+ }
+ if ($(add_child_template).length) {
+ addClass = detailClass.extend({
template: add_child_template,
- app: XOSAdminApp,
});
- } else {
- addClass = genericAddChildClass;
}
XOSAdminApp[collection_name + "AddChildView"] = addClass;
diff --git a/planetstack/core/xoslib/static/js/xoslib/xos-backbone.js b/planetstack/core/xoslib/static/js/xoslib/xos-backbone.js
index d5a0fc3..554ff5f 100644
--- a/planetstack/core/xoslib/static/js/xoslib/xos-backbone.js
+++ b/planetstack/core/xoslib/static/js/xoslib/xos-backbone.js
@@ -10,12 +10,14 @@
USERDEPLOYMENT_API = "/plstackapi/user_deployments/";
DEPLOYMENT_API = "/plstackapi/deployments/";
IMAGE_API = "/plstackapi/images/";
+ IMAGEDEPLOYMENTS_API = "/plstackapi/imagedeployments/";
NETWORKTEMPLATE_API = "/plstackapi/networktemplates/";
NETWORK_API = "/plstackapi/networks/";
NETWORKSLIVER_API = "/plstackapi/networkslivers/";
SERVICE_API = "/plstackapi/services/";
SLICEPRIVILEGE_API = "/plstackapi/slice_privileges/";
NETWORKDEPLOYMENT_API = "/plstackapi/networkdeployments/";
+ FLAVOR_API = "/plstackapi/flavors/";
/* changed as a side effect of the big rename
SLICEDEPLOYMENT_API = "/plstackapi/slice_deployments/";
@@ -382,12 +384,12 @@
define_model(this, {urlRoot: SLIVER_API,
relatedCollections: {"networkSlivers": "sliver"},
- foreignCollections: ["slices", "deployments", "images", "nodes", "users"],
- foreignFields: {"creator": "users", "image": "images", "node": "nodes", "deploymentNetwork": "deployments", "slice": "slices"},
+ foreignCollections: ["slices", "deployments", "images", "nodes", "users", "flavors"],
+ foreignFields: {"creator": "users", "image": "images", "node": "nodes", "deploymentNetwork": "deployments", "slice": "slices", "flavor": "flavors"},
modelName: "sliver",
listFields: ["backend_status", "id", "name", "instance_id", "instance_name", "slice", "deploymentNetwork", "image", "node", "flavor"],
- addFields: ["slice", "deploymentNetwork", "image", "node"],
- detailFields: ["backend_status", "name", "instance_id", "instance_name", "slice", "deploymentNetwork", "image", "node", "creator"],
+ addFields: ["slice", "deploymentNetwork", "flavor", "image", "node"],
+ detailFields: ["backend_status", "name", "instance_id", "instance_name", "slice", "deploymentNetwork", "flavor", "image", "node", "creator"],
preSave: function() { if (!this.attributes.name && this.attributes.slice) { this.attributes.name = xos.idToName(this.attributes.slice, "slices", "name"); } },
});
@@ -483,6 +485,13 @@
detailFields: ["backend_status", "name", "disk_format", "admin_tenant"],
});
+ define_model(this, {urlRoot: IMAGEDEPLOYMENTS_API,
+ modelName: "imageDeployment",
+ foreignCollections: ["images", "deployments"],
+ listFields: ["backend_status", "id", "image", "deployment", "glance_image_id"],
+ detailFields: ["backend_status", "image", "deployment", "glance_image_id"],
+ });
+
define_model(this, {urlRoot: NETWORKTEMPLATE_API,
modelName: "networkTemplate",
listFields: ["backend_status", "id", "name", "visibility", "translation", "sharedNetworkName", "sharedNetworkId"],
@@ -518,6 +527,13 @@
detailFields: ["backend_status", "name", "description", "versionNumber"],
});
+ define_model(this, {urlRoot: FLAVOR_API,
+ modelName: "flavor",
+ listFields: ["backend_status", "id", "name", "flavor", "order", "default"],
+ detailFields: ["backend_status", "name", "description", "flavor", "order", "default"],
+ inputType: {"default": "checkbox"},
+ });
+
// enhanced REST
// XXX this really needs to somehow be combined with Slice, to avoid duplication
define_model(this, {urlRoot: SLICEPLUS_API,
diff --git a/planetstack/core/xoslib/static/js/xoslib/xosHelper.js b/planetstack/core/xoslib/static/js/xoslib/xosHelper.js
index ece2419..65ccdbd 100644
--- a/planetstack/core/xoslib/static/js/xoslib/xosHelper.js
+++ b/planetstack/core/xoslib/static/js/xoslib/xosHelper.js
@@ -594,7 +594,66 @@
inputType: this.model.inputType,
model: this.model,
}},
+});
+XOSDetailView_sliver = XOSDetailView.extend( {
+ events: $.extend(XOSDetailView.events,
+ {"change #field_deploymentNetwork": "onDeploymentNetworkChange"}
+ ),
+
+ onShow: function() {
+ // Note that this causes the selects to be updated a second time. The
+ // first time was when the template was originally invoked, and the
+ // selects will all have the full unfiltered set of candidates. Then
+ // onShow will fire, and we'll update them with the filtered values.
+ this.onDeploymentNetworkChange();
+ },
+
+ onDeploymentNetworkChange: function(e) {
+ var deploymentID = this.$el.find("#field_deploymentNetwork").val();
+
+ console.log("onDeploymentNetworkChange");
+ console.log(deploymentID);
+
+ filterFunc = function(model) { return (model.attributes.deployment==deploymentID); }
+ newSelect = idToSelect("node",
+ this.model.attributes.node,
+ this.model.foreignFields["node"],
+ "humanReadableName",
+ false,
+ filterFunc);
+ this.$el.find("#field_node").html(newSelect);
+
+ filterFunc = function(model) { for (index in model.attributes.deployments) {
+ item=model.attributes.deployments[index];
+ if (item.toString()==deploymentID.toString()) return true;
+ };
+ return false;
+ }
+ newSelect = idToSelect("flavor",
+ this.model.attributes.flavor,
+ this.model.foreignFields["flavor"],
+ "humanReadableName",
+ false,
+ filterFunc);
+ this.$el.find("#field_flavor").html(newSelect);
+
+ filterFunc = function(model) { for (index in xos.imageDeployments.models) {
+ imageDeployment = xos.imageDeployments.models[index];
+ if ((imageDeployment.attributes.deployment == deploymentID) && (imageDeployment.attributes.image == model.id)) {
+ return true;
+ }
+ }
+ return false;
+ };
+ newSelect = idToSelect("image",
+ this.model.attributes.image,
+ this.model.foreignFields["image"],
+ "humanReadableName",
+ false,
+ filterFunc);
+ this.$el.find("#field_image").html(newSelect);
+ },
});
/* XOSItemView
@@ -920,7 +979,7 @@
fieldName = name of field within models of collection that will be displayed
*/
-idToOptions = function(selectedId, collectionName, fieldName) {
+idToOptions = function(selectedId, collectionName, fieldName, filterFunc) {
result=""
for (index in xos[collectionName].models) {
linkedObject = xos[collectionName].models[index];
@@ -931,6 +990,9 @@
} else {
selected = "";
}
+ if ((filterFunc) && (!filterFunc(linkedObject))) {
+ continue;
+ }
result = result + '<option value="' + linkedId + '"' + selected + '>' + linkedName + '</option>';
}
return result;
@@ -944,14 +1006,14 @@
fieldName = name of field within models of collection that will be displayed
*/
-idToSelect = function(variable, selectedId, collectionName, fieldName, readOnly) {
+idToSelect = function(variable, selectedId, collectionName, fieldName, readOnly, filterFunc) {
if (readOnly) {
readOnly = " readonly";
} else {
readOnly = "";
}
- result = '<select name="' + variable + '"' + readOnly + '>' +
- idToOptions(selectedId, collectionName, fieldName) +
+ result = '<select name="' + variable + '" id="field_' + variable + '"' + readOnly + '>' +
+ idToOptions(selectedId, collectionName, fieldName, filterFunc) +
'</select>';
return result;
}