Revision: 13466
http://freenas.svn.sourceforge.net/freenas/?rev=13466&view=rev
Author: jhixson
Date: 2013-03-27 23:59:35 +0000 (Wed, 27 Mar 2013)
Log Message:
-----------
Bring all changes to trunk into pluginjail branch.
Modified Paths:
--------------
projects/pluginjail/.gitignore
projects/pluginjail/README
projects/pluginjail/build/create_iso.sh
projects/pluginjail/gui/account/urls.py
projects/pluginjail/gui/freeadmin/api/utils.py
projects/pluginjail/gui/freeadmin/static/lib/js/freeadmin.js
projects/pluginjail/gui/freeadmin/utils.py
projects/pluginjail/gui/freeadmin/views.py
projects/pluginjail/gui/jails/urls.py
projects/pluginjail/gui/middleware/notifier.py
projects/pluginjail/gui/network/urls.py
projects/pluginjail/gui/plugins/urls.py
projects/pluginjail/gui/reporting/urls.py
projects/pluginjail/gui/services/forms.py
projects/pluginjail/gui/services/models.py
projects/pluginjail/gui/services/urls.py
projects/pluginjail/gui/sharing/forms.py
projects/pluginjail/gui/sharing/urls.py
projects/pluginjail/gui/storage/forms.py
projects/pluginjail/gui/storage/urls.py
projects/pluginjail/gui/storage/views.py
projects/pluginjail/gui/system/models.py
projects/pluginjail/gui/system/urls.py
projects/pluginjail/gui/templates/500_freenas.html
projects/pluginjail/gui/templates/account/index.html
projects/pluginjail/gui/templates/base.html
projects/pluginjail/gui/templates/freeadmin/generic_model_datagrid.html
projects/pluginjail/gui/templates/freeadmin/index.html
projects/pluginjail/gui/templates/jails/index.html
projects/pluginjail/gui/templates/network/index.html
projects/pluginjail/gui/templates/plugins/index.html
projects/pluginjail/gui/templates/plugins/plugin_confirm_delete.html
projects/pluginjail/gui/templates/reporting/index.html
projects/pluginjail/gui/templates/services/core.html
projects/pluginjail/gui/templates/services/index.html
projects/pluginjail/gui/templates/services/iscsi.html
projects/pluginjail/gui/templates/services/plugins.html
projects/pluginjail/gui/templates/services/pluginsjail_edit.html
projects/pluginjail/gui/templates/sharing/index.html
projects/pluginjail/gui/templates/storage/create_passphrase.html
projects/pluginjail/gui/templates/storage/index.html
projects/pluginjail/gui/templates/storage/multipath_status.html
projects/pluginjail/gui/templates/storage/replication_add.html
projects/pluginjail/gui/templates/storage/replication_datagrid.html
projects/pluginjail/gui/templates/storage/replications.html
projects/pluginjail/gui/templates/storage/snapshots.html
projects/pluginjail/gui/templates/storage/task_datagrid.html
projects/pluginjail/gui/templates/storage/volume_datagrid.html
projects/pluginjail/gui/templates/storage/volume_detach.html
projects/pluginjail/gui/templates/storage/wizard.html
projects/pluginjail/gui/templates/system/advanced_edit.html
projects/pluginjail/gui/templates/system/config_ok.html
projects/pluginjail/gui/templates/system/config_ok2.html
projects/pluginjail/gui/templates/system/debug.html
projects/pluginjail/gui/templates/system/done.html
projects/pluginjail/gui/templates/system/email_edit.html
projects/pluginjail/gui/templates/system/reporting.html
projects/pluginjail/gui/templates/system/settings_edit.html
projects/pluginjail/gui/templates/system/wizard_1.html
projects/pluginjail/gui/tools/alert.py
projects/pluginjail/gui/urls.py
projects/pluginjail/nanobsd/FREENAS.amd64
projects/pluginjail/nanobsd/FREENAS.i386
projects/pluginjail/nanobsd/Files/etc/crontab
projects/pluginjail/nanobsd/Files/etc/rc.conf.local
projects/pluginjail/nanobsd/Files/etc/rc.d/ix-collectd
projects/pluginjail/nanobsd/Files/etc/rc.d/ix-crontab
projects/pluginjail/nanobsd/Files/etc/rc.d/ix-samba
projects/pluginjail/nanobsd/Files/usr/local/etc/rc.d/django
projects/pluginjail/nanobsd/Installer/lib/functions.sh
projects/pluginjail/nanobsd/Installer/pre-install/0001.prevent_downgrade.sh
Added Paths:
-----------
projects/pluginjail/gui/freeadmin/static/lib/js/freeadmin/VolumeManager.js
projects/pluginjail/gui/freeadmin/static/lib/js/freeadmin/templates/volumemanager.html
projects/pluginjail/gui/services/migrations/0087_auto__del_field_cifs_cifs_srv_largerw.py
projects/pluginjail/gui/templates/storage/volumemanager.html
Removed Paths:
-------------
projects/pluginjail/nanobsd/Files/usr/local/bin/graph.py
Property Changed:
----------------
projects/pluginjail/
Index: projects/pluginjail
===================================================================
--- projects/pluginjail 2013-03-27 05:41:04 UTC (rev 13465)
+++ projects/pluginjail 2013-03-27 23:59:35 UTC (rev 13466)
Property changes on: projects/pluginjail
___________________________________________________________________
Modified: svn:mergeinfo
## -9,4 +9,4 ##
/branches/feedback:6189-6347
/experimental/ix-8.2:5657-5682
/tags/8.0.3-BETA2:9099-9100
-/trunk:7833-7857,13447-13449,13453-13463
+/trunk:7833-7857,13348-13350,13352-13365,13367,13369,13371,13375-13379,13381-13386,13405-13411,13413,13416-13424,13426-13429,13431-13432,13435-13444,13446-13449,13453-13463
\ No newline at end of property
Modified: projects/pluginjail/.gitignore
===================================================================
--- projects/pluginjail/.gitignore 2013-03-27 05:41:04 UTC (rev 13465)
+++ projects/pluginjail/.gitignore 2013-03-27 23:59:35 UTC (rev 13466)
@@ -3,3 +3,8 @@
*.mo
*.o
gui/local_settings.py
+FreeBSD/
+filtered-patches/
+os-base/
+pbi/
+sbin/
Modified: projects/pluginjail/README
===================================================================
--- projects/pluginjail/README 2013-03-27 05:41:04 UTC (rev 13465)
+++ projects/pluginjail/README 2013-03-27 23:59:35 UTC (rev 13466)
@@ -26,19 +26,24 @@
Building the System Quickstart Flow:
-- Checking out the code from svn:
+- Checking out the code from git:
-% svn co https://svn.code.sf.net/p/freenas/code/trunk
-% cd trunk
+% git clone --depth 1 git://github.com/freenas/freenas.git
+% cd freenas
-More information about checking out sources from svn via SourceForge
-can be found here: http://p.sf.net/sourceforge/svn .
+- Use the build script
-- Use the build script (substituting your favorite cvsup mirror)
+% sudo sh build/do_build.sh
-% sudo env FREEBSD_CVSUP_HOST=cvsup1.freebsd.org sh build/do_build.sh
+This will fetch TrueOS and ports for the build. However it is recommended that you maintain a local git mirror to speed up further builds:
+% git clone git://github.com/freenas/ports.git ${HOME}/ports
+% git clone git://github.com/trueos/trueos.git ${HOME}/trueos
+To build using those local mirrors run:
+
+% sudo env GIT_REPO=${HOME}/trueos GIT_PORTS_REPO=${HOME}/ports sh build/do_build.sh
+
That's it.
The End Result:
@@ -47,7 +52,7 @@
obj.yyyy/FreeNAS-VVVV-XXXX-yyyy.img.xz where:
- VVVV is the 'release' branch version or.
-- XXXX is the svn revision from the FreeNAS repo.
+- XXXX is the git commit hash from the FreeNAS repo.
- yyyy is either i386 or amd64 depending on your platform and what was
provided via $FREENAS_ARCH on the command line / via the environment.
@@ -65,12 +70,12 @@
2. Forcing an source / ports update:
-% sudo env FREEBSD_CVSUP_HOST=cvsup1.freebsd.org sh build/do_build.sh -u
+% sudo sh build/do_build.sh -u
3. Updating ports patches:
-% sudo rm -Rf obj.$FREENAS_ARCH/ports/packages/
-% sudo env FREEBSD_CVSUP_HOST=cvsup1.freebsd.org sh build/do_build.sh -u
+% sudo rm -Rf os-base/$FREENAS_ARCH/ports/packages/
+% sudo sh build/do_build.sh -u
NOTE: when things get smarter (and they will.. the developers feel your pain
too :/..), nuking individual packages won't be required; this will require
@@ -81,11 +86,11 @@
4. Update source and ports, patch, and rebuild FreeBSD:
-% sudo env FREEBSD_CVSUP_HOST=cvsup10.freebsd.org sh build/do_build.sh -fu
+% sudo sh build/do_build.sh -fu
5. Force a build from scratch (nukes packages, rebuild FreeBSD):
-% sudo env FREEBSD_CVSUP_HOST=cvsup10.freebsd.org sh build/do_build.sh -ff
+% sudo sh build/do_build.sh -ff
6. Build everything required (src, ports) but don't produce GUI upgrade/CD
images:
Modified: projects/pluginjail/build/create_iso.sh
===================================================================
--- projects/pluginjail/build/create_iso.sh 2013-03-27 05:41:04 UTC (rev 13465)
+++ projects/pluginjail/build/create_iso.sh 2013-03-27 23:59:35 UTC (rev 13466)
@@ -94,6 +94,13 @@
# installer code.
rm -f "$INSTALLUFSDIR/etc/rc.conf.local"
+ # NOTE: only glabel and gpart work statically when hardlinked as
+ # geom(8).
+ #
+ # Look for "nvalid class name" in sbin/geom/core/geom.c for more
+ # details.
+ tar -cf - -C${NANO_OBJ}/_.w/sbin gmirror graid | tar -xpf - -C ${INSTALLUFSDIR}/rescue/
+
# Compress what's left of the image after mangling it
makefs -b 10% ${TEMP_IMGFILE} ${INSTALLUFSDIR}
mkuzip -o ${ISODIR}/data/base.ufs.uzip ${TEMP_IMGFILE}
@@ -209,7 +216,7 @@
# Boot loader file for $NANO_LABEL. This relies on a hacked beastie.4th.
#
autoboot_delay="2"
-loader_logo="freenas"
+#loader_logo="freenas"
mfsroot_load="YES"
mfsroot_type="md_image"
@@ -219,16 +226,6 @@
init_shell="/rescue/sh"
init_script="/baseroot.rc"
init_chroot="/baseroot"
-opensolaris_load="YES"
-zfs_load="YES"
-# GEOM support
-geom_mirror_load="YES"
-geom_stripe_load="YES"
-geom_raid3_load="YES"
-geom_raid5_load="YES"
-geom_gate_load="YES"
-ntfs_load="YES"
-smbfs_load="YES"
EOF
eval ${MKISOFS_CMD}
echo "Created ${OUTPUT}"
Modified: projects/pluginjail/gui/account/urls.py
===================================================================
--- projects/pluginjail/gui/account/urls.py 2013-03-27 05:41:04 UTC (rev 13465)
+++ projects/pluginjail/gui/account/urls.py 2013-03-27 23:59:35 UTC (rev 13466)
@@ -25,7 +25,7 @@
#
#####################################################################
-from django.conf.urls.defaults import patterns, url
+from django.conf.urls import patterns, url
from django.contrib.auth.views import logout
from freenasUI.common.system import get_sw_name
Modified: projects/pluginjail/gui/freeadmin/api/utils.py
===================================================================
--- projects/pluginjail/gui/freeadmin/api/utils.py 2013-03-27 05:41:04 UTC (rev 13465)
+++ projects/pluginjail/gui/freeadmin/api/utils.py 2013-03-27 23:59:35 UTC (rev 13466)
@@ -83,10 +83,11 @@
response header so ranges could workd well with dojo
XXXXXX
"""
- objects = self.obj_get_list(request=request, **self.remove_api_resource_names(kwargs))
+ base_bundle = self.build_bundle(request=request)
+ objects = self.obj_get_list(bundle=base_bundle, **self.remove_api_resource_names(kwargs))
sorted_objects = self.apply_sorting(objects, options=request.GET)
- paginator = self._meta.paginator_class(request, sorted_objects, resource_uri=self.get_resource_list_uri(), limit=self._meta.limit)
+ paginator = self._meta.paginator_class(request, sorted_objects, resource_uri=self.get_resource_uri(), limit=self._meta.limit)
to_be_serialized = paginator.page()
bundles = [self.build_bundle(obj=obj, request=request) for obj in to_be_serialized['objects']]
Copied: projects/pluginjail/gui/freeadmin/static/lib/js/freeadmin/VolumeManager.js (from rev 13348, trunk/gui/freeadmin/static/lib/js/freeadmin/VolumeManager.js)
===================================================================
--- projects/pluginjail/gui/freeadmin/static/lib/js/freeadmin/VolumeManager.js (rev 0)
+++ projects/pluginjail/gui/freeadmin/static/lib/js/freeadmin/VolumeManager.js 2013-03-27 23:59:35 UTC (rev 13466)
@@ -0,0 +1,667 @@
+define([
+ "dojo/_base/array",
+ "dojo/_base/connect",
+ "dojo/_base/declare",
+ "dojo/_base/lang",
+ "dojo/dom-attr",
+ "dojo/dom-construct",
+ "dojo/dom-style",
+ "dojo/json",
+ "dojo/on",
+ "dojo/query",
+ "dojo/topic",
+ "dijit/_Widget",
+ "dijit/_TemplatedMixin",
+ "dijit/registry",
+ "dijit/Tooltip",
+ "dijit/form/Button",
+ "dijit/form/CheckBox",
+ "dijit/form/Form",
+ "dijit/form/Select",
+ "dijit/form/TextBox",
+ "dijit/form/ToggleButton",
+ "dijit/layout/TabContainer",
+ "dijit/layout/ContentPane",
+ "dojox/layout/ResizeHandle",
+ "dojox/widget/Toaster",
+ "dojo/text!freeadmin/templates/volumemanager.html"
+ ], function(
+ array,
+ connect,
+ declare,
+ lang,
+ domAttr,
+ domConst,
+ domStyle,
+ json,
+ on,
+ query,
+ topic,
+ _Widget,
+ _Templated,
+ registry,
+ Tooltip,
+ Button,
+ CheckBox,
+ Form,
+ Select,
+ TextBox,
+ ToggleButton,
+ TabContainer,
+ ContentPane,
+ ResizeHandle,
+ Toaster,
+ template) {
+
+ var PER_NODE_WIDTH = 48;
+ var PER_NODE_HEIGHT = 26;
+
+ var Disk = declare("freeadmin.Disk", [ _Widget, _Templated ], {
+ templateString: '<div class="disk" style="width: 38px; height: 16px; text-align: center; float: left; background-color: #eee; border: 1px solid #ddd; margin: 2px; padding: 2px;">${name}</div>',
+ name: "",
+ serial: "",
+ size: "",
+ vdev: null,
+ manager: null,
+ postCreate: function() {
+ var me = this;
+ new Tooltip({
+ showDelay: 200,
+ connectId: [me.domNode],
+ label: "Size: " + me.size
+ //label: "Size: " + me.size + "<br />Serial: " + me.serial
+ });
+ on(this.domNode, "click", function() {
+ lang.hitch(me, me.onClick)();
+ });
+ },
+ addToRow: function(row) {
+ try {
+ row.validate(this);
+ var index = this.manager._avail_disks[this.size].indexOf(this);
+ this.manager._avail_disks[this.size].splice(index, 1);
+ this.domNode.parentNode.removeChild(this.domNode);
+ row.resize.domNode.parentNode.appendChild(this.domNode);
+ row.disks.push(this);
+ lang.hitch(this.manager, this.manager.drawAvailDisks)();
+ this.set('vdev', row);
+ this.manager._disksCheck(row);
+ } catch(e) {
+ var me = this;
+ connect.publish("volumeManager", {
+ message: e.message,
+ type: "fatal",
+ duration: 50
+ });
+
+ }
+ },
+ remove: function() {
+ this.manager._avail_disks[this.get("size")].push(this);
+ this.domNode.parentNode.removeChild(this.domNode);
+ this.vdev.disks.splice(this.vdev.disks.indexOf(this), 1);
+ lang.hitch(this.manager, this.manager.drawAvailDisks)();
+ this.manager._disksCheck(this.vdev);
+ this.set('vdev', null);
+ },
+ onClick: function() {
+ if(this.vdev === null) {
+ for(var key in this.manager._layout) {
+ var row = this.manager._layout[key];
+ var slots = lang.hitch(row.resize, row.resize.getSlots)();
+ if(slots > row.disks.length) {
+ this.addToRow(row);
+ break;
+ }
+ }
+ } else {
+ this.remove();
+ }
+ }
+ });
+
+ var Vdev = declare("freeadmin.Vdev", [ _Widget, _Templated ], {
+ templateString: '<tr><td data-dojo-attach-point="dapVdevType" style="width: 110px;"></td><td><div class="vdev" data-dojo-attach-point="dapResMain" style="width: 5px; position: relative;"><div data-dojo-attach-point="dapRes" style="position: absolute;"></div></div></td><td data-dojo-attach-point="dapNumCol"></td><td data-dojo-attach-point="dapDelete">Delete</td></tr>',
+ widgetsInTemplate: true,
+ numDisks: 0,
+ type: "",
+ disks: [],
+ initialDisks: [],
+ can_delete: false,
+ vdev: null,
+ manager: null,
+ validate: function(disk) {
+ var valid = true;
+ for(var key in this.disks) {
+ var each = this.disks[key];
+ if(each.size != disk.size) {
+ valid = false;
+ break;
+ }
+ }
+ if(valid === false) {
+ throw new Object({message: "Disk size mismatch"});
+ }
+ },
+ getChildren: function() {
+ // This needs investigating
+ // For some reason chidlren are not retrieved automatically
+ return [this.vdevtype, this.vdisks];
+ },
+ postCreate: function() {
+ var me = this;
+ this.disks = [];
+
+ this.vdevtype = new Select({
+ options: [
+ { label: "RaidZ", value: "raidz" },
+ { label: "RaidZ2", value: "raidz2" },
+ { label: "RaidZ3", value: "raidz3" },
+ { label: "Mirror", value: "mirror" },
+ { label: "Stripe", value: "stripe" },
+ { label: "Log (ZIL)", value: "log" },
+ { label: "Cache (L2ARC)", value: "cache" }
+ ],
+ }).placeAt(this.dapVdevType);
+ if(this.type) {
+ this.vdevtype.set('value', this.type);
+ }
+ this.vdevtype.startup();
+
+ this.vdisks = new _Widget();
+ this.dapResMain.appendChild(this.vdisks.domNode);
+
+ this.resize = new ResizeHandle({
+ targetContainer: this.dapResMain,
+ resizeAxis: "xy",
+ activeResize: false,
+ lastH: 0,
+ lastW: 0,
+ animateSizing: false, // Animated cause problem to get the size in onResize
+ intermediateChanges: true,
+ minHeight: 30,
+ minWidth: 30,
+ _disks: null,
+ _checkConstraints: function(newW, newH){
+ var availDisks = me.disks.length + me.manager.getAvailDisksNum();
+
+ var numRows = (newH / PER_NODE_HEIGHT);
+ var floorR = Math.floor(numRows);
+ if(numRows - floorR >= 0.5) {
+ floorR += 1;
+ }
+ if(floorR < 1) floorR = 1; // At least 1 row
+ newH = floorR * PER_NODE_HEIGHT;
+
+ var numNodes = newW / PER_NODE_WIDTH;
+ var floor = Math.floor(numNodes);
+ if(numNodes - floor >= 0.5) {
+ floor += 1;
+ }
+ if(floor < 0) floor = 0; // Non-negative disks
+ newW = floor * PER_NODE_WIDTH;
+
+ var disks = me.manager._disksForVdev(me, floor, floorR);
+
+ if(floor * floorR > availDisks || disks === null) {
+ newH = this.lastH;
+ newW = this.lastW;
+ } else {
+ if(this.lastH != newH || this.lastW != newW) {
+ me.manager._disksCheck(me, false, floor, floorR);
+ this.lastH = newH;
+ this.lastW = newW;
+ this._disks = disks;
+ }
+ }
+
+ return { w: newW, h: newH };
+ },
+ getSlots: function() {
+ var width = domStyle.get(this.domNode.parentNode, "width");
+ return Math.floor(width / PER_NODE_WIDTH);
+ },
+ onResize: function(e) {
+ if(this._disks !== null) {
+
+ /*
+ * We need to take care manipulating me.disks
+ * because disk.remove() will interact over the same
+ * structure
+ */
+ for(var i=0,j=0,len=me.disks.length;i<len;i++) {
+ var disk = me.disks[j];
+ var index = this._disks[0].indexOf(disk);
+ if(index == -1) {
+ disk.remove();
+ } else {
+ j++;
+ }
+ }
+ for(var i in this._disks[0]) {
+ var disk = this._disks[0][i];
+ var index = me.disks.indexOf(disk);
+ if(index == -1) {
+ disk.addToRow(me);
+ }
+ }
+
+ for(var i=1;i<this._disks.length;i++) {
+ var vdev = me.manager.addVdev({
+ can_delete: true,
+ initialDisks: this._disks[i],
+ type: me.vdevtype.get("value")
+ });
+ }
+ this._disks = null;
+ }
+ // Set back the original height size after selecting multiple rows
+ domStyle.set(this.targetDomNode, "height", PER_NODE_HEIGHT + "px");
+
+ me.manager._disksCheck(me);
+
+ lang.hitch(me.manager, me.manager.drawAvailDisks)();
+ }
+ }, this.dapRes);
+ domStyle.set(this.dapResMain, "height", PER_NODE_HEIGHT + "px");
+ this.resize.startup();
+
+ if(this.can_delete === true) {
+
+ on(this.dapDelete, "click", function() {
+ while(true) {
+ if(me.disks.length == 0) break;
+ me.disks[0].remove();
+ }
+ me.destroy();
+ });
+
+ } else {
+ domConst.destroy(this.dapDelete);
+ }
+
+ on(this.vdevtype, "change", function() {
+ if(this._stopEvent !== true) {
+ me.manager._disksCheck(me, true);
+ } else {
+ this._stopEvent = false;
+ }
+ });
+ this.manager._disksCheck(this);
+
+ if(this.numDisks !== undefined) {
+ for(var i=0;i<this.numDisks;i++) {
+ var disk = this.manager.popAvailDisk();
+ if(disk) {
+ disk.addToRow(this);
+ }
+ }
+ }
+
+ if(this.initialDisks.length > 0) {
+ for(var i in this.initialDisks) {
+ this.initialDisks[i].addToRow(this);
+ }
+ }
+
+ domStyle.set(this.resize.domNode.parentNode, "width", this.disks.length * PER_NODE_WIDTH + "px");
+
+ }
+ });
+
+ var VolumeManager = declare("freeadmin.VolumeManager", [ _Widget, _Templated ], {
+ templateString: template,
+ disks: "{}",
+ url: "",
+ url_progress: "",
+ dedup_warning: "",
+ extend: "",
+ add_label: 'Add Volume<br/ ><span style="color: red;">Existing data will be cleared</span>',
+ extend_label: "Extend Volume",
+ _layout: [],
+ _total_vdevs: null,
+ _initial_vdevs: null,
+ _form: null,
+ _avail_disks: [],
+ drawAvailDisks: function() {
+
+ domConst.empty(this.dapDisksTable);
+ for(var size in this._avail_disks) {
+ var tr = domConst.create("tr", null, this.dapDisksTable);
+ domStyle.set(tr, "height", (PER_NODE_HEIGHT + 2) + "px");
+ domConst.create("th", {innerHTML: size}, tr);
+ var td = domConst.create("td", null, tr);
+ var disks = this._avail_disks[size];
+ if(disks.length == 0) {
+ td.innerHTML = "<i>(all disks in use)</i>";
+ domStyle.set(td, "color", "#aaa");
+ }
+ for(var key in disks) {
+ var disk = disks[key];
+ td.appendChild(disk.domNode);
+ }
+ }
+ },
+ getAvailDisksNum: function() {
+ var num = 0;
+ for(var size in this._avail_disks) {
+ num += this._avail_disks[size].length;
+ }
+ return num;
+ },
+ popAvailDisk: function() {
+ var disk = null;
+ for(var size in this._avail_disks) {
+ for(var idx in this._avail_disks[size]) {
+ disk = this._avail_disks[size][idx];
+ break;
+ }
+ if(disk !== null) break;
+ }
+ return disk;
+ },
+ postCreate: function() {
+
+ var me = this, volume_name, volume_add, okbtn, enc, encini;
+
+ this._layout = [];
+
+ this.disks = json.parse(this.disks);
+ this.extend = json.parse(this.extend);
+
+ if(!gettext) {
+ gettext = function(s) { return s; }
+ }
+
+ this._form = new Form({}, this.dapForm);
+ this._form.startup();
+
+ new TextBox({
+ name: "__all__",
+ type: "hidden"
+ }, this.dapAll);
+
+ new TextBox({
+ name: "layout-__all__",
+ type: "hidden"
+ }, this.dapLayoutAll);
+
+ volume_name = new TextBox({
+ name: "volume_name",
+ onKeyUp: function() {
+ if(this.get('value') == '') {
+ volume_add.set('disabled', false);
+ } else {
+ volume_add.set('disabled', true);
+ }
+ }
+ }, this.dapName);
+
+ volume_add = new Select({
+ name: "volume_add",
+ options: this.extend,
+ value: "",
+ onChange: function(val) {
+ if(val != '') {
+ volume_name.set('disabled', true);
+ enc.set('disabled', true);
+ encini.set('disabled', true);
+ okbtn.set('label', me.extend_label);
+ } else {
+ volume_name.set('disabled', false);
+ enc.set('disabled', false);
+ encini.set('disabled', false);
+ okbtn.set('label', me.add_label);
+ }
+ }
+ }, this.dapExtend);
+
+ new Select({
+ name: "dedup",
+ options: [
+ { label: "On", value: "on" },
+ { label: "Off", value: "off" },
+ ],
+ value: "off"
+ }, this.dapDedup);
+
+ enc = new CheckBox({
+ name: "encryption"
+ }, this.dapDiskEnc);
+
+ encini = new CheckBox({
+ name: "encryption_inirand",
+ disabled: true
+ }, this.dapDiskEncIni);
+
+ on(enc, "click", function() {
+ if(this.get("value") == "on") {
+ encini.set('disabled', false);
+ } else {
+ encini.set('disabled', true);
+ }
+ });
+
+ this._avail_disks = {};
+ for(var size in this.disks) {
+ var disks = this.disks[size];
+ this._avail_disks[size] = [];
+ for(var key in disks) {
+ this._avail_disks[size].push(new Disk({
+ manager: this,
+ name: disks[key]['dev'],
+ size: size,
+ serial: disks[key]['serial']
+ }));
+ }
+ }
+
+ lang.hitch(this, this.drawAvailDisks)();
+
+ /*
+ * Add extra row for the layout
+ */
+ var add_extra = new Button({
+ label: "Add Extra Row"
+ }, this.dapLayoutAdd);
+ on(add_extra, "click", function(evt) {
+ lang.hitch(me, me.addVdev)({can_delete: true});
+ });
+
+ okbtn = new Button({
+ label: this.add_label,
+ onClick: function() {
+ lang.hitch(me, me.submit)();
+ }
+ }, this.dapAdd);
+
+ new Button({
+ label: "Cancel",
+ onClick: function() {
+ cancelDialog(this);
+ }
+ }, this.dapCancel);
+
+
+ /*
+ topic.subscribe("/dojo/resize/start", function(inst) {
+ console.log("here", inst);
+ });
+ topic.subscribe("/dojo/resize/stop", function(inst) {
+ console.log("here", inst);
+ });
+ */
+
+ this._total_vdevs = new _Widget({
+ name: "layout-TOTAL_FORMS",
+ value: 0
+ });
+ this._initial_vdevs = new _Widget({
+ name: "layout-INITIAL_FORMS",
+ value: 0
+ });
+ this._form.domNode.appendChild(this._total_vdevs.domNode);
+ this._form.domNode.appendChild(this._initial_vdevs.domNode);
+
+ new Toaster({
+ messageTopic: "volumeManager",
+ separator: "<hr/>",
+ positionDirection: "br-left",
+ duration: "0"
+ }, this.dapToaster);
+
+ this.addVdev({can_delete: false});
+
+ //this._supportingWidgets.push(slider);
+
+ this.inherited(arguments);
+
+ },
+ addVdev: function(attrs) {
+
+ var vdev;
+ attrs['manager'] = this;
+ vdev = new Vdev(attrs);
+ domConst.place(vdev.domNode, this.dapLayoutTable);
+
+ this._layout.push(vdev);
+ return vdev;
+
+ },
+ _disksForVdev: function(vdev, slots, rows) {
+
+ var disksrows = [];
+ // Clone all_disks from _avail_disks
+ var all_disks = {};
+ for(var size in this._avail_disks) {
+ all_disks[size] = [];
+ for(var i in this._avail_disks[size]) {
+ all_disks[size].push(this._avail_disks[size][i]);
+ }
+ }
+ // Add disks from current vdev to all_disks
+ if(vdev.disks.length > 0) {
+ for(var i in vdev.disks) {
+ var disk = vdev.disks[i];
+ all_disks[disk.size].push(disk);
+ }
+ }
+
+ for(var i=0;i<rows;i++) {
+
+ var disks = [];
+ // Find disks for the same size for a row
+ for(var size in all_disks) {
+ var bysize = all_disks[size];
+ if(bysize.length >= slots) {
+ disks = bysize.slice(0, slots);
+ bysize.splice(0, slots);
+ break;
+ }
+ }
+ /*
+ * If not enough disks of same size per vdev were found, abort all
+ */
+ if(disks.length > 0) {
+ disksrows.push(disks);
+ } else {
+ disksrows = null;
+ break;
+ }
+
+ }
+
+ return disksrows;
+
+ },
+ _optimalCheck: {
+ 'mirror': function(num) {
+ return num == 2;
+ },
+ 'raidz': function(num) {
+ if(num < 3) return false;
+ return (Math.log(num - 1) / Math.LN2) % 1 == 0;
+ },
+ 'raidz2': function(num) {
+ if(num < 4) return false;
+ return (Math.log(num - 2) / Math.LN2) % 1 == 0;
+ },
+ 'raidz3': function(num) {
+ if(num < 5) return false;
+ return (Math.log(num - 3) / Math.LN2) % 1 == 0;
+ }
+ },
+ _disksCheck: function(vdev, manual, cols, rows) {
+
+ var found = false, has_check = false, numdisks;
+ if(cols !== undefined) {
+ numdisks = cols;
+ } else {
+ numdisks = vdev.disks.length;
+ }
+
+ if(manual !== true) {
+ for(var key in this._optimalCheck) {
+ if(this._optimalCheck[key](numdisks)) {
+ // .set will trigger onChange, ignore it once
+ vdev.vdevtype._stopEvent = true;
+ vdev.vdevtype.set('value', key);
+ found = true;
+ has_check = true;
+ break;
+ }
+ }
+ if(found == false) {
+ var vdevtype = vdev.vdevtype.get("value");
+ has_check = this._optimalCheck[vdevtype] !== undefined;
+ }
+ } else {
+ var vdevtype = vdev.vdevtype.get("value");
+ var optimalf = this._optimalCheck[vdevtype];
+ if(optimalf !== undefined) {
+ found = optimalf(numdisks);
+ has_check = true;
+ }
+ }
+
+ if(rows !== undefined && rows > 1) {
+ rows = rows +'x ';
+ } else {
+ rows = '';
+ }
+ if(has_check) {
+ if(found) {
+ vdev.dapNumCol.innerHTML = rows + numdisks + ' disks; optimal';
+ } else {
+ vdev.dapNumCol.innerHTML = rows + numdisks + ' disks; non-optimal';
+ }
+ } else {
+ vdev.dapNumCol.innerHTML = rows + numdisks + ' disks';
+ }
+ },
+ submit: function() {
+ /*
+ * Set all field names for layout before submit
+ * It is easier than keep track of the fields on-the-fly
+ */
+ for(var i=0;i<this._layout.length;i++) {
+ var vdev = this._layout[i];
+ vdev.vdevtype.set('name', 'layout-' + i + '-vdevtype');
+ vdev.vdisks.set('name', 'layout-' + i + '-disks');
+ var disks = [];
+ for(var key in vdev.disks) {
+ disks.push(vdev.disks[key].get("name"));
+ }
+ vdev.vdisks.set('value', disks);
+ domAttr.set(vdev.vdisks.domNode.parentNode, "data-dojo-name", 'layout-' + i + '-disks');
+ }
+ this._total_vdevs.set('value', this._layout.length);
+ doSubmit({
+ url: this.url,
+ form: this._form,
+ progressbar: this.url_progress
+ });
+ }
+ });
+ return VolumeManager;
+});
Copied: projects/pluginjail/gui/freeadmin/static/lib/js/freeadmin/templates/volumemanager.html (from rev 13348, trunk/gui/freeadmin/static/lib/js/freeadmin/templates/volumemanager.html)
===================================================================
--- projects/pluginjail/gui/freeadmin/static/lib/js/freeadmin/templates/volumemanager.html (rev 0)
+++ projects/pluginjail/gui/freeadmin/static/lib/js/freeadmin/templates/volumemanager.html 2013-03-27 23:59:35 UTC (rev 13466)
@@ -0,0 +1,75 @@
+<div data-dojo-attach-point="dapManager">
+<form data-dojo-attach-point="dapForm">
+ <input type="hidden" data-dojo-attach-point="dapAll" />
+ <table>
+ <tr>
+ <th>Volume Name</th>
+ </tr>
+ <tr>
+ <td>
+ <input data-dojo-attach-point="dapName" type="text" />
+ </td>
+ </tr>
+ <tr>
+ <th>Volume to extend</th>
+ </tr>
+ <tr>
+ <td>
+ <select data-dojo-attach-point="dapExtend"></select>
+ </td>
+ </tr>
+ <tr>
+ <th>Enable full disk encryption</th>
+ </tr>
+ <tr>
+ <td>
+ <input data-dojo-attach-point="dapDiskEnc" type="checkbox" />
+ </td>
+ </tr>
+ <tr>
+ <th>Initialize disks with random data</th>
+ </tr>
+ <tr>
+ <td>
+ <input data-dojo-attach-point="dapDiskEncIni" type="checkbox" />
+ </td>
+ </tr>
+ <tr>
+ <th>Deduplication</th>
+ </tr>
+ <tr>
+ <td>
+ <p>${dedup_warning}</p>
+ <input data-dojo-attach-point="dapDedup" type="checkbox" />
+ </td>
+ </tr>
+ <tr>
+ <th>Available disks</th>
+ </tr>
+ <tr>
+ <td>
+ <div data-dojo-attach-point="dapDisks">
+ <table data-dojo-attach-point="dapDisksTable">
+ </table>
+ </div>
+ </td>
+ </tr>
+ <tr>
+ <th>Volume layout</th>
+ </tr>
+ <tr>
+ <td>
+ <div data-dojo-attach-point="dapLayout">
+ <input type="hidden" data-dojo-attach-point="dapLayoutAll" />
+ <table data-dojo-attach-point="dapLayoutTable">
+ </table>
+ <button data-dojo-attach-point="dapLayoutAdd" />
+ </div>
+ </td>
+ </tr>
+ <table>
+ <button data-dojo-attach-point="dapAdd" />
+ <button data-dojo-attach-point="dapCancel" />
+ <div data-dojo-attach-point="dapToaster"></div>
+</form>
+</div>
Modified: projects/pluginjail/gui/freeadmin/static/lib/js/freeadmin.js
===================================================================
--- projects/pluginjail/gui/freeadmin/static/lib/js/freeadmin.js 2013-03-27 05:41:04 UTC (rev 13465)
+++ projects/pluginjail/gui/freeadmin/static/lib/js/freeadmin.js 2013-03-27 23:59:35 UTC (rev 13466)
@@ -56,8 +56,9 @@
"freeadmin/tree/Tree",
"freeadmin/ESCDialog",
"freeadmin/Menu",
+ "freeadmin/RRDControl",
+ "freeadmin/VolumeManager",
"freeadmin/WebShell",
- "freeadmin/RRDControl",
"freeadmin/tree/TreeLazy",
"freeadmin/tree/JsonRestStore",
"freeadmin/tree/ForestStoreModel",
@@ -129,8 +130,9 @@
Tree,
ESCDialog,
fMenu,
+ RRDControl,
+ VolumeManager,
WebShell,
- RRDControl,
TreeLazy,
JsonRestStore,
ForestStoreModel,
@@ -535,18 +537,27 @@
domConstruct.destroy(item);
});
if(data.error == true) {
- var first = null;
- for(key in data.errors) {
+ var first, field, dom, node;
+ for(var key in data.errors) {
- field = query("input[name="+key+"],textarea[name="+key+"],select[name="+key+"]", form.domNode);
- if(field.length == 0) {
- console.log("Form element not found: ", key);
- continue;
+ dom = query("input[name="+key+"],textarea[name="+key+"],select[name="+key+"]", form.domNode);
+ if(dom.length == 0) {
+ dom = query("div[data-dojo-name="+key+"]", form.domNode);
+ if(dom.length != 0) {
+ node = dom[0];
+ } else {
+ console.log("Form element not found: ", key);
+ continue;
+ }
+ } else {
+ field = registry.getEnclosingWidget(dom[0]);
+ if(field) {
+ if(!first && field.focus)
+ first = field;
+ node = field.domNode;
+ }
}
- field = registry.getEnclosingWidget(field[0]);
- if(!first && field.focus)
- first = field;
- var ul = domConstruct.create('ul', {style: {display: "none"}}, field.domNode.parentNode, "first");
+ var ul = domConstruct.create('ul', {style: {display: "none"}}, node.parentNode, "first");
domAttr.set(ul, "class", "errorlist");
for(var i=0; i<data.errors[key].length;i++) {
var li = domConstruct.create('li', {innerHTML: data.errors[key][i]}, ul);
@@ -631,8 +642,10 @@
attrs = {};
}
- // prevent the default submit
- dEvent.stop(attrs.event);
+ if(attrs.event !== undefined) {
+ // prevent the default submit
+ dEvent.stop(attrs.event);
+ }
query('input[type=button],input[type=submit]', attrs.form.domNode).forEach(
function(inputElem){
Modified: projects/pluginjail/gui/freeadmin/utils.py
===================================================================
--- projects/pluginjail/gui/freeadmin/utils.py 2013-03-27 05:41:04 UTC (rev 13465)
+++ projects/pluginjail/gui/freeadmin/utils.py 2013-03-27 23:59:35 UTC (rev 13466)
@@ -27,7 +27,10 @@
import logging
from django.db.models import CASCADE
+from django.utils import translation
+from freenasUI.system.models import Settings
+
log = logging.getLogger('freeadmin.utils')
@@ -67,3 +70,8 @@
reldict[related.model._meta.verbose_name] = list(qs)
return reldict, relnum
+
+
+def set_language():
+ language = Settings.objects.order_by('-id')[0].stg_language
+ translation.activate(language)
Modified: projects/pluginjail/gui/freeadmin/views.py
===================================================================
--- projects/pluginjail/gui/freeadmin/views.py 2013-03-27 05:41:04 UTC (rev 13465)
+++ projects/pluginjail/gui/freeadmin/views.py 2013-03-27 23:59:35 UTC (rev 13466)
@@ -90,6 +90,11 @@
error = True
for name, fs in self.formsets.items():
+ fserrors = fs.non_form_errors()
+ if fserrors:
+ error = True
+ errors["%s-__all__" % name] = [unicode(e) for e in fserrors]
+
for i, form in enumerate(fs.forms):
if form.errors:
error = True
Modified: projects/pluginjail/gui/jails/urls.py
===================================================================
--- projects/pluginjail/gui/jails/urls.py 2013-03-27 05:41:04 UTC (rev 13465)
+++ projects/pluginjail/gui/jails/urls.py 2013-03-27 23:59:35 UTC (rev 13466)
@@ -25,7 +25,7 @@
#
#####################################################################
-from django.conf.urls.defaults import patterns, url
+from django.conf.urls import patterns, url
urlpatterns = patterns('freenasUI.jails.views',
url(r'^home/$', 'jails_home', name="jails_home"),
Modified: projects/pluginjail/gui/middleware/notifier.py
===================================================================
--- projects/pluginjail/gui/middleware/notifier.py 2013-03-27 05:41:04 UTC (rev 13465)
+++ projects/pluginjail/gui/middleware/notifier.py 2013-03-27 23:59:35 UTC (rev 13466)
@@ -1337,7 +1337,7 @@
want4khack = force4khack
- for name, vgrp in groups.items():
+ for vgrp in groups.values():
vgrp_type = vgrp['type']
if vgrp_type != 'stripe':
z_vdev += " " + vgrp_type
@@ -4334,26 +4334,37 @@
raise ValueError("Unknown disk %s" % (devname, ))
return self.__get_geoms_recursive(provid)
+ def _do_disk_wipe_quick(self, devname):
+ pipe = self.__pipeopen("dd if=/dev/zero of=/dev/%s bs=1m count=1" % (devname, ))
+ err = pipe.communicate()[1]
+ if pipe.returncode != 0:
+ raise MiddlewareError(
+ "Failed to wipe %s: %s" % (devname, err)
+ )
+ try:
+ p1 = self.__pipeopen("diskinfo %s" % (devname, ))
+ size = int(re.sub(r'\s+', ' ', p1.communicate()[0]).split()[2]) / (1024)
+ except:
+ log.error("Unable to determine size of %s", devname)
+ else:
+ pipe = self.__pipeopen("dd if=/dev/zero of=/dev/%s bs=1m oseek=%s" % (
+ devname,
+ size / 1024 - 4,
+ ))
+ pipe.communicate()
+
def disk_wipe(self, devname, mode='quick'):
if mode == 'quick':
+ doc = self.__geom_confxml()
+ parts = [node.content for node in doc.xpathEval("//class[name = 'PART']/geom[name = '%s']/provider/name" % devname)]
+ """
+ Wipe beginning and the end of every partition
+ This should erase ZFS label and such to prevent further errors on replace
+ """
+ for part in parts:
+ self._do_disk_wipe_quick(part)
self.__gpt_unlabeldisk(devname)
- pipe = self.__pipeopen("dd if=/dev/zero of=/dev/%s bs=1m count=1" % (devname, ))
- err = pipe.communicate()[1]
- if pipe.returncode != 0:
- raise MiddlewareError(
- "Failed to wipe %s: %s" % (devname, err)
- )
- try:
- p1 = self.__pipeopen("diskinfo %s" % (devname, ))
- size = int(re.sub(r'\s+', ' ', p1.communicate()[0]).split()[2]) / (1024)
- except:
- log.error("Unable to determine size of %s", devname)
- else:
- pipe = self.__pipeopen("dd if=/dev/zero of=/dev/%s bs=1m oseek=%s" % (
- devname,
- size / 1024 - 4,
- ))
- pipe.communicate()
+ self._do_disk_wipe_quick(devname)
elif mode in ('full', 'fullrandom'):
libc = ctypes.cdll.LoadLibrary("libc.so.7")
Modified: projects/pluginjail/gui/network/urls.py
===================================================================
--- projects/pluginjail/gui/network/urls.py 2013-03-27 05:41:04 UTC (rev 13465)
+++ projects/pluginjail/gui/network/urls.py 2013-03-27 23:59:35 UTC (rev 13466)
@@ -25,7 +25,7 @@
#
#####################################################################
-from django.conf.urls.defaults import patterns, url
+from django.conf.urls import patterns, url
urlpatterns = patterns('freenasUI.network.views',
url(r'^home/$', 'network', name='network_home'),
Modified: projects/pluginjail/gui/plugins/urls.py
===================================================================
--- projects/pluginjail/gui/plugins/urls.py 2013-03-27 05:41:04 UTC (rev 13465)
+++ projects/pluginjail/gui/plugins/urls.py 2013-03-27 23:59:35 UTC (rev 13466)
@@ -25,7 +25,7 @@
#
#####################################################################
-from django.conf.urls.defaults import patterns, url
+from django.conf.urls import patterns, url
from freenasUI.plugins.forms import (JailInstallWizard, JailUpdateWizard,
PBITemporaryLocationForm, JailInfoForm, JailPBIUploadForm)
Modified: projects/pluginjail/gui/reporting/urls.py
===================================================================
--- projects/pluginjail/gui/reporting/urls.py 2013-03-27 05:41:04 UTC (rev 13465)
+++ projects/pluginjail/gui/reporting/urls.py 2013-03-27 23:59:35 UTC (rev 13466)
@@ -25,7 +25,7 @@
#
#####################################################################
-from django.conf.urls.defaults import patterns, url
+from django.conf.urls import patterns, url
urlpatterns = patterns('freenasUI.reporting.views',
url(r'^$', 'index', name="reporting_index"),
Modified: projects/pluginjail/gui/services/forms.py
===================================================================
--- projects/pluginjail/gui/services/forms.py 2013-03-27 05:41:04 UTC (rev 13465)
+++ projects/pluginjail/gui/services/forms.py 2013-03-27 23:59:35 UTC (rev 13466)
@@ -73,6 +73,13 @@
except:
raise forms.ValidationError(_("This is not a valid mask"))
+ def clean_cifs_srv_workgroup(self):
+ netbios = self.cleaned_data.get("cifs_srv_netbiosname")
+ workgroup = self.cleaned_data.get("cifs_srv_workgroup").strip()
+ if netbios and netbios.lower() == workgroup.lower():
+ raise forms.ValidationError("NetBIOS and Workgroup must be unique")
+ return workgroup
+
def clean_cifs_srv_filemask(self):
v = self.cleaned_data.get("cifs_srv_filemask").strip()
self.__check_octet(v)
Copied: projects/pluginjail/gui/services/migrations/0087_auto__del_field_cifs_cifs_srv_largerw.py (from rev 13365, trunk/gui/services/migrations/0087_auto__del_field_cifs_cifs_srv_largerw.py)
===================================================================
--- projects/pluginjail/gui/services/migrations/0087_auto__del_field_cifs_cifs_srv_largerw.py (rev 0)
+++ projects/pluginjail/gui/services/migrations/0087_auto__del_field_cifs_cifs_srv_largerw.py 2013-03-27 23:59:35 UTC (rev 13466)
@@ -0,0 +1,361 @@
+# -*- coding: utf-8 -*-
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+ # Deleting field 'CIFS.cifs_srv_largerw'
+ db.delete_column('services_cifs', 'cifs_srv_largerw')
+
+
+ def backwards(self, orm):
+ # Adding field 'CIFS.cifs_srv_largerw'
+ db.add_column('services_cifs', 'cifs_srv_largerw',
+ self.gf('django.db.models.fields.BooleanField')(default=False),
+ keep_default=False)
+
+
+ models = {
+ 'services.activedirectory': {
+ 'Meta': {'object_name': 'ActiveDirectory'},
+ 'ad_adminname': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+ 'ad_adminpw': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+ 'ad_allow_trusted_doms': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'ad_dcname': ('django.db.models.fields.CharField', [], {'max_length': '120', 'blank': 'True'}),
+ 'ad_dns_timeout': ('django.db.models.fields.IntegerField', [], {'default': '10'}),
+ 'ad_domainname': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+ 'ad_gcname': ('django.db.models.fields.CharField', [], {'max_length': '120', 'blank': 'True'}),
+ 'ad_kpwdname': ('django.db.models.fields.CharField', [], {'max_length': '120', 'blank': 'True'}),
+ 'ad_krbname': ('django.db.models.fields.CharField', [], {'max_length': '120', 'blank': 'True'}),
+ 'ad_netbiosname': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+ 'ad_timeout': ('django.db.models.fields.IntegerField', [], {'default': '10'}),
+ 'ad_unix_extensions': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'ad_use_default_domain': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'ad_verbose_logging': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'ad_workgroup': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
+ },
+ 'services.afp': {
+ 'Meta': {'object_name': 'AFP'},
+ 'afp_srv_connections_limit': ('django.db.models.fields.IntegerField', [], {'default': '50', 'max_length': '120'}),
+ 'afp_srv_guest': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'afp_srv_guest_user': ('freenasUI.freeadmin.models.UserField', [], {'default': "'nobody'", 'max_length': '120'}),
+ 'afp_srv_name': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
+ },
+ 'services.cifs': {
+ 'Meta': {'object_name': 'CIFS'},
+ 'cifs_srv_aio_enable': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'cifs_srv_aio_rs': ('django.db.models.fields.IntegerField', [], {'default': '4096', 'max_length': '120'}),
+ 'cifs_srv_aio_ws': ('django.db.models.fields.IntegerField', [], {'default': '4096', 'max_length': '120'}),
+ 'cifs_srv_authmodel': ('django.db.models.fields.CharField', [], {'max_length': '10'}),
+ 'cifs_srv_description': ('django.db.models.fields.CharField', [], {'max_length': '120', 'blank': 'True'}),
+ 'cifs_srv_dirmask': ('django.db.models.fields.CharField', [], {'max_length': '120', 'blank': 'True'}),
+ 'cifs_srv_dosattr': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'cifs_srv_doscharset': ('django.db.models.fields.CharField', [], {'default': "'CP437'", 'max_length': '120'}),
+ 'cifs_srv_easupport': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'cifs_srv_filemask': ('django.db.models.fields.CharField', [], {'max_length': '120', 'blank': 'True'}),
+ 'cifs_srv_guest': ('freenasUI.freeadmin.models.UserField', [], {'default': "'nobody'", 'max_length': '120'}),
+ 'cifs_srv_homedir': ('freenasUI.freeadmin.models.PathField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'cifs_srv_homedir_aux': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'cifs_srv_homedir_browseable_enable': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'cifs_srv_homedir_enable': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'cifs_srv_hostlookup': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'cifs_srv_localmaster': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'cifs_srv_loglevel': ('django.db.models.fields.CharField', [], {'default': "'1'", 'max_length': '120'}),
+ 'cifs_srv_netbiosname': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+ 'cifs_srv_nullpw': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'cifs_srv_sendfile': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'cifs_srv_smb_options': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'cifs_srv_timeserver': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'cifs_srv_unixcharset': ('django.db.models.fields.CharField', [], {'default': "'UTF-8'", 'max_length': '120'}),
+ 'cifs_srv_unixext': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'cifs_srv_workgroup': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+ 'cifs_srv_zeroconf': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
+ },
+ 'services.dynamicdns': {
+ 'Meta': {'object_name': 'DynamicDNS'},
+ 'ddns_domain': ('django.db.models.fields.CharField', [], {'max_length': '120', 'blank': 'True'}),
+ 'ddns_fupdateperiod': ('django.db.models.fields.CharField', [], {'max_length': '120', 'blank': 'True'}),
+ 'ddns_options': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'ddns_password': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+ 'ddns_provider': ('django.db.models.fields.CharField', [], {'default': "'dyndns'", 'max_length': '120', 'blank': 'True'}),
+ 'ddns_updateperiod': ('django.db.models.fields.CharField', [], {'max_length': '120', 'blank': 'True'}),
+ 'ddns_username': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
+ },
+ 'services.ftp': {
+ 'Meta': {'object_name': 'FTP'},
+ 'ftp_anonpath': ('freenasUI.freeadmin.models.PathField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'ftp_anonuserbw': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'ftp_anonuserdlbw': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'ftp_banner': ('django.db.models.fields.TextField', [], {'max_length': '120', 'blank': 'True'}),
+ 'ftp_clients': ('django.db.models.fields.PositiveIntegerField', [], {'default': '32'}),
+ 'ftp_defaultroot': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'ftp_dirmask': ('django.db.models.fields.CharField', [], {'default': "'077'", 'max_length': '3'}),
+ 'ftp_filemask': ('django.db.models.fields.CharField', [], {'default': "'077'", 'max_length': '3'}),
+ 'ftp_fxp': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'ftp_ident': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'ftp_ipconnections': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'ftp_localuserbw': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'ftp_localuserdlbw': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'ftp_loginattempt': ('django.db.models.fields.PositiveIntegerField', [], {'default': '3'}),
+ 'ftp_masqaddress': ('django.db.models.fields.CharField', [], {'max_length': '120', 'blank': 'True'}),
+ 'ftp_onlyanonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'ftp_onlylocal': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'ftp_options': ('django.db.models.fields.TextField', [], {'max_length': '120', 'blank': 'True'}),
+ 'ftp_passiveportsmax': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'ftp_passiveportsmin': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'ftp_port': ('django.db.models.fields.PositiveIntegerField', [], {'default': '21'}),
+ 'ftp_resume': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'ftp_reversedns': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'ftp_rootlogin': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'ftp_ssltls': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'ftp_ssltls_certfile': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'ftp_timeout': ('django.db.models.fields.PositiveIntegerField', [], {'default': '120'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
+ },
+ 'services.iscsitarget': {
+ 'Meta': {'object_name': 'iSCSITarget'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'iscsi_target_alias': ('django.db.models.fields.CharField', [], {'max_length': '120', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'iscsi_target_authgroup': ('django.db.models.fields.IntegerField', [], {'max_length': '120', 'null': 'True', 'blank': 'True'}),
+ 'iscsi_target_authtype': ('django.db.models.fields.CharField', [], {'default': "'Auto'", 'max_length': '120'}),
+ 'iscsi_target_flags': ('django.db.models.fields.CharField', [], {'default': "'rw'", 'max_length': '120'}),
+ 'iscsi_target_initialdigest': ('django.db.models.fields.CharField', [], {'default': "'Auto'", 'max_length': '120'}),
+ 'iscsi_target_initiatorgroup': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['services.iSCSITargetAuthorizedInitiator']"}),
+ 'iscsi_target_logical_blocksize': ('django.db.models.fields.IntegerField', [], {'default': '512', 'max_length': '3'}),
+ 'iscsi_target_name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '120'}),
+ 'iscsi_target_portalgroup': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['services.iSCSITargetPortal']"}),
+ 'iscsi_target_queue_depth': ('django.db.models.fields.IntegerField', [], {'default': '32', 'max_length': '3'}),
+ 'iscsi_target_serial': ('django.db.models.fields.CharField', [], {'default': "'10000001'", 'max_length': '16'}),
+ 'iscsi_target_type': ('django.db.models.fields.CharField', [], {'default': "'Disk'", 'max_length': '120'})
+ },
+ 'services.iscsitargetauthcredential': {
+ 'Meta': {'object_name': 'iSCSITargetAuthCredential'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'iscsi_target_auth_peersecret': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+ 'iscsi_target_auth_peeruser': ('django.db.models.fields.CharField', [], {'max_length': '120', 'blank': 'True'}),
+ 'iscsi_target_auth_secret': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+ 'iscsi_target_auth_tag': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'iscsi_target_auth_user': ('django.db.models.fields.CharField', [], {'max_length': '120'})
+ },
+ 'services.iscsitargetauthorizedinitiator': {
+ 'Meta': {'object_name': 'iSCSITargetAuthorizedInitiator'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'iscsi_target_initiator_auth_network': ('django.db.models.fields.TextField', [], {'default': "'ALL'", 'max_length': '2048'}),
+ 'iscsi_target_initiator_comment': ('django.db.models.fields.CharField', [], {'max_length': '120', 'blank': 'True'}),
+ 'iscsi_target_initiator_initiators': ('django.db.models.fields.TextField', [], {'default': "'ALL'", 'max_length': '2048'}),
+ 'iscsi_target_initiator_tag': ('django.db.models.fields.IntegerField', [], {'default': '1', 'unique': 'True'})
+ },
+ 'services.iscsitargetextent': {
+ 'Meta': {'ordering': "['iscsi_target_extent_name']", 'object_name': 'iSCSITargetExtent'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'iscsi_target_extent_comment': ('django.db.models.fields.CharField', [], {'max_length': '120', 'blank': 'True'}),
+ 'iscsi_target_extent_filesize': ('django.db.models.fields.CharField', [], {'default': '0', 'max_length': '120'}),
+ 'iscsi_target_extent_name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '120'}),
+ 'iscsi_target_extent_path': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+ 'iscsi_target_extent_type': ('django.db.models.fields.CharField', [], {'max_length': '120'})
+ },
+ 'services.iscsitargetglobalconfiguration': {
+ 'Meta': {'object_name': 'iSCSITargetGlobalConfiguration'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'iscsi_basename': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+ 'iscsi_defaultt2r': ('django.db.models.fields.IntegerField', [], {'default': '60', 'max_length': '120'}),
+ 'iscsi_defaultt2w': ('django.db.models.fields.IntegerField', [], {'default': '2', 'max_length': '120'}),
+ 'iscsi_discoveryauthgroup': ('django.db.models.fields.IntegerField', [], {'max_length': '120', 'null': 'True', 'blank': 'True'}),
+ 'iscsi_discoveryauthmethod': ('django.db.models.fields.CharField', [], {'default': "'Auto'", 'max_length': '120'}),
+ 'iscsi_firstburst': ('django.db.models.fields.IntegerField', [], {'default': '65536', 'max_length': '120'}),
+ 'iscsi_iotimeout': ('django.db.models.fields.IntegerField', [], {'default': '30', 'max_length': '120'}),
+ 'iscsi_luc_authgroup': ('django.db.models.fields.IntegerField', [], {'max_length': '120', 'null': 'True', 'blank': 'True'}),
+ 'iscsi_luc_authmethod': ('django.db.models.fields.CharField', [], {'default': "'chap'", 'max_length': '120', 'blank': 'True'}),
+ 'iscsi_luc_authnetwork': ('django.db.models.fields.CharField', [], {'default': "'127.0.0.0/8'", 'max_length': '120', 'blank': 'True'}),
+ 'iscsi_lucip': ('django.db.models.fields.IPAddressField', [], {'default': "'127.0.0.1'", 'max_length': '15', 'null': 'True', 'blank': 'True'}),
+ 'iscsi_lucport': ('django.db.models.fields.IntegerField', [], {'default': '3261', 'null': 'True', 'blank': 'True'}),
+ 'iscsi_maxburst': ('django.db.models.fields.IntegerField', [], {'default': '262144', 'max_length': '120'}),
+ 'iscsi_maxconnect': ('django.db.models.fields.IntegerField', [], {'default': '8', 'max_length': '120'}),
+ 'iscsi_maxoutstandingr2t': ('django.db.models.fields.IntegerField', [], {'default': '16', 'max_length': '120'}),
+ 'iscsi_maxrecdata': ('django.db.models.fields.IntegerField', [], {'default': '262144', 'max_length': '120'}),
+ 'iscsi_maxsesh': ('django.db.models.fields.IntegerField', [], {'default': '16', 'max_length': '120'}),
+ 'iscsi_nopinint': ('django.db.models.fields.IntegerField', [], {'default': '20', 'max_length': '120'}),
+ 'iscsi_r2t': ('django.db.models.fields.IntegerField', [], {'default': '32', 'max_length': '120'}),
+ 'iscsi_toggleluc': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'services.iscsitargetportal': {
+ 'Meta': {'object_name': 'iSCSITargetPortal'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'iscsi_target_portal_comment': ('django.db.models.fields.CharField', [], {'max_length': '120', 'blank': 'True'}),
+ 'iscsi_target_portal_tag': ('django.db.models.fields.IntegerField', [], {'default': '1', 'max_length': '120'})
+ },
+ 'services.iscsitargetportalip': {
+ 'Meta': {'unique_together': "(('iscsi_target_portalip_ip', 'iscsi_target_portalip_port'),)", 'object_name': 'iSCSITargetPortalIP'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'iscsi_target_portalip_ip': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),
+ 'iscsi_target_portalip_port': ('django.db.models.fields.SmallIntegerField', [], {'default': '3260'}),
+ 'iscsi_target_portalip_portal': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['services.iSCSITargetPortal']"})
+ },
+ 'services.iscsitargettoextent': {
+ 'Meta': {'object_name': 'iSCSITargetToExtent'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'iscsi_extent': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['services.iSCSITargetExtent']", 'unique': 'True'}),
+ 'iscsi_target': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['services.iSCSITarget']"})
+ },
+ 'services.ldap': {
+ 'Meta': {'object_name': 'LDAP'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ldap_anonbind': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'ldap_basedn': ('django.db.models.fields.CharField', [], {'max_length': '120', 'blank': 'True'}),
+ 'ldap_groupsuffix': ('django.db.models.fields.CharField', [], {'max_length': '120', 'blank': 'True'}),
+ 'ldap_hostname': ('django.db.models.fields.CharField', [], {'max_length': '120', 'blank': 'True'}),
+ 'ldap_machinesuffix': ('django.db.models.fields.CharField', [], {'max_length': '120', 'blank': 'True'}),
+ 'ldap_options': ('django.db.models.fields.TextField', [], {'max_length': '120', 'blank': 'True'}),
+ 'ldap_passwordsuffix': ('django.db.models.fields.CharField', [], {'max_length': '120', 'blank': 'True'}),
+ 'ldap_pwencryption': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+ 'ldap_rootbasedn': ('django.db.models.fields.CharField', [], {'max_length': '120', 'blank': 'True'}),
+ 'ldap_rootbindpw': ('django.db.models.fields.CharField', [], {'max_length': '120', 'blank': 'True'}),
+ 'ldap_ssl': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+ 'ldap_tls_cacertfile': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'ldap_usersuffix': ('django.db.models.fields.CharField', [], {'max_length': '120', 'blank': 'True'})
+ },
+ 'services.nfs': {
+ 'Meta': {'object_name': 'NFS'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'nfs_srv_allow_nonroot': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'nfs_srv_async': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'nfs_srv_bindip': ('django.db.models.fields.CharField', [], {'max_length': '250', 'blank': 'True'}),
+ 'nfs_srv_servers': ('django.db.models.fields.PositiveIntegerField', [], {'default': '4'})
+ },
+ 'services.nis': {
+ 'Meta': {'object_name': 'NIS'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'nis_domain': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+ 'nis_manycast': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'nis_secure_mode': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'nis_servers': ('django.db.models.fields.CharField', [], {'max_length': '8192', 'blank': 'True'})
+ },
+ 'services.nt4': {
+ 'Meta': {'object_name': 'NT4'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'nt4_adminname': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+ 'nt4_adminpw': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+ 'nt4_dcname': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+ 'nt4_netbiosname': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+ 'nt4_workgroup': ('django.db.models.fields.CharField', [], {'max_length': '120'})
+ },
+ 'services.pluginsjail': {
+ 'Meta': {'object_name': 'PluginsJail'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'jail_ipv4address': ('freenasUI.contrib.IPAddressField.IPAddressField', [], {}),
+ 'jail_ipv4netmask': ('django.db.models.fields.CharField', [], {'max_length': '3'}),
+ 'jail_mac': ('freenasUI.freeadmin.models.MACField', [], {'default': "''", 'max_length': '17', 'blank': 'True'}),
+ 'jail_name': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '120'}),
+ 'jail_path': ('freenasUI.freeadmin.models.PathField', [], {'max_length': '255'}),
+ 'plugins_path': ('freenasUI.freeadmin.models.PathField', [], {'max_length': '255'})
+ },
+ 'services.rpctoken': {
+ 'Meta': {'object_name': 'RPCToken'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'key': ('django.db.models.fields.CharField', [], {'max_length': '1024'}),
+ 'secret': ('django.db.models.fields.CharField', [], {'max_length': '1024'})
+ },
+ 'services.rsyncd': {
+ 'Meta': {'object_name': 'Rsyncd'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'rsyncd_auxiliary': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'rsyncd_port': ('django.db.models.fields.IntegerField', [], {'default': '873'})
+ },
+ 'services.rsyncmod': {
+ 'Meta': {'ordering': "['rsyncmod_name']", 'object_name': 'RsyncMod'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'rsyncmod_auxiliary': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'rsyncmod_comment': ('django.db.models.fields.CharField', [], {'max_length': '120', 'blank': 'True'}),
+ 'rsyncmod_group': ('freenasUI.freeadmin.models.GroupField', [], {'default': "'nobody'", 'max_length': '120', 'blank': 'True'}),
+ 'rsyncmod_hostsallow': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'rsyncmod_hostsdeny': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'rsyncmod_maxconn': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'rsyncmod_mode': ('django.db.models.fields.CharField', [], {'default': "'rw'", 'max_length': '120'}),
+ 'rsyncmod_name': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+ 'rsyncmod_path': ('freenasUI.freeadmin.models.PathField', [], {'max_length': '255'}),
+ 'rsyncmod_user': ('freenasUI.freeadmin.models.UserField', [], {'default': "'nobody'", 'max_length': '120', 'blank': 'True'})
+ },
+ 'services.services': {
+ 'Meta': {'object_name': 'services'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'srv_enable': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'srv_service': ('django.db.models.fields.CharField', [], {'max_length': '120'})
+ },
+ 'services.smart': {
+ 'Meta': {'object_name': 'SMART'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'smart_critical': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'smart_difference': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'smart_email': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
+ 'smart_informal': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'smart_interval': ('django.db.models.fields.IntegerField', [], {'default': '30'}),
+ 'smart_powermode': ('django.db.models.fields.CharField', [], {'default': "'never'", 'max_length': '60'})
+ },
+ 'services.snmp': {
+ 'Meta': {'object_name': 'SNMP'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'snmp_community': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+ 'snmp_contact': ('django.db.models.fields.CharField', [], {'max_length': '120', 'blank': 'True'}),
+ 'snmp_location': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
+ 'snmp_options': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'snmp_traps': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'services.ssh': {
+ 'Meta': {'object_name': 'SSH'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ssh_compression': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'ssh_host_dsa_key': ('django.db.models.fields.TextField', [], {'max_length': '1024', 'null': 'True', 'blank': 'True'}),
+ 'ssh_host_dsa_key_pub': ('django.db.models.fields.TextField', [], {'max_length': '1024', 'null': 'True', 'blank': 'True'}),
+ 'ssh_host_ecdsa_key': ('django.db.models.fields.TextField', [], {'max_length': '1024', 'null': 'True', 'blank': 'True'}),
+ 'ssh_host_ecdsa_key_pub': ('django.db.models.fields.TextField', [], {'max_length': '1024', 'null': 'True', 'blank': 'True'}),
+ 'ssh_host_key': ('django.db.models.fields.TextField', [], {'max_length': '1024', 'null': 'True', 'blank': 'True'}),
+ 'ssh_host_key_pub': ('django.db.models.fields.TextField', [], {'max_length': '1024', 'null': 'True', 'blank': 'True'}),
+ 'ssh_host_rsa_key': ('django.db.models.fields.TextField', [], {'max_length': '1024', 'null': 'True', 'blank': 'True'}),
+ 'ssh_host_rsa_key_pub': ('django.db.models.fields.TextField', [], {'max_length': '1024', 'null': 'True', 'blank': 'True'}),
+ 'ssh_options': ('django.db.models.fields.TextField', [], {'max_length': '120', 'blank': 'True'}),
+ 'ssh_passwordauth': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'ssh_privatekey': ('django.db.models.fields.TextField', [], {'max_length': '1024', 'blank': 'True'}),
+ 'ssh_rootlogin': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'ssh_sftp_log_facility': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}),
+ 'ssh_sftp_log_level': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}),
+ 'ssh_tcpfwd': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'ssh_tcpport': ('django.db.models.fields.PositiveIntegerField', [], {})
+ },
+ 'services.tftp': {
+ 'Meta': {'object_name': 'TFTP'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'tftp_directory': ('freenasUI.freeadmin.models.PathField', [], {'max_length': '255'}),
+ 'tftp_newfiles': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'tftp_options': ('django.db.models.fields.CharField', [], {'max_length': '120', 'blank': 'True'}),
+ 'tftp_port': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'tftp_umask': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+ 'tftp_username': ('freenasUI.freeadmin.models.UserField', [], {'default': "'nobody'", 'max_length': '120'})
+ },
+ 'services.ups': {
+ 'Meta': {'object_name': 'UPS'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ups_description': ('django.db.models.fields.CharField', [], {'max_length': '120', 'blank': 'True'}),
+ 'ups_driver': ('django.db.models.fields.CharField', [], {'max_length': '120', 'blank': 'True'}),
+ 'ups_emailnotify': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'ups_extrausers': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'ups_identifier': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+ 'ups_masterpwd': ('django.db.models.fields.CharField', [], {'default': "'fixmepass'", 'max_length': '30'}),
+ 'ups_options': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'ups_port': ('django.db.models.fields.CharField', [], {'max_length': '120', 'blank': 'True'}),
+ 'ups_rmonitor': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'ups_shutdown': ('django.db.models.fields.CharField', [], {'default': "'batt'", 'max_length': '120'}),
+ 'ups_shutdowntimer': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+ 'ups_subject': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+ 'ups_toemail': ('django.db.models.fields.CharField', [], {'max_length': '120', 'blank': 'True'})
+ }
+ }
+
+ complete_apps = ['services']
\ No newline at end of file
Modified: projects/pluginjail/gui/services/models.py
===================================================================
--- projects/pluginjail/gui/services/models.py 2013-03-27 05:41:04 UTC (rev 13465)
+++ projects/pluginjail/gui/services/models.py 2013-03-27 23:59:35 UTC (rev 13466)
@@ -26,6 +26,7 @@
#####################################################################
import hashlib
import hmac
+import logging
import uuid
from django.db import models
@@ -41,7 +42,9 @@
from freenasUI.services.exceptions import ServiceFailed
from freenasUI.storage.models import Volume, Disk
+log = logging.getLogger("services.forms")
+
class services(Model):
srv_service = models.CharField(
max_length=120,
@@ -136,8 +139,6 @@
help_text=_("Use this option to override the directory creation "
"mask (0777 by default).")
)
- cifs_srv_largerw = models.BooleanField(
- verbose_name=_("Large RW support"))
cifs_srv_sendfile = models.BooleanField(
verbose_name=_("Send files with sendfile(2)"))
cifs_srv_easupport = models.BooleanField(
@@ -511,10 +512,7 @@
disk = Disk.objects.get(id=self.iscsi_target_extent_path)
if self.iscsi_target_extent_type == "Disk":
devname = disk.identifier_to_device()
- if devname:
- notifier().unlabel_disk(disk.identifier_to_device())
- notifier().sync_disk(devname)
- else:
+ if not devname:
disk.disk_enabled = False
disk.save()
expected_iscsi_volume_name = 'iscsi:%s' % (
@@ -522,8 +520,8 @@
)
vol = Volume.objects.get(vol_name=expected_iscsi_volume_name)
vol.delete()
- except:
- pass
+ except Exception, e:
+ log.error("Unable to sync of iSCSI extent delete: %s", e)
for te in iSCSITargetToExtent.objects.filter(iscsi_extent=self):
te.delete()
Modified: projects/pluginjail/gui/services/urls.py
===================================================================
--- projects/pluginjail/gui/services/urls.py 2013-03-27 05:41:04 UTC (rev 13465)
+++ projects/pluginjail/gui/services/urls.py 2013-03-27 23:59:35 UTC (rev 13466)
@@ -25,7 +25,7 @@
#
#####################################################################
-from django.conf.urls.defaults import patterns, url
+from django.conf.urls import patterns, url
urlpatterns = patterns('freenasUI.services.views',
url(r'^index/$', 'index', name="services_home"),
Modified: projects/pluginjail/gui/sharing/forms.py
===================================================================
--- projects/pluginjail/gui/sharing/forms.py 2013-03-27 05:41:04 UTC (rev 13465)
+++ projects/pluginjail/gui/sharing/forms.py 2013-03-27 23:59:35 UTC (rev 13466)
@@ -112,6 +112,14 @@
)
if self.instance.id:
self.fields['afp_sharepw2'].initial = self.instance.afp_sharepw
+ if self.instance.afp_sharepw:
+ self.fields['afp_deletepw'] = forms.BooleanField(
+ label=_("Delete password"),
+ initial=False,
+ required=False,
+ )
+ self.fields.keyOrder.remove('afp_deletepw')
+ self.fields.keyOrder.insert(5, 'afp_deletepw')
if not self.instance.afp_upriv:
self.fields['afp_fperm'].widget.attrs['disabled'] = 'true'
self.fields['afp_dperm'].widget.attrs['disabled'] = 'true'
@@ -130,7 +138,7 @@
def clean(self):
cdata = self.cleaned_data
- if not cdata.get("afp_sharepw"):
+ if not cdata.get("afp_sharepw") and not cdata.get("afp_deletepw"):
cdata['afp_sharepw'] = self.instance.afp_sharepw
return cdata
Modified: projects/pluginjail/gui/sharing/urls.py
===================================================================
--- projects/pluginjail/gui/sharing/urls.py 2013-03-27 05:41:04 UTC (rev 13465)
+++ projects/pluginjail/gui/sharing/urls.py 2013-03-27 23:59:35 UTC (rev 13466)
@@ -25,7 +25,7 @@
#
#####################################################################
-from django.conf.urls.defaults import patterns, url
+from django.conf.urls import patterns, url
urlpatterns = patterns('freenasUI.sharing.views',
url(r'^home/$', 'home', name="sharing_home"),
Modified: projects/pluginjail/gui/storage/forms.py
===================================================================
--- projects/pluginjail/gui/storage/forms.py 2013-03-27 05:41:04 UTC (rev 13465)
+++ projects/pluginjail/gui/storage/forms.py 2013-03-27 23:59:35 UTC (rev 13466)
@@ -39,6 +39,7 @@
from django.core.files.storage import FileSystemStorage
from django.db import transaction
from django.forms import FileField
+from django.forms.formsets import BaseFormSet
from django.http import HttpResponse, QueryDict
from django.utils.safestring import mark_safe
from django.utils.translation import ugettext_lazy as _, ungettext
@@ -135,7 +136,20 @@
return cdata
-class VolumeWizardForm(forms.Form):
+class VolumeMixin(object):
+
+ def clean_volume_name(self):
+ vname = self.cleaned_data['volume_name']
+ if vname and not re.search(r'^[a-z][-_.a-z0-9]*$', vname, re.I):
+ raise forms.ValidationError(_("The volume name must start with "
+ "letters and may include numbers, \"-\", \"_\" and \".\" ."))
+ if models.Volume.objects.filter(vol_name=vname).exists():
+ raise forms.ValidationError(_("A volume with that name already "
+ "exists."))
+ return vname
+
+
+class VolumeWizardForm(forms.Form, VolumeMixin):
volume_name = forms.CharField(
max_length=30,
label=_('Volume name'),
@@ -252,16 +266,6 @@
choices = [tuple(d) for d in choices]
return choices
- def clean_volume_name(self):
- vname = self.cleaned_data['volume_name']
- if vname and not re.search(r'^[a-z][-_.a-z0-9]*$', vname, re.I):
- raise forms.ValidationError(_("The volume name must start with "
- "letters and may include numbers, \"-\", \"_\" and \".\" ."))
- if models.Volume.objects.filter(vol_name=vname).exists():
- raise forms.ValidationError(_("A volume with that name already "
- "exists."))
- return vname
-
def clean_group_type(self):
len_disks = len(self.cleaned_data['volume_disks'])
if 'volume_disks' not in self.cleaned_data or \
@@ -319,7 +323,7 @@
)
if not force_vdev:
errors.append(
- _("You're trying to add a virtual device of type "
+ _("You are trying to add a virtual device of type "
"'%(addtype)s' in a pool that has a virtual "
"device of type '%(vdevtype)s'") % {
'addtype': self.cleaned_data.get('group_type'),
@@ -335,9 +339,9 @@
)
if not force_vdev:
errors.append(
- _("You're trying to add a virtual device consisted"
- " of %(addnum)s devices in a pool that has a "
- "virtual device consisted of %(vdevnum)s devices"
+ _("You are trying to add a virtual device consisting"
+ " of %(addnum)s device(s) in a pool that has a "
+ "virtual device consisted of %(vdevnum)s device(s)"
) % {
'addnum': len(disks),
'vdevnum': len(list(iter(vdev))),
@@ -504,6 +508,170 @@
notifier().restart("cron")
+class VolumeManagerForm(VolumeMixin, forms.Form):
+ volume_name = forms.CharField(
+ max_length=30,
+ required=False)
+ volume_add = forms.CharField(
+ max_length=30,
+ required=False)
+ encryption = forms.BooleanField(
+ required=False,
+ initial=False,
+ )
+ encryption_inirand = forms.BooleanField(
+ initial=False,
+ required=False,
+ )
+ dedup = forms.ChoiceField(
+ choices=choices.ZFS_DEDUP,
+ initial="off",
+ )
+
+ def clean(self):
+ vname = (
+ self.cleaned_data.get("volume_name") or
+ self.cleaned_data.get("volume_add")
+ )
+ if not vname:
+ self._errors['__all__'] = self.error_class([
+ _("You must specify a new volume name or select an existing "
+ "ZFS volume to append a virtual device"),
+ ])
+ else:
+ self.cleaned_data["volume_name"] = vname
+ return self.cleaned_data
+
+ def done(self, formset):
+ volume_name = self.cleaned_data.get("volume_name")
+ init_rand = self.cleaned_data.get("encryption_inirand", False)
+ if self.cleaned_data.get("encryption", False):
+ volume_encrypt = 1
+ else:
+ volume_encrypt = 0
+ dedup = self.cleaned_data.get("dedup", False)
+ force4khack = True
+
+ with transaction.commit_on_success():
+ vols = models.Volume.objects.filter(
+ vol_name=volume_name,
+ vol_fstype='ZFS')
+ if vols.count() > 0:
+ volume = vols[0]
+ add = True
+ else:
+ add = False
+ volume = models.Volume(
+ vol_name=volume_name,
+ vol_fstype='ZFS',
+ vol_encrypt=volume_encrypt)
+ volume.save()
+
+ mp = models.MountPoint(
+ mp_volume=volume,
+ mp_path='/mnt/' + volume_name,
+ mp_options="rw",
+ )
+ mp.save()
+ self.volume = volume
+
+ grouped = OrderedDict()
+ #FIXME: Make log as log mirror
+ for i, form in enumerate(formset):
+ grouped[i] = {
+ 'type': form.cleaned_data.get("vdevtype"),
+ 'disks': form.cleaned_data.get("disks"),
+ }
+
+ if add:
+ for gtype, group in grouped.items():
+ notifier().zfs_volume_attach_group(
+ volume,
+ group,
+ force4khack=force4khack)
+
+ else:
+ notifier().init(
+ "volume",
+ volume,
+ groups=grouped,
+ force4khack=force4khack,
+ init_rand=init_rand,
+ )
+
+ if dedup:
+ notifier().zfs_set_option(volume.vol_name, "dedup", dedup)
+
+ if volume.vol_fstype == 'ZFS':
+ models.Scrub.objects.create(scrub_volume=volume)
+
+ # This must be outside transaction block to make sure the changes
+ # are committed before the call of ix-fstab
+ notifier().reload("disk")
+ # For scrub cronjob
+ if volume.vol_fstype == 'ZFS':
+ notifier().restart("cron")
+
+ return True
+
+
+class VolumeVdevForm(forms.Form):
+ vdevtype = forms.CharField(
+ max_length=20,
+ )
+ disks = forms.CharField(
+ max_length=100,
+ widget=forms.widgets.SelectMultiple(),
+ )
+
+ def clean_disks(self):
+ vdev = self.cleaned_data.get("vdevtype")
+ #TODO: Safe?
+ disks = eval(self.cleaned_data.get("disks"))
+ errmsg = _("You need at least %d disks")
+ if vdev == "mirror" and len(disks) < 2:
+ raise forms.ValidationError(errmsg % 2)
+ elif vdev == "raidz" and len(disks) < 3:
+ raise forms.ValidationError(errmsg % 3)
+ elif vdev == "raidz2" and len(disks) < 4:
+ raise forms.ValidationError(errmsg % 4)
+ elif vdev == "raidz3" and len(disks) < 5:
+ raise forms.ValidationError(errmsg % 5)
+ return disks
+
+ def clean(self):
+ if (
+ self.cleaned_data.get("vdevtype") == "log"
+ and
+ len(self.cleaned_data.get("disks")) > 1
+ ):
+ self.cleaned_data["vdevtype"] = "log mirror"
+ return self.cleaned_data
+
+
+class VdevFormSet(BaseFormSet):
+
+ def clean(self):
+ if any(self.errors):
+ # Don't bother validating the formset unless each form
+ # is valid on its own
+ return
+
+ """
+ We need to make sure at least one vdev is a
+ data vdev (non-log/cache/spare)
+ """
+ has_datavdev = False
+ for i in range(0, self.total_form_count()):
+ form = self.forms[i]
+ vdevtype = form.cleaned_data['vdevtype']
+ if vdevtype in ('mirror', 'stripe', 'raidz', 'raidz2', 'raidz3'):
+ has_datavdev = True
+ break
+ if not has_datavdev:
+ raise forms.ValidationError("You need a storage vdev")
+
+
class VolumeImportForm(forms.Form):
volume_name = forms.CharField(max_length=30, label=_('Volume name'))
Modified: projects/pluginjail/gui/storage/urls.py
===================================================================
--- projects/pluginjail/gui/storage/urls.py 2013-03-27 05:41:04 UTC (rev 13465)
+++ projects/pluginjail/gui/storage/urls.py 2013-03-27 23:59:35 UTC (rev 13466)
@@ -25,7 +25,7 @@
#
#####################################################################
-from django.conf.urls.defaults import patterns, url
+from django.conf.urls import patterns, url
from freenasUI.storage.forms import (
AutoImportWizard, VolumeAutoImportForm, AutoImportChoiceForm,
@@ -53,6 +53,7 @@
url(r'^snapshot/create/(?P<fs>[\-a-zA-Z0-9_/\.:]+)/$', 'manualsnap', name="storage_manualsnap"),
url(r'^snapshot/clone/(?P<snapshot>[\-a-zA-Z0-9_/\.:]+@[\-a-zA-Z0-9_\.:]+)/$', 'clonesnap', name="storage_clonesnap"),
url(r'^mountpoint/permission/(?P<path>.+)/$', 'mp_permission', name="storage_mp_permission"),
+ url(r'^volumemanager/$', 'volumemanager', name="storage_volumemanager"),
url(r'^wizard/$', 'wizard', name="storage_wizard"),
url(r'^wizard/progress/$', 'wizard_progress', name="storage_wizard_progress"),
url(r'^detach/(?P<vid>\d+)/$', 'volume_detach', name="storage_detach"),
Modified: projects/pluginjail/gui/storage/views.py
===================================================================
--- projects/pluginjail/gui/storage/views.py 2013-03-27 05:41:04 UTC (rev 13465)
+++ projects/pluginjail/gui/storage/views.py 2013-03-27 23:59:35 UTC (rev 13466)
@@ -24,6 +24,8 @@
# POSSIBILITY OF SUCH DAMAGE.
#
#####################################################################
+from collections import OrderedDict
+import json
import logging
import os
import re
@@ -32,6 +34,7 @@
from django.core.servers.basehttp import FileWrapper
from django.core.urlresolvers import reverse
+from django.forms.formsets import formset_factory
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render
from django.utils import simplejson
@@ -49,6 +52,16 @@
log = logging.getLogger('storage.views')
+#FIXME: Move to a utils module
+def _diskcmp(a, b):
+ rega = re.search(r'^([a-z]+)(\d+)$', a[1])
+ regb = re.search(r'^([a-z]+)(\d+)$', b[1])
+ return cmp(
+ (a[0], rega.group(1), int(rega.group(2))),
+ (b[0], regb.group(1), int(regb.group(2))),
+ )
+
+
def home(request):
return render(request, 'storage/index.html', {
'focused_tab': request.GET.get("tab", None),
@@ -110,6 +123,67 @@
return render(request, 'storage/snapshots.html')
+def volumemanager(request):
+
+ if request.method == "POST":
+ form = forms.VolumeManagerForm(request.POST)
+ VdevFormSet = formset_factory(
+ forms.VolumeVdevForm,
+ formset=forms.VdevFormSet)
+ formset = VdevFormSet(request.POST, prefix='layout')
+ formset.form = form
+ if form.is_valid() and formset.is_valid() and form.done(formset):
+ return JsonResp(request, message=_("Volume successfully added."))
+ else:
+ return JsonResp(request, form=form, formsets={'layout': formset})
+ disks = []
+
+ # Grab disk list
+ # Root device already ruled out
+ for disk, info in notifier().get_disks().items():
+ disks.append(forms.Disk(
+ info['devname'],
+ info['capacity'],
+ serial=info.get('ident')
+ ))
+ disks = sorted(disks, key=lambda x: (x.size, x.dev), cmp=_diskcmp)
+
+ # Exclude what's already added
+ used_disks = []
+ for v in models.Volume.objects.all():
+ used_disks.extend(v.get_disks())
+
+ qs = iSCSITargetExtent.objects.filter(iscsi_target_extent_type='Disk')
+ used_disks.extend([i.get_device()[5:] for i in qs])
+
+ bysize = dict()
+ for d in list(disks):
+ if d.dev in used_disks:
+ continue
+ hsize = forms.humanize_number_si(d.size)
+ if hsize not in bysize:
+ bysize[hsize] = []
+ bysize[hsize].append({
+ 'dev': d.dev,
+ 'name': str(d),
+ 'size': d.size,
+ 'serial': d.serial,
+ })
+
+ bysize = OrderedDict(sorted(bysize.iteritems(), reverse=True))
+
+ qs = models.Volume.objects.filter(vol_fstype='ZFS')
+
+ return render(request, "storage/volumemanager.html", {
+ 'disks': json.dumps(bysize),
+ 'dedup_warning': forms.DEDUP_WARNING,
+ 'extend': json.dumps(
+ [{'value': '', 'label': '-----'}] +
+ [{'label': x.vol_name, 'value': x.vol_name} for x in qs]
+ ),
+ })
+
+
def wizard(request):
if request.method == "POST":
Modified: projects/pluginjail/gui/system/models.py
===================================================================
--- projects/pluginjail/gui/system/models.py 2013-03-27 05:41:04 UTC (rev 13465)
+++ projects/pluginjail/gui/system/models.py 2013-03-27 23:59:35 UTC (rev 13466)
@@ -353,7 +353,7 @@
null=True,
max_length=120,
verbose_name=_("Passphrase"),
- help_text=_("Private key passphrase)"),
+ help_text=_("Private key passphrase"),
)
ssl_certfile = models.TextField(
blank=True,
Modified: projects/pluginjail/gui/system/urls.py
===================================================================
--- projects/pluginjail/gui/system/urls.py 2013-03-27 05:41:04 UTC (rev 13465)
+++ projects/pluginjail/gui/system/urls.py 2013-03-27 23:59:35 UTC (rev 13466)
@@ -25,7 +25,7 @@
#
#####################################################################
-from django.conf.urls.defaults import patterns, url
+from django.conf.urls import patterns, url
from freenasUI.system.forms import (FirmwareWizard,
FirmwareTemporaryLocationForm, FirmwareUploadForm)
Modified: projects/pluginjail/gui/templates/500_freenas.html
===================================================================
--- projects/pluginjail/gui/templates/500_freenas.html 2013-03-27 05:41:04 UTC (rev 13465)
+++ projects/pluginjail/gui/templates/500_freenas.html 2013-03-27 23:59:35 UTC (rev 13466)
@@ -156,7 +156,7 @@
Exception Value: {{ exception_value|escape }}
</textarea>
<br><br>
- <input type="submit" value="Share this traceback on a public Web site">
+ <!-- <input type="submit" value="Share this traceback on a public Web site"> -->
</div>
</form>
</div>
Modified: projects/pluginjail/gui/templates/account/index.html
===================================================================
--- projects/pluginjail/gui/templates/account/index.html 2013-03-27 05:41:04 UTC (rev 13465)
+++ projects/pluginjail/gui/templates/account/index.html 2013-03-27 23:59:35 UTC (rev 13466)
@@ -2,23 +2,23 @@
<div data-dojo-type="dijit.layout.TabContainer" data-dojo-props="title: '{% trans "Admin Account"|force_escape|force_escape %}', nested: true, doLayout: true" style="width:100%;" id="tab_account">
<div data-dojo-type="dijit.layout.ContentPane" data-dojo-props="title: '{% trans "Change Admin User"|force_escape|force_escape %}'
{% if focus_form == "account.AdminAccount.ChangeAdmin" %}, selected: true{% endif %},
- href: '{% url account_changeform %}'" class="objrefresh" tab="account.AdminAccount.ChangeAdmin">
+ href: '{% url "account_changeform" %}'" class="objrefresh" tab="account.AdminAccount.ChangeAdmin">
</div>
<div data-dojo-type="dijit.layout.ContentPane" data-dojo-props="title: '{% trans "Change Password"|force_escape|force_escape %}'
{% if focus_form == "account.AdminAccount.ChangePass" %}, selected: true{% endif %},
- href: '{% url account_passform %}'" class="objrefresh" tab="account.AdminAccount.ChangePass">
+ href: '{% url "account_passform" %}'" class="objrefresh" tab="account.AdminAccount.ChangePass">
</div>
<div data-dojo-type="dijit.layout.ContentPane" data-dojo-props="title: '{% trans "Groups"|force_escape|force_escape %}'
{% if focus_form == "account.bsdGroups.View" %}, selected: true{% endif %},
- href: '{% url freeadmin_account_bsdgroups_datagrid %}',
+ href: '{% url "freeadmin_account_bsdgroups_datagrid" %}',
refreshOnShow: true" class="objrefresh data_account_bsdGroups" style="overflow-y:scroll;" tab="account.bsdGroups.View">
</div>
<div data-dojo-type="dijit.layout.ContentPane" data-dojo-props="title: '{% trans "Users"|force_escape|force_escape %}'
{% if focus_form == "account.bsdUsers.View" %}, selected: true{% endif %},
- href: '{% url freeadmin_account_bsdusers_datagrid %}',
+ href: '{% url "freeadmin_account_bsdusers_datagrid" %}',
refreshOnShow: true" class="objrefresh data_account_bsdUsers" style="overflow-y:scroll;" tab="account.bsdUsers.View">
</div>
Modified: projects/pluginjail/gui/templates/base.html
===================================================================
--- projects/pluginjail/gui/templates/base.html 2013-03-27 05:41:04 UTC (rev 13465)
+++ projects/pluginjail/gui/templates/base.html 2013-03-27 23:59:35 UTC (rev 13466)
@@ -10,12 +10,15 @@
</style>
<script type="text/javascript">
var dojoConfig = {
- 'isDebug':true,
- 'parseOnLoad':true,
- 'baseUrl':"{{ DOJANGO.DOJO_URL }}",
- 'async': true,
- 'cacheBust': '{{ cache_hash }}',
- 'packages': [
+ has: {
+ "dojo-undef-api": true
+ },
+ isDebug:true,
+ parseOnLoad:true,
+ baseUrl:"{{ DOJANGO.DOJO_URL }}",
+ async: true,
+ cacheBust: '{{ cache_hash }}',
+ packages: [
{name: "freeadmin", location: "../../../../../static/lib/js/freeadmin"},
{name: "dgrid", location: "../../../../../static/lib/js/dgrid"},
{name: "xstyle", location: "../../../../../static/lib/js/xstyle"},
@@ -33,6 +36,8 @@
<link rel="stylesheet" href="{{ DOJANGO.DOJOX_URL }}/layout/resources/ExpandoPane.css?cache={{ cache_hash }}" />
<link rel="stylesheet" href="{{ DOJANGO.DOJOX_URL }}/grid/resources/claroGrid.css?cache={{ cache_hash }}" type="text/css" />
<link rel="stylesheet" href="{{ DOJANGO.DOJOX_URL }}/grid/enhanced/resources/EnhancedGrid.css?cache={{ cache_hash }}" type="text/css" />
+ <link rel="stylesheet" href="{{ DOJANGO.DOJOX_URL }}/layout/resources/ResizeHandle.css?cache={{ cache_hash }}" type="text/css" />
+ <link rel="stylesheet" href="{{ DOJANGO.DOJOX_URL }}/widget/Toaster/Toaster.css?cache={{ cache_hash }}" type="text/css" />
<link rel="stylesheet" href="{{ STATIC_URL }}css/template.css?cache={{ cache_hash }}" type="text/css" />
<link href="{{ STATIC_URL }}favicon.ico" rel="shortcut icon" type="image/x-icon" />
{% block dojango_header_extra %}{% endblock %}
Modified: projects/pluginjail/gui/templates/freeadmin/generic_model_datagrid.html
===================================================================
--- projects/pluginjail/gui/templates/freeadmin/generic_model_datagrid.html 2013-03-27 05:41:04 UTC (rev 13465)
+++ projects/pluginjail/gui/templates/freeadmin/generic_model_datagrid.html 2013-03-27 23:59:35 UTC (rev 13466)
@@ -139,7 +139,7 @@
});
var store = new JsonRest({
- target: "{% url api_dispatch_list api_name="v1.0" resource_name=resource_name %}{{ datagrid_filters|escapejs }}",
+ target: "{% url "api_dispatch_list" api_name="v1.0" resource_name=resource_name %}{{ datagrid_filters|escapejs }}",
getChildren: function(parent, options){
return parent.children;
},
Modified: projects/pluginjail/gui/templates/freeadmin/index.html
===================================================================
--- projects/pluginjail/gui/templates/freeadmin/index.html 2013-03-27 05:41:04 UTC (rev 13465)
+++ projects/pluginjail/gui/templates/freeadmin/index.html 2013-03-27 23:59:35 UTC (rev 13466)
@@ -1,7 +1,7 @@
{% extends "base.html" %}
{% block dojango_header_extra %}
-<script type="text/javascript" src="{% url django.views.i18n.javascript_catalog %}"></script>
+<script type="text/javascript" src="{% url "django.views.i18n.javascript_catalog" %}"></script>
<script type="text/javascript" src="{{ STATIC_URL }}lib/js/freeadmin.js?cache={{ cache_hash }}"></script>
<script type="text/javascript" src="{{ STATIC_URL }}lib/js/top.js?cache={{ cache_hash }}"></script>
<script type="text/javascript" src="{{ STATIC_URL }}lib/js/alert.js?cache={{ cache_hash }}"></script>
@@ -9,17 +9,17 @@
<script type="text/javascript">
menuSetURLs = function() {
- Menu.urlInfo = '{% url system_info %}';
- Menu.urlSettings = '{% url system_settings %}';
- Menu.urlReporting = '{% url system_reporting %}';
- Menu.urlNetwork = '{% url network_home %}';
- Menu.urlSharing = '{% url sharing_home %}';
- Menu.urlServices = '{% url services_home %}';
- Menu.urlAccount = '{% url account_home %}';
- Menu.urlStorage = '{% url storage_home %}';
- Menu.urlJails = '{% url jails_home %}';
- Menu.urlISCSI = '{% url services_iscsi %}';
- Menu.urlTree = '{% url freeadmin_menu %}';
+ Menu.urlInfo = '{% url "system_info" %}';
+ Menu.urlSettings = '{% url "system_settings" %}';
+ Menu.urlReporting = '{% url "system_reporting" %}';
+ Menu.urlNetwork = '{% url "network_home" %}';
+ Menu.urlSharing = '{% url "sharing_home" %}';
+ Menu.urlServices = '{% url "services_home" %}';
+ Menu.urlAccount = '{% url "account_home" %}';
+ Menu.urlStorage = '{% url "storage_home" %}';
+ Menu.urlJails = '{% url "jails_home" %}';
+ Menu.urlISCSI = '{% url "services_iscsi" %}';
+ Menu.urlTree = '{% url "freeadmin_menu" %}';
}
Modified: projects/pluginjail/gui/templates/jails/index.html
===================================================================
--- projects/pluginjail/gui/templates/jails/index.html 2013-03-27 05:41:04 UTC (rev 13465)
+++ projects/pluginjail/gui/templates/jails/index.html 2013-03-27 23:59:35 UTC (rev 13466)
@@ -1,12 +1,12 @@
<div data-dojo-type="dijit.layout.TabContainer" data-dojo-props="nested:true, doLayout:true" id="tab_jails">
<div data-dojo-type="dijit.layout.ContentPane" data-dojo-props="title: '{% trans "Jails"|force_escape|force_escape %}'
{% if focus_form == "jails.View" %}, selected: true{% endif %},
- href: '{% url freeadmin_jails_jails_datagrid %}',
+ href: '{% url "freeadmin_jails_jails_datagrid" %}',
refreshOnShow: true" class="objrefresh data_jails_Jails"" tab="jails.View">
</div>
<div data-dojo-type="dijit.layout.ContentPane" data-dojo-props="title: '{% trans "Configuration"|force_escape|force_escape %}'
{% if focus_form == "jails.JailsConfiguration" %}, selected: true{% endif %},
- href: '{% url freeadmin_jails_jailsconfiguration_edit oid=jailsconf %}?inline=true',
+ href: '{% url "freeadmin_jails_jailsconfiguration_edit" oid=jailsconf %}?inline=true',
doLayout: false,
refreshOnShow: true" class="objrefresh data_jails_JailsConfiguration"" tab="jails.JailsConfiguration">
</div>
Modified: projects/pluginjail/gui/templates/network/index.html
===================================================================
--- projects/pluginjail/gui/templates/network/index.html 2013-03-27 05:41:04 UTC (rev 13465)
+++ projects/pluginjail/gui/templates/network/index.html 2013-03-27 23:59:35 UTC (rev 13466)
@@ -1,33 +1,33 @@
<div data-dojo-type="dijit.layout.TabContainer" data-dojo-props="nested:true, doLayout:true" id="tab_networksettings">
<div data-dojo-type="dijit.layout.ContentPane" data-dojo-props="title: '{% trans "Global Configuration"|force_escape|force_escape %}'
{% if focus_form == "network.GlobalConfiguration" %}, selected: true{% endif %},
- href: '{% url freeadmin_network_globalconfiguration_edit oid=globalconf %}?inline=true',
@@ Diff output truncated at 100000 characters. @@
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|